Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线)。
微服务架构就是将一个完整的应用从数据存储开始垂直拆分成多个不同的服务,每个服务都能独立部署、独立维护、独立扩展,服务与服务间通过诸如RESTful API的方式互相调用。
服务发现模块:Eureka。
创建一个基础的Spring Boot工程,并在pom.xml
中引入需要的依赖内容:
org.springframework.boot
spring-boot-starter-parent
1.3.5.RELEASE
org.springframework.boot
spring-boot-starter-test
test
org.springframework.cloud
spring-cloud-starter-eureka-server
org.springframework.cloud
spring-cloud-dependencies
Brixton.RELEASE
pom
import
通过@EnableEurekaServer
注解启动一个服务注册中心提供给其他应用进行对话
@EnableEurekaServer
@SpringBootApplication
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
}
}
在默认设置下,该服务注册中心也会将自己作为客户端来尝试注册它自己,所以我们需要禁用它的客户端注册行为,只需要在application.properties
中问增加如下配置:
server.port=1111
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.serviceUrl.defaultZone=http://localhost:${server.port}/eureka/
这里将服务注册中心的端口通过server.port
属性设置为1111
。
创建一个基本的Spring Boot应用,在pom.xml
中,加入如下配置:
org.springframework.boot
spring-boot-starter-parent
1.3.5.RELEASE
org.springframework.boot
spring-boot-starter-test
test
org.springframework.cloud
spring-cloud-starter-eureka
org.springframework.cloud
spring-cloud-dependencies
Brixton.RELEASE
pom
import
实现/add
请求处理接口
@RestController
public class ComputeController {
private final Logger logger = Logger.getLogger(getClass());
@Autowired
private DiscoveryClient client;
@RequestMapping(value = "/add" ,method = RequestMethod.GET)
public Integer add(@RequestParam Integer a, @RequestParam Integer b) {
ServiceInstance instance = client.getLocalServiceInstance();
Integer r = a + b;
logger.info("/add, host:" + instance.getHost() + ", service_id:" + instance.getServiceId() + ", result:" + r);
return r;
}
}
最后在主类中通过加上@EnableDiscoveryClient
注解,该注解能激活Eureka中的DiscoveryClient
实现,才能实现Controller中对服务信息的输出。
@EnableDiscoveryClient
@SpringBootApplication
public class ComputeServiceApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(ComputeServiceApplication.class).web(true).run(args);
}
}
我们在完成了服务内容的实现之后,再继续对application.properties
做一些配置工作,具体如下
spring.application.name=compute-service
server.port=2222
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
通过spring.application.name
属性,我们可以指定微服务的名称后续在调用的时候只需要使用该名称就可以进行服务的访问。
eureka.client.serviceUrl.defaultZone
属性对应服务注册中心的配置内容,指定服务注册中心的位置。
Ribbon是一个基于HTTP和TCP客户端的负载均衡器。
Ribbon可以在通过客户端中配置的ribbonServerList服务端列表去轮询访问以达到均衡负载的作用。
准备工作
使用Ribbon实现客户端负载均衡的消费者
构建一个基本Spring Boot项目,并在pom.xml中加入如下内容:
org.springframework.boot
spring-boot-starter-parent
1.3.5.RELEASE
org.springframework.cloud
spring-cloud-starter-ribbon
org.springframework.cloud
spring-cloud-starter-eureka
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.cloud
spring-cloud-dependencies
Brixton.RELEASE
pom
import
在应用主类中,通过@EnableDiscoveryClient
注解来添加发现服务能力。创建RestTemplate实例,并通过@LoadBalanced
注解开启均衡负载能力。
@SpringBootApplication
@EnableDiscoveryClient
public class RibbonApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class, args);
}
}
创建ConsumerController
来消费COMPUTE-SERVICE
的add服务。通过直接RestTemplate来调用服务,计算1 + 2的值。
@RestController
public class ConsumerController {
@Autowired
RestTemplate restTemplate;
@RequestMapping(value = "/add", method = RequestMethod.GET)
public String add() {
return restTemplate.getForEntity("http://COMPUTE-SERVICE/add?a=1&b=2", String.class).getBody();
}
}
application.properties
中配置eureka服务注册中心
spring.application.name=ribbon-consumer
server.port=3333
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
Feign:
Feign是一个声明式的Web Service客户端,它使得编写Web Serivce客户端变得更加简单。我们只需要使用Feign来创建一个接口并用注解来配置它既可完成。它具备可插拔的注解支持,包括Feign注解和JAX-RS注解。Feign也支持可插拔的编码器和解码器。Spring Cloud为Feign增加了对Spring MVC注解的支持,还整合了Ribbon和Eureka来提供均衡负载的HTTP客户端实现。
创建一个Spring Boot工程,配置pom.xml
,将上述的配置中的ribbon依赖替换成feign的依赖即可,具体如下:
org.springframework.boot
spring-boot-starter-parent
1.3.5.RELEASE
org.springframework.cloud
spring-cloud-starter-feign
org.springframework.cloud
spring-cloud-starter-eureka
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.cloud
spring-cloud-dependencies
Brixton.RELEASE
pom
import
在应用主类中通过@EnableFeignClients
注解开启Feign功能,具体如下:
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class FeignApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class, args);
}
}
定义compute-service
服务的接口,具体如下:
@FeignClient("compute-service")
public interface ComputeClient {
@RequestMapping(method = RequestMethod.GET, value = "/add")
Integer add(@RequestParam(value = "a") Integer a, @RequestParam(value = "b") Integer b);
}
@FeignClient("compute-service")
注解来绑定该接口对应compute-service服务在web层中调用上面定义的ComputeClient
,具体如下:
@RestController
public class ConsumerController {
@Autowired
ComputeClient computeClient;
@RequestMapping(value = "/add", method = RequestMethod.GET)
public Integer add() {
return computeClient.add(10, 20);
}
}
application.properties
中不用变,指定eureka服务注册中心即可,如:
spring.application.name=feign-consumer
server.port=3333
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
断路器模式源于Martin Fowler的Circuit Breaker一文。“断路器”本身是一种开关装置,用于在电路上保护线路过载,当线路中有电器发生短路时,“断路器”能够及时的切断故障电路,防止发生过载、发热、甚至起火等严重后果。
在分布式架构中,断路器模式的作用也是类似的,当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个错误响应,而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。
pom.xml
中引入依赖hystrix依赖
org.springframework.cloud
spring-cloud-starter-hystrix
RibbonApplication
中使用@EnableCircuitBreaker
注解开启断路器功能:@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class RibbonApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class, args);
}
}
ComputeService
类,在使用ribbon消费服务的函数上增加@HystrixCommand
注解来指定回调方法。@Service
public class ComputeService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "addServiceFallback")
public String addService() {
return restTemplate.getForEntity("http://COMPUTE-SERVICE/add?a=10&b=20", String.class).getBody();
}
public String addServiceFallback() {
return "error";
}
}
@RestController
public class ConsumerController {
@Autowired
private ComputeService computeService;
@RequestMapping(value = "/add", method = RequestMethod.GET)
public String add() {
return computeService.addService();
}
}
Feign使用Hystrix:
@FeignClient
注解中的fallback属性指定回调类@FeignClient(value = "compute-service", fallback = ComputeClientHystrix.class)
public interface ComputeClient {
@RequestMapping(method = RequestMethod.GET, value = "/add")
Integer add(@RequestParam(value = "a") Integer a, @RequestParam(value = "b") Integer b);
}
创建回调类ComputeClientHystrix
,实现@FeignClient
的接口,此时实现的方法就是对应@FeignClient
接口中映射的fallback函数
@Component
public class ComputeClientHystrix implements ComputeClient {
@Override
public Integer add(@RequestParam(value = "a") Integer a, @RequestParam(value = "b") Integer b) {
return -9999;
}
}