文章目录
一、OpenFeign是什么?
Feign 是一个声明式的WebService客户端,使用Feign 能让编写WebService的客户端更加简单,他可以通过定义一个服务接口然后在上面添加注解的方式,Feign 也可以支持可拔插的编码器和解码器,SpringCloud对Feign进行了封装,使其支持了Spring MVC的标准注解和 HttpMessageConverters,Feign可以与Eureka和Ribbon组合支持负载均衡。
前面在使用 Ribbon和RestTemplate时, 使用RestTemplate对Http 请求的封装处理,形成了模版化的调用方式,但是实际开发中,由于对服务依赖的调用可能不止一处 ,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用,所以Feign在此基础上做了进一步的封装,由他来帮助我们定义和实现依赖服务接口的定义,在Feign的实现下,我们只需要创建一个借口并使用注解的方式来配置它(类似于SpringMvc的Controller层不写实现类,??SpringMvc和Mybatis结合体??? 哈哈),即可完成对服务提供方的接口绑定,简化了Ribbon的使用。
二、如何使用
1.创建module,并引入依赖
继续在原来的工程上创建一个模块sgg-consumer-feign80
<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>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
2.创建application.yml文件
server:
port: 80
spring:
application:
name: ssg-consumer-service
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka,http://localhost:7002/eureka
instance:
instance-id: sgg-consumer-feign80
prefer-ip-address: true
3. 创建cn.fllday.remote包,进行远程调用
依旧是调用 SGG-PAYMENT-SERVICE
服务
@Component
@FeignClient(value = "SGG-PAYMENT-SERVICE")
public interface OrderRemoteService {
@GetMapping(value = "/payment/{id}")
CommonResult getOrderPayment(@PathVariable("id") Long id);
@PostMapping(value = "/payment/create")
CommonResult createPayment(@RequestBody Payment payment);
@GetMapping(value = "/payment/timeout")
CommonResult getFeignTimeout();
}
4. 创建 cn.fllday.controller , 创建对外接口
@RequestMapping(value = "/consumer/feign/payment")
@RestController
public class OrderFeignController {
@Autowired
private OrderRemoteService orderRemoteService;
@GetMapping(value = "/{id}")
public CommonResult getFeignPaymentById(@PathVariable(value = "id") Long id) {
return orderRemoteService.getOrderPayment(id);
}
@PostMapping(value = "/create")
public CommonResult createPayment(Payment payment) {
return orderRemoteService.createPayment(payment);
}
@GetMapping(value = "/timeout")
public CommonResult getFeignTimeout() {
return orderRemoteService.getFeignTimeout();
}
}
5. 给服务提供者添加一个时间比较长的接口
PaymentController.java
@GetMapping(value = "timeout")
public CommonResult timeOut() throws InterruptedException {
Thread.sleep(4000);
return new CommonResult(200, "111");
}
启动类添加 @EnableFeignClients
注解
@SpringBootApplication
@EnableFeignClients
@EnableEurekaClient
public class OrderFeign80App {
public static void main(String[] args) {
SpringApplication.run(OrderFeign80App.class, args);
}
}
6.打开postman 准备访问啦
首先访问 post 接口
访问成功
查询 get 接口
多访问几次,可以发现我们的 feign 是支持负载均衡的,因为 feign 也是集成了 ribbon 的。
访问时间比较长的接口
@GetMapping(value = "/timeout")
public CommonResult getFeignTimeout() {
return orderRemoteService.getFeignTimeout();
}
咦,报错了。看看控制台的报错信息,因为异常信息太多,所以就不进行全部粘贴了
java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(SocketInputStream.java) ~[na:1.8.0_201]
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) ~[na:1.8.0_201]
at java.net.SocketInputStream.read(SocketInputStream.java:171) ~[na:1.8.0_201]
at java.net.SocketInputStream.read(SocketInputStream.java:141) ~[na:1.8.0_201]
不过人家的错误提示已经很明显了。 就是读取时间超时。 这是因为feign 的默认超时时间是 1 秒钟,如果响应超出了这个时间,就会出现这个错误。 所以我们需要配置一下Feign 的响应时间
在application.yml文件中添加以下配置
# 设置feign 客户端超时时间, openFeign 默认支持 ribbon
ribbon:
# 指的是建立连接所用的时间, 适用于网络状态正常的情况下, 两端连接所用的时间
ReadTimeout: 5000
# 指的是建立连接后从服务器读取到可用资源所用的时间。
ConnectTimeout: 5000
重启服务之后,再次调用该接口
可以发现我们的服务调用成功了。
7.Feign的局部配置
系统不可能仅仅只调用一个服务,所以如果你对调用服务的配置超时时间不一致,还可以只配置局部,也就是你如果有两个服务 service 。 你可以一个配置 3 秒,一个配置 1 秒。
#局部配置
# 对所有操作请求都进行重试
SGG-PAYMENT-SERVICE:
ribbon:
OkToRetryOnAllOperations: true
# 对当前实例的重试次数
SGG-PAYMENT-SERVICE:
ribbon:
MaxAutoRetries: 2
# 切换实例的重试次数
SGG-PAYMENT-SERVICE:
ribbon:
MaxAutoRetriesNextServer: 0
# 请求连接的超时时间
SGG-PAYMENT-SERVICE:
ribbon:
ConnectTimeout: 3000
# 请求处理的超时时间
SGG-PAYMENT-SERVICE:
ribbon:
ReadTimeout: 3000
这里就不做演示了。
8. Feign 的日志增强
查看Feign 的每次远程调用的具体日志
创建Feign的配置类
@Configuration
public class FeignConfig {
@Bean
Logger.Level level() {
return Logger.Level.FULL;
}
}
配置yml 文件
logging:
level:
cn.fllday.remote.OrderRemoteService: debug # 指定哪一个远程调用类
再次访问我们的接口 查看日志打印。,
22:26:40.287 [http-nio-80-exec-5] DEBUG o.s.web.servlet.DispatcherServlet:91- GET "/consumer/feign/payment/1", parameters={}
22:26:40.288 [http-nio-80-exec-5] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping:412- Mapped to cn.fllday.controller.OrderFeignController#getFeignPaymentById(Long)
22:26:40.289 [http-nio-80-exec-5] DEBUG cn.fllday.remotes.OrderRemoteService:72- [OrderRemoteService#getOrderPayment] ---> GET http://SGG-PAYMENT-SERVICE/payment/1 HTTP/1.1
22:26:40.289 [http-nio-80-exec-5] DEBUG cn.fllday.remotes.OrderRemoteService:72- [OrderRemoteService#getOrderPayment] ---> END HTTP (0-byte body)
22:26:40.289 [http-nio-80-exec-5] DEBUG c.n.l.ZoneAwareLoadBalancer:112- Zone aware logic disabled or there is only one zone
22:26:40.290 [http-nio-80-exec-5] DEBUG c.n.loadbalancer.LoadBalancerContext:492- SGG-PAYMENT-SERVICE using LB returned Server: 192.168.101.2:8001 for request http:///payment/1
22:26:40.305 [http-nio-80-exec-5] DEBUG cn.fllday.remotes.OrderRemoteService:72- [OrderRemoteService#getOrderPayment] <--- HTTP/1.1 200 (15ms)
22:26:40.305 [http-nio-80-exec-5] DEBUG cn.fllday.remotes.OrderRemoteService:72- [OrderRemoteService#getOrderPayment] connection: keep-alive
22:26:40.305 [http-nio-80-exec-5] DEBUG cn.fllday.remotes.OrderRemoteService:72- [OrderRemoteService#getOrderPayment] content-type: application/json
22:26:40.305 [http-nio-80-exec-5] DEBUG cn.fllday.remotes.OrderRemoteService:72- [OrderRemoteService#getOrderPayment] date: Tue, 08 Sep 2020 14:26:40 GMT
22:26:40.305 [http-nio-80-exec-5] DEBUG cn.fllday.remotes.OrderRemoteService:72- [OrderRemoteService#getOrderPayment] keep-alive: timeout=60
22:26:40.305 [http-nio-80-exec-5] DEBUG cn.fllday.remotes.OrderRemoteService:72- [OrderRemoteService#getOrderPayment] transfer-encoding: chunked
22:26:40.306 [http-nio-80-exec-5] DEBUG cn.fllday.remotes.OrderRemoteService:72- [OrderRemoteService#getOrderPayment]
22:26:40.306 [http-nio-80-exec-5] DEBUG cn.fllday.remotes.OrderRemoteService:72- [OrderRemoteService#getOrderPayment] {"code":200,"message":"查询成功","data":"8001"}
22:26:40.306 [http-nio-80-exec-5] DEBUG cn.fllday.remotes.OrderRemoteService:72- [OrderRemoteService#getOrderPayment] <--- END HTTP (51-byte body)
22:26:40.306 [http-nio-80-exec-5] DEBUG o.s.w.c.HttpMessageConverterExtractor:102- Reading to [cn.fllday.entity.CommonResult<?>]
22:26:40.307 [http-nio-80-exec-5] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor:273- Using 'application/json', given [*/*] and supported [application/json, application/*+json, application/json, application/*+json]
22:26:40.307 [http-nio-80-exec-5] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor:91- Writing [CommonResult(code=200, message=查询成功, data=8001)]
22:26:40.308 [http-nio-80-exec-5] DEBUG o.s.web.servlet.DispatcherServlet:1131- Completed 200 OK
如果没有的,你可以去配置一下logback-spring.xml 如果还是没有,那只能说你太倒霉了。我也没有别的解决办法了