本文提供了关于SpringCloud项目开发资料的详细介绍,涵盖了环境搭建、服务发现与注册、服务网关与路由等内容,帮助新手快速入门。文章还包括了微服务间通信、配置中心与服务容错的实战案例,以及详细的示例代码,助力开发者理解和实现SpringCloud项目开发。
Spring Cloud 是一个基于 Spring Boot 的开发工具包,用于快速构建分布式系统。它提供了一系列工具来帮助开发分布式系统,包括配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、领导选举、分布式会话以及集群状态管理等组件。
application.properties
或 application.yml
文件pom.xml
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <version>2.2.5.RELEASE</version> </dependency> </dependencies>
application.yml
server: port: 8761 spring: application: name: service-registry eureka: client: register-with-eureka: false fetch-registry: false server: true
主启动类
package com.example.eurekaserver; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }
Eureka 是 Netflix 开发的服务注册与发现组件,主要用于构建服务发现机制。服务提供者启动后,会向注册中心发送心跳来维持注册状态。服务消费者在需要调用服务时,先从注册中心获取服务提供者的地址信息,然后直接进行调用。
服务提供者(Provider)
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.2.5.RELEASE</version> </dependency> </dependencies>
application.yml
server: port: 8081 spring: application: name: service-provider eureka: client: service-url: defaultZone: http://localhost:8761/eureka/
主启动类
package com.example.serviceprovider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient public class ServiceProviderApplication { public static void main(String[] args) { SpringApplication.run(ServiceProviderApplication.class, args); } }
服务接口
package com.example.serviceprovider.service; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; @FeignClient("service-provider") public interface ServiceProviderClient { @GetMapping("/hello") String hello(); }
服务消费者
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.2.5.RELEASE</version> </dependency> </dependencies>
application.yml
server: port: 8082 spring: application: name: service-consumer eureka: client: service-url: defaultZone: http://localhost:8761/eureka/
主启动类
package com.example.serviceconsumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient public class ServiceConsumerApplication { public static void main(String[] args) { SpringApplication.run(ServiceConsumerApplication.class, args); } }
控制器
package com.example.serviceconsumer.controller; import com.example.serviceprovider.service.ServiceProviderClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ConsumerController { @Autowired private ServiceProviderClient serviceProviderClient; @GetMapping("/hello") public String hello() { return serviceProviderClient.hello(); } }
Zuul 是 Netflix 开发的一个基于 Java 和 Spring Boot 的 API Gateway,它负责将客户端请求路由到不同后端服务,并提供服务的负载均衡、过滤、定制路由等功能。它作为服务的统一入口,可以有效地控制服务的访问路径和权限。
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> <version>2.2.5.RELEASE</version> </dependency> </dependencies>
application.yml
server: port: 8080 spring: application: name: service-gateway eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ zuul: routes: provider: path: /provider/** url: http://localhost:8081
主启动类
package com.example.servicegateway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; @SpringBootApplication @EnableEurekaClient @EnableZuulProxy public class ServiceGatewayApplication { public static void main(String[] args) { SpringApplication.run(ServiceGatewayApplication.class, args); } }
Spring Cloud Gateway 是 Spring Cloud 的新一代网关,提供了更强大的路由功能和灵活的过滤器支持。与 Zuul 类似,Spring Cloud Gateway 也可以用于构建 API Gateway,实现服务路由和负载均衡等功能。
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> </dependencies>
application.yml
server: port: 8081 spring: application: name: service-gateway eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ spring: cloud: gateway: routes: - id: service-provider uri: http://localhost:8081 predicates: - Path=/provider/**
主启动类
package com.example.servicegateway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.context.annotation.Bean; @SpringBootApplication @EnableEurekaClient public class ServiceGatewayApplication { public static void main(String[] args) { SpringApplication.run(ServiceGatewayApplication.class, args); } @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { return builder .routes() .route("service-provider", r -> r.path("/provider/**") .uri("http://localhost:8081")) .build(); } }
Ribbon 是 Netflix 开发的客户端负载均衡组件,可以基于配置文件中的规则,从服务列表中按权重随机选择一个服务实例进行调用。它提供了服务列表管理、断路器等功能。
Feign 是一个声明式的 web 服务客户端,它使得编写 web 服务客户端变得更加容易。Feign 集成了 Ribbon 和 Eureka,可以利用 Feign 的注解和配置来实现声明式的服务调用。
服务提供者
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.2.5.RELEASE</version> </dependency> </dependencies>
application.yml
server: port: 8081 spring: application: name: service-provider eureka: client: service-url: defaultZone: http://localhost:8761/eureka/
主启动类
package com.example.serviceprovider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient public class ServiceProviderApplication { public static void main(String[] args) { SpringApplication.run(ServiceProviderApplication.class, args); } }
服务接口
package com.example.serviceprovider.service; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; @FeignClient("service-provider") public interface ServiceProviderClient { @GetMapping("/hello") String hello(); }
服务消费者
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.2.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies>
application.yml
server: port: 8082 spring: application: name: service-consumer eureka: client: service-url: defaultZone: http://localhost:8761/eureka/
主启动类
package com.example.serviceconsumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableEurekaClient @EnableFeignClients public class ServiceConsumerApplication { public static void main(String[] args) { SpringApplication.run(ServiceConsumerApplication.class, args); } }
控制器
package com.example.serviceconsumer.controller; import com.example.serviceprovider.service.ServiceProviderClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ConsumerController { @Autowired private ServiceProviderClient serviceProviderClient; @GetMapping("/hello") public String hello() { return serviceProviderClient.hello(); } }
Spring Cloud Config 是一个为 Spring Boot 应用提供外部配置的工具,它包含客户端和服务器两部分。Spring Cloud Config Server 从指定的存储位置读取配置文件,并通过 REST 接口提供给客户端使用。Spring Cloud Config Client 可以从 Config Server 获取配置文件,并将其注入到 Spring 容器中。
Hystrix 是 Netflix 开发的一个延迟和容错库,用来隔离服务之间的调用,防止某一个服务的不可用导致整个系统的不可用。当调用服务失败、超时或抛出异常时,Hystrix 可以使用降级逻辑保证系统继续正常运行。
服务提供者
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.2.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> </dependencies>
application.yml
server: port: 8081 spring: application: name: service-provider eureka: client: service-url: defaultZone: http://localhost:8761/eureka/
主启动类
package com.example.serviceprovider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.hystrix.EnableHystrix; @SpringBootApplication @EnableEurekaClient @EnableHystrix public class ServiceProviderApplication { public static void main(String[] args) { SpringApplication.run(ServiceProviderApplication.class, args); } }
服务接口
package com.example.serviceprovider.service; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; @FeignClient(name = "service-provider", fallback = ServiceProviderClientFallback.class, fallbackFactory = ServiceProviderClientFallbackFactory.class) public interface ServiceProviderClient { @GetMapping("/hello") String hello(); @GetMapping("/error") String error(); }
控制器
package com.example.serviceprovider.controller; import com.example.serviceprovider.service.ServiceProviderClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class ProviderController { @Autowired private ServiceProviderClient serviceProviderClient; @GetMapping("/hello") public String hello() { return serviceProviderClient.hello(); } @GetMapping("/error") public String error() { return serviceProviderClient.error(); } }
服务消费者
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2021.0.5</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies>
application.yml
server: port: 8082 spring: application: name: service-consumer eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ feign: hystrix: enabled: true
主启动类
package com.example.serviceconsumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.netflix.hystrix.EnableHystrix; @SpringBootApplication @EnableEurekaClient @EnableFeignClients @EnableHystrix public class ServiceConsumerApplication { public static void main(String[] args) { SpringApplication.run(ServiceConsumerApplication.class, args); } }
控制器
package com.example.serviceconsumer.controller; import com.example.serviceprovider.service.ServiceProviderClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ConsumerController { @Autowired private ServiceProviderClient serviceProviderClient; @GetMapping("/hello") public String hello() { return serviceProviderClient.hello(); } }
服务降级
package com.example.serviceconsumer.service; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.cloud.openfeign.FallbackFactory; @FeignClient(name = "service-provider", fallback = ServiceProviderClientFallback.class, fallbackFactory = ServiceProviderClientFallbackFactory.class) public interface ServiceProviderClient { @GetMapping("/hello") String hello(); @GetMapping("/error") String error(); } class ServiceProviderClientFallback implements ServiceProviderClient { @Override public String hello() { return "Hello, fallback"; } @Override public String error() { return "Error, fallback"; } } class ServiceProviderClientFallbackFactory implements FallbackFactory<ServiceProviderClient> { @Override public ServiceProviderClient create(Throwable cause) { return new ServiceProviderClient() { @Override public String hello() { return "Hello, fallback factory"; } @Override public String error() { return "Error, fallback factory"; } }; } }
搭建一个简单的 SpringCloud 微服务项目,包括服务注册中心、服务提供者、服务消费者和配置中心。
服务注册中心
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <version>2.2.5.RELEASE</version> </dependency> </dependencies>
application.yml
server: port: 8761 spring: application: name: service-registry eureka: client: register-with-eureka: false fetch-registry: false server: true
主启动类
package com.example.eurekaserver; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }
服务提供者
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.2.5.RELEASE</version> </dependency> </dependencies>
application.yml
server: port: 8081 spring: application: name: service-provider eureka: client: service-url: defaultZone: http://localhost:8761/eureka/
主启动类
package com.example.serviceprovider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient public class ServiceProviderApplication { public static void main(String[] args) { SpringApplication.run(ServiceProviderApplication.class, args); } }
控制器
package com.example.serviceprovider.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ProviderController { @GetMapping("/hello") public String hello() { return "Hello, ServiceProvider"; } }
服务消费者
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.2.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies>
application.yml
server: port: 8082 spring: application: name: service-consumer eureka: client: service-url: defaultZone: http://localhost:8761/eureka/
主启动类
package com.example.serviceconsumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableEurekaClient @EnableFeignClients public class ServiceConsumerApplication { public static void main(String[] args) { SpringApplication.run(ServiceConsumerApplication.class, args); } }
控制器
package com.example.serviceconsumer.controller; import com.example.serviceprovider.controller.ProviderController; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ConsumerController { @Autowired private ProviderController providerController; @GetMapping("/hello") public String hello() { return providerController.hello(); } }
服务提供者服务接口
package com.example.serviceprovider.service; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; @FeignClient("service-provider") public interface ServiceProviderClient { @GetMapping("/hello") String hello(); }
配置中心
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.2.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> </dependencies>
application.yml
server: port: 8888 spring: application: name: config-server eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ spring.cloud: config: server: git: uri: https://github.com/yourusername/config-repo username: yourusername password: yourpassword
主启动类
package com.example.configserver; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.config.server.EnableConfigServer; @SpringBootApplication @EnableEurekaClient @EnableConfigServer public class ConfigServerApplication { public static void main(String[] args) { SpringApplication.run(ConfigServerApplication.class, args); } }
配置文件
在配置中心的 Git 仓库中添加配置文件,例如 application.yml
和 application-dev.yml
。
服务提供者配置
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.2.5.RELEASE</version> </dependency> </dependencies>
bootstrap.yml
spring: application: name: service-provider cloud: config: uri: http://localhost:8888 label: master
服务消费者配置
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.2.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies>
bootstrap.yml
spring: application: name: service-consumer cloud: config: uri: http://localhost:8888 label: master
mvn spring-boot:run -Dspring-boot.run.main-class=com.example.eurekaserver.EurekaServerApplication
mvn spring-boot:run -Dspring-boot.run.main-class=com.example.serviceprovider.ServiceProviderApplication
mvn spring-boot:run -Dspring-boot.run.main-class=com.example.serviceconsumer.ServiceConsumerApplication
mvn spring-boot:run -Dspring-boot.run.main-class=com.example.configserver.ConfigServerApplication
通过以上步骤,可以搭建一个简单的 SpringCloud 微服务项目,并进行测试和部署。