OpenFeign简介
概述
Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单。
他的使用方法是 定义一个服务接口,然后在上面添加注解。 Feign也支持可拔插式的编码器和解码器。Feign可以与Eureka和Ribbon组合使用以支持负载均衡
作用
Feign旨在使编写java http客户端变得更简单。在使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,形成了一套模板化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往在一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端来包装这些依赖服务的调用。 所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置它 ,即可完成对服务提供方接口绑定,简化了使用Spring Cloud Ribbon时,自动封装服务调用客户端的开发量。
OpenFeign服务调用
接口加注解调用
pom
<dependencies>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>cn.nwnu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--一般基础通用配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
application.yml
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
启动类
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableFeignClients //激活OpenFeign
public class OrderFeignMain80 {
public static void main(String args[]){
SpringApplication.run(OrderFeignMain80.class, args);
}
}
客户端服务接口
@FeignClient
value是注册进eureka的服务名称
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {
/**
* 相当于RestTemplate调用微服务http://CLOUD-PAYMENT-SERVICE/payment/get/{id}
* openFeign做了封装,简化开发,在controller直接调用PaymentFeignService即可
* @param id
* @return
*/
@GetMapping(value = "/payment/get/{id}")
public CommonResult getPaymentById(@PathVariable("id") Long id);
}
controller
@RestController
@Slf4j
public class OrderFeignController {
@Resource
private PaymentFeignService paymentFeignService;
@GetMapping(value = "/consumer/payment/get/{id}")
public CommonResult getPaymentById(@PathVariable("id") Long id){
//直接调用PaymentFeignService
return paymentFeignService.getPaymentById(id);
}
}
OpenFeign超时控制
OpenFeign默认等待1s,超过1s就报错timeout
演示超时
- 在服务端8001、8002添加代码
/**
* 演示超时
* @return
*/
@GetMapping(value = "/feign/timeout")
public String paymentFeignTimeout(){
//暂停几秒钟线程
try{
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return serverPort;
}
- 客户端80 service添加接口
@GetMapping(value = "/payment/feign/timeout")
public String paymentFeignTimeout();
- controller调用
/**
* 演示超时
* @return
*/
@GetMapping(value = "/consumer/payment/feign/timeout")
public String paymentFeignTimeout(){
return paymentFeignService.paymentFeignTimeout();
}
通过上述步骤,服务自测通过,但是通过客户端访问是,报错timeout
设置客户端的超时时间
默认Feign客户端只等待一秒,但是服务端处理超过1秒,导致feign客户端不想等待了,直接返回报错,为了避免这样的错误,我们需要设置Feign客户端超时控制
yml开启配置
#设置Feign客户端超时时间(OpenFeign默认支持Ribbon
ribbon:
# 指的是建立连接所用的时间,适用于网络正常的情况下,两端连接所用时间
ReadTimeout: 5000
# 指的是建立连接后从服务器读取到可用资源所用的时间
ConnectTimeout: 5000
OpenFeign日志增强
简介
feign提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解Feign中http请求的细节,说白了就是***对Feign接口的调用进行监控和输出***
日志级别
- NONE:默认的,不显示任何日志
- BASIC:仅记录请求方法、url、响应状态码及执行时间
- HEADERS:除了BASIC定义的信息之外,还有请求和响应的头信息
- FULL:除了HEADERS定义的信息外,还有请求及响应的正文及元数据
开启日志
配置类
配置日志bean
package cn.nwnu.springcloud.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfig {
/**
* 开启最详细的日志
* @return
*/
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
yml
yml文件需要开启日志的Feign客户端
logging:
level:
# feign日志以什么级别监控哪个接口
cn.nwnu.springcloud.services.PaymentFeignService: debug
控制台日志打印
2020-03-17 09:59:23.101 DEBUG 4000 --- [p-nio-80-exec-1] c.n.s.services.PaymentFeignService : [PaymentFeignService#getPaymentById] <--- HTTP/1.1 200 (325ms)
2020-03-17 09:59:23.101 DEBUG 4000 --- [p-nio-80-exec-1] c.n.s.services.PaymentFeignService : [PaymentFeignService#getPaymentById] connection: keep-alive
2020-03-17 09:59:23.101 DEBUG 4000 --- [p-nio-80-exec-1] c.n.s.services.PaymentFeignService : [PaymentFeignService#getPaymentById] content-type: application/json
2020-03-17 09:59:23.101 DEBUG 4000 --- [p-nio-80-exec-1] c.n.s.services.PaymentFeignService : [PaymentFeignService#getPaymentById] date: Tue, 17 Mar 2020 01:59:23 GMT
2020-03-17 09:59:23.101 DEBUG 4000 --- [p-nio-80-exec-1] c.n.s.services.PaymentFeignService : [PaymentFeignService#getPaymentById] keep-alive: timeout=60
2020-03-17 09:59:23.101 DEBUG 4000 --- [p-nio-80-exec-1] c.n.s.services.PaymentFeignService : [PaymentFeignService#getPaymentById] transfer-encoding: chunked
2020-03-17 09:59:23.102 DEBUG 4000 --- [p-nio-80-exec-1] c.n.s.services.PaymentFeignService : [PaymentFeignService#getPaymentById]
2020-03-17 09:59:23.103 DEBUG 4000 --- [p-nio-80-exec-1] c.n.s.services.PaymentFeignService : [PaymentFeignService#getPaymentById] {"code":200,"message":"成功8001","data":{"id":31,"serial":"dfsgsfhsgf"}}
2020-03-17 09:59:23.103 DEBUG 4000 --- [p-nio-80-exec-1] c.n.s.services.PaymentFeignService : [PaymentFeignService#getPaymentById] <--- END HTTP (74-byte body)
2020-03-17 09:59:23.994 INFO 4000 --- [erListUpdater-0] c.netflix.config.ChainedDynamicProperty : Flipping property: CLOUD-PAYMENT-SERVICE.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647