从零搭建一个微服务Demo:手把手教你用SpringBoot整合SpringCloud Netflix五大件

微服务架构已经成为现代企业级应用开发的主流选择。对于Java开发者而言,SpringBoot和SpringCloud的组合提供了快速构建分布式系统的完美解决方案。本文将带领你从零开始,通过实际编码演示如何将一个简单的SpringBoot应用逐步扩展为完整的微服务系统,集成Eureka服务注册中心、Ribbon客户端负载均衡、Hystrix熔断器、Zuul API网关和Config配置中心这五大核心组件。

1. 环境准备与基础项目搭建

在开始之前,确保你的开发环境满足以下要求:

  • JDK 1.8或更高版本
  • IntelliJ IDEA(推荐)或其他Java IDE
  • Maven 3.5+
  • Git客户端

首先创建一个基础的SpringBoot项目作为我们的起点:

mvn archetype:generate -DgroupId=com.example -DartifactId=microservice-demo -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

然后修改pom.xml文件,添加SpringBoot和SpringCloud的依赖:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.0</version>
</parent>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2021.0.3</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

提示:SpringCloud版本需要与SpringBoot版本匹配,这里我们使用2021.0.3(代号"2021.0.x")与SpringBoot 2.7.x配合使用。

2. 集成Eureka服务注册与发现

服务注册与发现是微服务架构的基础功能。我们将首先搭建一个Eureka Server,然后改造我们的基础应用成为Eureka Client。

2.1 创建Eureka Server

新建一个模块作为Eureka服务注册中心:

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

配置application.yml:

server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

2.2 将应用注册为Eureka Client

修改基础应用的pom.xml添加Eureka Client依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

在启动类上添加@EnableEurekaClient注解:

@SpringBootApplication
@EnableEurekaClient
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

配置application.yml:

spring:
  application:
    name: demo-service

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

启动Eureka Server和Demo应用后,访问http://localhost:8761,你应该能看到DEMO-SERVICE已经注册到Eureka。

3. 实现服务间调用与负载均衡

在微服务架构中,服务间的通信是核心功能。我们将使用Ribbon和Feign两种方式实现服务调用。

3.1 使用Ribbon实现客户端负载均衡

首先创建第二个服务provider-service,同样注册到Eureka。然后在demo-service中添加Ribbon支持:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

创建一个RestTemplate bean并添加@LoadBalanced注解:

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
    return new RestTemplate();
}

现在可以通过服务名调用provider-service:

@RestController
public class DemoController {
    
    @Autowired
    private RestTemplate restTemplate;
    
    @GetMapping("/call-provider")
    public String callProvider() {
        return restTemplate.getForObject(
            "http://provider-service/api/resource", 
            String.class
        );
    }
}

3.2 使用Feign简化服务调用

Feign提供了更声明式的服务调用方式。首先添加依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

在启动类上添加@EnableFeignClients注解:

@EnableFeignClients
@SpringBootApplication
public class DemoApplication {
    // ...
}

创建Feign客户端接口:

@FeignClient("provider-service")
public interface ProviderClient {
    
    @GetMapping("/api/resource")
    String getResource();
}

然后在Controller中注入使用:

@Autowired
private ProviderClient providerClient;

@GetMapping("/feign-call")
public String feignCall() {
    return providerClient.getResource();
}

4. 集成Hystrix实现熔断与降级

在分布式系统中,服务故障是不可避免的。Hystrix提供了熔断、降级和隔离机制来增强系统的弹性。

4.1 基本熔断配置

添加Hystrix依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

在启动类上添加@EnableCircuitBreaker注解:

@EnableCircuitBreaker
@SpringBootApplication
public class DemoApplication {
    // ...
}

为Feign客户端启用Hystrix支持(在application.yml中):

feign:
  hystrix:
    enabled: true

4.2 实现降级逻辑

为Feign客户端指定fallback类:

@FeignClient(name = "provider-service", fallback = ProviderClientFallback.class)
public interface ProviderClient {
    // ...
}

@Component
public class ProviderClientFallback implements ProviderClient {
    @Override
    public String getResource() {
        return "Fallback response";
    }
}

或者使用方法级的熔断:

@HystrixCommand(fallbackMethod = "fallbackMethod")
@GetMapping("/hystrix-example")
public String hystrixExample() {
    // 可能失败的操作
}

public String fallbackMethod() {
    return "Fallback response";
}

4.3 Hystrix仪表盘监控

添加Hystrix仪表盘依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>

