Open Feign是在feign的基础上进行的加强
是一个声明式的web服务客户端,让编写web客户端变得非常容易,只需要创建一个接口并在接口上添加注解即可
意在使编写Java Http客户端变得更容易
在实际的开发当中,由于对服务依赖的调用不止一处,这就导致一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。
Feign就在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义,在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置它,(类似于以前Dao接口上标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可)即可完成对服务提供方的接口绑定,简化了使用Spring Cloud Ribbon时,自动封装服务调用客户端的开发量。
Feign集成了Ribbon,使得它也可以实现以轮询的方式实现客户端的负载均衡
Feign与OpenFeign的区别
Feign是Spring Cloud组件中一个轻量级RESTful的HTTP服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用接口,就可以调用服务注册中心的服务。
OpenFeign是Spring Cloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中。
从ribbon+restTemplate换成OpenFeign
创建cloud-consumer-feign-order80
依赖中除了原版80模块的内容,还要加入:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Yml中加入:
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
default-Zone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
主启动类:
@SpringBootApplication
@EnableFeignClients
public class OpenFeignMain80 {
public static void main(String[] args) {
SpringApplication.run(OpenFeignMain80.class,args);
}
}
写一个service层接口:
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {
@GetMapping(value = "/payment/get/{id}")
CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
}
再写一个controller
@RestController
public class OrderFeignController {
@Resource
private PaymentFeignService paymentFeignService;
@GetMapping(value = "/consumer/payment/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
return paymentFeignService.getPaymentById(id);
}
}
输入url:http://localhost/consumer/payment/get/1
发现显示正常即成功
OpenFeign超时控制
先故意超时试试
在8001的paymentcontroller中加入:
@GetMapping(value = "/payment/feign/timeout")
public String paymentFeignTimeout(){
try{
TimeUnit.SECONDS.sleep(3);
}catch (InterruptedException e){
e.printStackTrace();
}
return serverPort;
}
接着在PaymentFeignService
@GetMapping(value = "/payment/feign/timeout")
public String paymentFeignTimeout();
最后在OrderFeignController
@GetMapping(value = "/consumer/payment/feign/timeout")
public String paymentFeignTimeout(){
//底层默认是openfeign-ribbon,客户端一般默认等待一秒
return paymentFeignService.paymentFeignTimeout();
}
停止8002,输入http://localhost:8001/payment/feign/timeout
三秒后出现8001的名字,自测通过
再输入http://localhost/consumer/payment/feign/timeout
出现错误:
Read timed out executing GET http://CLOUD-PAYMENT-SERVICE/payment/feign/timeout
说明出现了超时错误
可以在yml中设置超时时间
#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下, 两端连接所用的时间
ReadTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间
ConnectTimeout: 5000
再次输入上面的网址既不会报错
OpenFeign日志打印功能
日志级别:
NONE: 默认的,不显示任何日志
BASIC:仅记录请求方法、URL、响应状态码以及执行时间
HEADERS:除了BASIC中定义的信息以外,还有请求和响应的头信息
FULL: 除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据
先设置一个配置类:src/main/java/com/xs/springcloud/cfgbeans/FeignConfig.java
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
然后在yml中加入:
logging:
level:
#看feign日志监控哪个接口
com.xs.springcloud.service.PaymentFeignService: debug
重启输入http://localhost/consumer/payment/get/1
可在后台看到非常详细的日志内容
已经停止更新的Hystrix
分布式系统面临的问题:
复杂分布式体系结构应用程序会有非常多的依赖关系,每个依赖关系都在某个时候会有不可避免的失败,会对整个服务关系造成影响,最终变成服务雪崩。为了解决这个问题,就出现断路器模型。
Hystrix 是一个帮助解决分布式系统交互时超时处理和容错的类库, 它同样拥有保护系统的能力。
断路器本身就是个开关装置,当某个服务单元出现故障时,通过断路器的故障监控,向调用方返回一个符合预期的,可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证服务调用方的线程无需长时间地被占用,避免故障在分布式中的蔓延,乃至雪崩。
Hystrix能进行服务降级,服务熔断,服务限流,接近实时的监控等等
服务降级:当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心交易正常运作或高效运作。
服务熔断:在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施就叫做熔断。
服务限流:秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行。
对前面的内容进行改造,改造前的内容可以去自己的gitee仓库“43-46集”的版本看
接下来进行Hystrix支付微服务的构建
恢复单机版,去7001的yml中
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com
client:
# 不会自己注册自己
register-with-eureka: false
# 不需要检索服务,我自己就是服务中心
fetch-registry: false
service-url:
# 单机就是7001自己
defaultZone: http://eureka7001.com:7001/eureka/
新建模块cloud-provider-hystrix-payment8001
为了节约时间就不写impl了,正常是要写的
Pom就是按原版的8001加上,并删除数据库相关内容
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
Yml中
server:
port: 8001
spring:
application:
name: cloud-provider-hystrix-payment
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
# defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
defaultZone: http://eureka7001.com:7001/eureka
主启动类和以前一样没差
service层和controller中各两个方法
@Service
public class PaymentService {
//正常方法
public String paymentInfo_ok(Integer id){
return "线程池: "+Thread.currentThread().getName()+" paymentInfo_ok,id: "+id;
}
//错误方法
public String paymentInfo_TimeOut(Integer id){
int timeNumber = 3;
try{
TimeUnit.SECONDS.sleep(timeNumber);
}catch (InterruptedException e){
e.printStackTrace();
}
return "线程池: "+Thread.currentThread().getName()+" paymentInfo_TimeOut,id: "+id+",耗时: "+timeNumber;
}
}
@RestController
public class PaymentController {
@Resource
private PaymentService paymentService;
@Value("${server.port}")
private String serverPort;
//正常方法
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfo_ok(@PathVariable("id") Integer id){
return paymentService.paymentInfo_ok(id);
}
//错误方法
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_timeout(@PathVariable("id") Integer id){
return paymentService.paymentInfo_TimeOut(id);
}
}
启动eurka服务7001,再启动本项目,输入网址
http://localhost:8001/payment/hystrix/ok/1
显示:线程池: http-nio-8001-exec-1 paymentInfo_ok,id: 1
http://localhost:8001/payment/hystrix/timeout/1
显示:线程池: http-nio-8001-exec-1 paymentInfo_TimeOut,id: 1,耗时: 3
以上为43-50集的内容