Feign
1.Feign是什么
Feign 是 Netflix 公司开发的一个声明式的 REST 调用客户端
(调用远程的restful风格的http接口 的一个组件)
调用组件其实很多,比如:
1、Httpclient(apache)
2、Httpurlconnection (jdk)
3、restTemplate(spring)
4、OkHttp(android)
5、Feign (Netflix) --> 实现非常优雅
Spring Cloud Feign 对 Ribbon 负载均衡进行了简化,在其基础上进行了进一步的封装,在配置上大大简化了开发工作,它是一种声明式的调用方式,它的使用方法是定义一个接口,然后在接口上添加注解,使其支持了Spring MVC标准注解和HttpMessageConverters,Feign可以与Eureka和Ribbon组合使用以支持负载均衡
2.Feign能干什么?
Feign旨在简化微服务消费方(调用者,客户端)代码的开发,前面在使用Ribbon+RestTemplate进行服务调用时,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方式,但是在实际开发中,由于服务提供者提供的接口非常多,一个接口也可能会被多处调用,Feign在Ribbon+RestTemplate的基础上做了进一步封装,在Feign封装之后,我们只需创建一个接口并使用注解的方式来配置,即可完成对服务提供方的接口绑定,简化了使用Ribbon + RestTemplate的调用,自动封装服务调用客户端,减少代码开发量
3.Feign的使用
3.1添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
3.2配置Feign
从SpringCloudEdgware开始,Feign支持使用属性自定义Feign。对于一个指定名称的FeignClient(例如该FeignClient的名称为feignName),Feign支持如下配置项
feign:
compression: #支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。通过下面的参数即可开启请求与响应的压缩功能
request:
enabled: true #开启请求压缩
mime-types: text/xml,application/xml,application/json #开启支持压缩的MIME TYPE
min-request-size: 2048 #配置压缩数据大小的下限
response:
enabled: true #开启相应压缩
client:
config:
default:
connectTimeout: 5000 #连接超时时间
readTimeout: 5000 #读超时时间
loggerLevel: full #日志级别
errorDecoder: StashErrorDecoder #Feign的错误解码器,这里我们自定义一个
retryer: CustomRetryer #自定义一个配置重试的方式
requestInterceptors: FeignRequestInterceptor #自定义请求拦截器
decode404: false #配置熔断不处理404
logging:
level:
com.example.nacosCofigClient.service.BuyerService: debug
feign的错误解码器
/**
* 自定义一个Feign的错误解码器
*/
@Configuration
public class StashErrorDecoder implements ErrorDecoder {
@Override
public Exception decode(String methodKey, Response response) {
if (response.status() >= 400 && response.status() <= 499) {
//这里是给出的自定义异常(先用null啦)
return null;
}
if (response.status() >= 500 && response.status() <= 599) {
//这里是给出的自定义异常(先用null啦)
return null;
}
//这里是其他状态码处理方法(先用null啦)
return null;
}
}
feign的请求拦截器
/**
* 自定义Feign拦截器
*/
public class FeignRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String values = request.getHeader(name);
requestTemplate.header(name, values);
}
}
}
}
请求拦截器要注册成bean
@Configuration
public class FeignInterceptorConfig {
/**
* feign请求拦截器
*/
@Bean
public RequestInterceptor requestInterceptor(){
return new FeignRequestInterceptor();
}
}
feign的重试器
@Component
public class CustomRetryer implements Retryer {
//最大重试次数
private int retryMaxAttempt;
//每次重试的间隔时间
private long retryInterval;
private int attempt = 1;
public CustomRetryer(){
}
public CustomRetryer(int retryMaxAttempt, Long retryInterval) {
this.retryMaxAttempt = retryMaxAttempt;
this.retryInterval = retryInterval;
}
/**
* 在continueOrPropagate方法中,你可以定制你的重试机制。
* 记住,为了停止重试并且传播错误信息,你必须抛出这个方法收到的retryable异常。
* 否则,它会继续重试。在这个例子中,我们在尝试我们设定的最大重试次数之后,抛出这个异常,
* 否则它会在继续下一次重试之前,等待间隔时间(参数)
* @param e
*/
@Override
public void continueOrPropagate(RetryableException e) {
System.out.println("Feign retry attempt {} due to {} " + attempt + e.getMessage());
if (attempt++ == retryMaxAttempt) {
throw e;
}
try {
Thread.sleep(retryInterval);
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
}
}
/**
* 返回构造器 6是最大重试次数,2000L时每次重试的间隔时间
* @return
*/
@Override
public Retryer clone() {
return new CustomRetryer(6, 2000L);
}
}
3.3feign的日志
在开发或者运行阶段往往希望看到Feign请求过程的日志记录,默认情况下Feign的日志是没有开启的。要想用属性配置方式来达到日志效果,只需配置一下即可
第一种
/**
* java bean的方式指定日志级别
* 配置Feign的日志Feign有四种日志级别:
* 1)NONE【性能最佳,适用于生产】:不记录任何日志(默认值)
* 2)BASIC【适用于生产环境追踪问题】:仅记录请求方法、URL、响应状态代码以及执行时间
* 3)HEADERS:记录BASIC级别的基础上,记录请求和响应的header。
* 4)FULL【比较适用于开发及测试环境定位问题】:记录请求和响应的header、body和元数据
*/
@Configuration
public class DefaultFeignConfiguration {
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.BASIC;
}
}
第二种
logging.level.xx : debug : Feign日志只会对日志级别为debug的做出响应
logging:
level:
com.example.nacosCofigClient.service.BuyerService: debug
3.4Feign使用OKhttp发送request
Feign底层默认是使用jdk中的HttpURLConnection发送HTTP请求,feign也提供了OKhttp来发送请求,具体配置如下:
feign:
okhttp:
enabled: true
hystrix:
enabled: true
4.Feign原理简述
- 启动时,程序会进行包扫描,扫描所有包下所有@FeignClient注解的类,并将这些类注入到spring的IOC容器中。当定义的Feign中的接口被调用时,通过JDK的动态代理来生成RequestTemplate。
- RequestTemplate中包含请求的所有信息,如请求参数,请求URL等。
- RequestTemplate声场Request,然后将Request交给client处理,这个client默认是JDK的HTTPUrlConnection,也可以是OKhttp、Apache的HTTPClient等。
- 最后client封装成LoadBaLanceClient,结合ribbon负载均衡地发起调用。
5.feign源码分析
通过上面的使用过程,@EnableFeignClients和@FeignClient两个注解就实现了Feign的功能,那我们从@EnableFeignClients注解开始分析Feign的源码
5.1EnableFeignClients
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({FeignClientsRegistrar.class})
public @interface EnableFeignClients {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<?>[] defaultConfiguration() default {};
Class<?>[] clients() default {};
}
剩下的看不懂啦
https://baijiahao.baidu.com/s?id=1698639270980356594&wfr=spider&for=pc