在启动类上添加@EnableHystrixDashboard注解:

@EnableHystrixDashboard
@SpringBootApplication
public class DemoApplication {
    // ...
}

访问http://localhost:8080/hystrix,输入监控流地址http://localhost:8080/actuator/hystrix.stream即可查看熔断器状态。

5. 使用Zuul构建API网关

API网关是微服务架构中的重要组件,负责路由、过滤和聚合等跨领域功能。

5.1 创建Zuul网关服务

新建一个模块作为网关服务,添加依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

在启动类上添加@EnableZuulProxy注解:

@EnableZuulProxy
@SpringBootApplication
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

基本配置application.yml:

zuul:
  routes:
    demo-service:
      path: /demo/**
      serviceId: demo-service
    provider-service:
      path: /provider/**
      serviceId: provider-service

5.2 实现自定义过滤器

Zuul的强大之处在于可以自定义各种过滤器:

@Component
public class AuthFilter extends ZuulFilter {
    
    @Override
    public String filterType() {
        return "pre";
    }
    
    @Override
    public int filterOrder() {
        return 1;
    }
    
    @Override
    public boolean shouldFilter() {
        return true;
    }
    
    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        
        String token = request.getHeader("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            ctx.setResponseBody("Unauthorized");
        }
        
        return null;
    }
}

5.3 网关的负载均衡与熔断

Zuul默认集成了Ribbon和Hystrix,可以通过以下配置调整:

ribbon:
  ConnectTimeout: 1000
  ReadTimeout: 3000

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000

6. 集中化配置管理

随着服务数量增加,分散的配置管理变得困难。Spring Cloud Config提供了集中化的配置管理解决方案。

6.1 搭建Config Server

新建一个模块作为配置中心,添加依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>

在启动类上添加@EnableConfigServer注解:

@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

配置application.yml指定Git仓库:

server:
  port: 8888

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/your-repo/config-repo
          search-paths: '{application}'

6.2 客户端配置

在demo-service中添加Config Client依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

创建bootstrap.yml(优先级高于application.yml):

spring:
  application:
    name: demo-service
  cloud:
    config:
      uri: http://localhost:8888
      fail-fast: true

6.3 配置刷新

要实现配置的动态刷新,首先在需要刷新的bean上添加@RefreshScope:

@RefreshScope
@RestController
public class DemoController {
    @Value("${custom.property}")
    private String customProperty;
    
    // ...
}

然后添加Actuator依赖并暴露refresh端点:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

配置application.yml:

management:
  endpoints:
    web:
      exposure:
        include: refresh,health,info

现在,修改Git仓库中的配置后,向客户端服务的/actuator/refresh端点发送POST请求即可刷新配置。

7. 系统整合与测试

现在我们已经完成了所有核心组件的集成,让我们来验证整个系统是否正常工作。

7.1 启动顺序建议

  1. 配置中心(Config Server)
  2. 服务注册中心(Eureka Server)
  3. 配置客户端服务(如provider-service)
  4. API网关(Zuul)
  5. 其他微服务

7.2 验证服务注册与发现

访问Eureka控制台http://localhost:8761,确认所有服务都已注册:

服务名称 状态 实例数
CONFIG-SERVER UP 1
GATEWAY UP 1
DEMO-SERVICE UP 1
PROVIDER-SERVICE UP 1

7.3 测试API网关路由

通过网关访问各个服务:

  • http://localhost:8080/demo/hello → 路由到demo-service
  • http://localhost:8080/provider/api/resource → 路由到provider-service

7.4 验证熔断机制

故意停止provider-service,然后访问demo-service的接口,应该能看到降级响应。

7.5 配置中心测试

修改Git仓库中的配置,通过POST请求刷新客户端配置,验证配置是否生效。

8. 生产环境注意事项

在实际生产环境中部署微服务系统时,还需要考虑以下方面:

  • Eureka高可用:部署多个Eureka节点并相互注册
  • Zuul性能优化:调整线程池、超时设置和缓存
  • 配置安全:加密敏感配置信息
  • 服务监控:集成Spring Boot Admin和Prometheus
  • 日志收集:使用ELK或类似方案集中管理日志
  • 容器化部署:考虑使用Docker和Kubernetes
// 示例:Eureka Server高可用配置
eureka:
  client:
    serviceUrl:
      defaultZone: http://peer1:8761/eureka/,http://peer2:8761/eureka/

注意:生产环境中应该为每个组件配置适当的资源限制和健康检查,并建立完善的监控告警系统。

更多推荐