OpenFeign 底层就是Http的调用。减少了使用OkHttp,RestTemplate 代码耦合度,提高了代码利用率。
同时可以配合注册中心,实现负载均衡请求
引入和配置Feign
版本要与SpringBoot一致
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>${}</version>
</dependency>
SpringBoot启动类添加EnableFeignClients注解
value属性指定Feign接口所在包路径,扫描以生成代理类
@FeignClient(name = "userFeign",url = "http://127.0.0.1:8080")
public interface UserFeign {
@GetMapping("/user/getRandomId")
String getRandomId();
}
// 如果配置了URL会调用url指定的服务地址和端口
// 如果未配置URL则会根据注册中心的服务名称name值,调用(此方法可以达到负载均衡机制)
日志
Logger 抽象类实现了对Feign日志输出的格式定义,包括 请求前,请求后
Slf4jLogger 是Logger抽象类的实现类,具体实现了日志输出log()方法,默认使用该类进行的日志打印
上面两个类都是Feign包下的,由OpenFeign实现
feign:
client:
config:
default: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
loggerLevel: FULL # 日志级别,NONE,BASIC,HEADERS,FULL
自定义重写Logger格式。适用于开发测试期间输出详细情况,来发现问题(比如注入链式日志追踪TraceId)
Logger类
//主要是四个方法
//log() 输出日志时直接调用,由具体实现类实现
protected abstract void log(String configKey, String format, Object... args);
// feign请求前进行进行打印日志,打印请求信息
protected void logRequest(String configKey, Level logLevel, Request request) {}
// feign响应后打印日志,打印响应信息
protected Response logAndRebufferResponse(String configKey,
Level logLevel,
Response response,
long elapsedTime)
throws IOException {}
// feign调用发生异常时,进行调用
protected IOException logIOException(String configKey,
Level logLevel,
IOException ioe,
long elapsedTime) {}
例如:自定义实现日志输出
@Bean
public Logger logger(){
Logger logger = new Logger() {
// 直接利用Slf4jLogger实现
@Override
protected void log(String configKey, String format, Object... args) {
log.debug(String.format(methodTag(configKey) + format, args));
}
@Override
protected void logRequest(String configKey, Level logLevel, Request request) {
log.info("开始请求....."+configKey);
}
@Override
protected Response logAndRebufferResponse(String configKey, Level logLevel, Response response, long elapsedTime) throws IOException {
byte[] bytes = Util.toByteArray(response.body().asInputStream());
log.info("获取响应的结果...."+ new String(bytes));
return response.toBuilder().body(bytes).build();// 参照Slf4jLogger实现,因为已经读取了一次流,流已经关闭。需要重新创建响应体
}
};
return logger;
}
拦截器
拦截器可以在Feign发送请求时,在请求头中添加字段
@Bean
public RequestInterceptor requestInterceptor(){
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
log.info("feign 请求前添加请求头");
requestTemplate.header("traceId",traceId);
}
};
}
重试机制
Feign重试机制默认是不开启的
可以通过实现Retryer接口,将实现类注入到Spring IOC容器中
已有的重试机制是Retryer.Default
Retry.Default类中 continueOrPropagate()方法,实现了请求次数和请求时间间隔的逻辑
局部配置和全剧配置
@Configuration
@Slf4j
public class FeignConfig {
@Bean
public RequestInterceptor requestInterceptor(){
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
log.info("feign 请求前添加请求头");
requestTemplate.header("traceId",traceId);
}
};
}
@Bean
public Logger logger(){
Logger logger = new Logger() {
@Override
protected void log(String configKey, String format, Object... args) {
log.debug(String.format(methodTag(configKey) + format, args));
}
@Override
protected void logRequest(String configKey, Level logLevel, Request request) {
log.info("开始请求....."+configKey);
}
@Override
protected Response logAndRebufferResponse(String configKey, Level logLevel, Response response, long elapsedTime) throws IOException {
byte[] bytes = Util.toByteArray(response.body().asInputStream());
log.info("获取响应的结果...."+ new String(bytes));
return response.toBuilder().body(bytes).build();// 因为已经读取了一次流,流已经关闭。需要重新创建响应体
}
};
return logger;
}
@Bean
public Retryer retryer(){
// 初始重试间隔时间 (默认按照1.5倍递增)
// 最大重试间隔时间
// 最大重试次数
return new Retryer.Default(100,1000,5);
}
@Bean
public Request.Options options(){
// 链接服务端超时时间ms
// 接受服务端响应时间ms
// 是否支持重定向
return new Request.Options(1000,1000,true);
}
}
自定义的Logger实现类,加了@Configuration交给Spring容器进行管理,就是全局配置
局部配置,取消@Configuration注解,通过@FeignClient(name = “feign”,configuration = FeignConfig.class),进行配置