@FeignClient标签
@FeignClient标签的常用属性如下:
name:指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现 url:
url一般用于调试,可以手动指定@FeignClient调用的地址 decode404:当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException configuration:
Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract fallback:
定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口
fallbackFactory: 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码
path:定义当前FeignClient的统一前缀,当我们项目中配置了server.context-path,server.servlet-path时使用
contextId比如我们有个user服务,但user服务中有很多个接口,我们不想将所有的调用接口都定义在一个类中,就可以使用他
@EnableFeignClients标签
@EnableFeignClients注解用来启动FeignClient,以支持Feign。该注解可以通过配置,扫描指定位置的@FeignClient注解声明的Feign客户端接口。
常用属性如下:
basePackages属性字段去指明应用程序A在启动的时候需要扫描服务B中的标注了@FeignClient注解的接口的包路径
basePackageClasses属性是basePackages属性的安全替代属性。该属性将扫描指定的每个类所在的包下面的所有被@FeignClient修饰的类;这需要考虑在每个包中创建一个特殊的标记类或接口,该类或接口除了被该属性引用外,没有其他用途。
defaultConfiguration属性用来自定义所有Feign客户端的配置,使用@Configuration进行配置。当然也可以为某一个Feign客户端进行配置。具体配置方法见@FeignClient的configuration属性。
clients扫描所有被@FeignClient注解指定的客户端列表。如果clients不是空数组,则不通过类路径自动扫描功能来加载FeignClient。
定义与使用feign
引用
父项目引入
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
子项目引入
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
使用@EnableFeignClients
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
编写feign客户端
@FeignClient(name = "user-service")
public interface UserClient {
/**
* 路径: /user/110
*
* @param id 用户id
* @return 用户
*/
@GetMapping("/user/{id}")
User queryById(@PathVariable("id") Long id);
}
配置与优化
feign相关配置
feign的日志级别
配置方式
方式一 代码配置
Feign配置类,可以添加在主类下,但是不用添加@Configuration。如果添加了@Configuration而且又放在了主类之下,那么就会所有Feign客户端实例共享,同Ribbon配置类一样父子上下文加载冲突;如果一定添加@Configuration,就放在主类加载之外的包。建议还是不用加@Configuration。
/**
* 配置
*
* @Description
* @Author weiwenbin
* @Date 2022/8/24 下午4:10
*/
public class DefaultFeignClientConfiguration {
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.BASIC;
}
}
局部-代码配置
在指定的客户端中加入configuration
@FeignClient(name = "user-service", configuration = DefaultFeignClientConfiguration.class)
全局-代码配置
在启动类的中EnableFeignClients注解中加入defaultConfiguration,
@EnableFeignClients(defaultConfiguration = DefaultFeignClientConfiguration.class)
方式二 配置文件(属性)配置
局部-属性配置
feign:
client:
config:
#想要调用的微服务名称
user-server:
loggerLevel: FULL
全局-属性配置
feign:
client:
config:
#将调用的微服务名称改成default就配置成全局的了
default:
loggerLevel: FULL
配置相关优化
Feign底层的客户端实现:
URLConnection:默认实现,不支持连接池
Apache HttpClient:支持连接池
OKHttp:支持连接池因此优化Feign的性能主要包括:
①、使用连接池代替默认的URLConnection
②、日志级别,最好用basic或none
HttpClient连接池配置
feign:
httpClient:
# 支持HttpClient的开关
enabled: true
代码配置
package cn.itcast.order.config;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
/**
* 连接池配置
*
* @Description 连接池配置
* @Author weiwenbin
* @Date 2022/8/25 下午2:12
*/
@Configuration
public class HttpClientConfig {
@Bean
public HttpClient httpClient() {
// 生成默认请求配置
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
// 超时时间
requestConfigBuilder.setSocketTimeout(5 * 1000);
// 连接时间
requestConfigBuilder.setConnectTimeout(5 * 1000);
RequestConfig defaultRequestConfig = requestConfigBuilder.build();
// 连接池配置
// 长连接保持30秒
final PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.MILLISECONDS);
// 总连接数
pollingConnectionManager.setMaxTotal(5000);
// 同路由的并发数
pollingConnectionManager.setDefaultMaxPerRoute(100);
// httpclient 配置
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
// 保持长连接配置,需要在头添加Keep-Alive
httpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());
httpClientBuilder.setConnectionManager(pollingConnectionManager);
httpClientBuilder.setDefaultRequestConfig(defaultRequestConfig);
HttpClient client = httpClientBuilder.build();
// 启动定时器,定时回收过期的连接
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
pollingConnectionManager.closeExpiredConnections();
pollingConnectionManager.closeIdleConnections(5, TimeUnit.SECONDS);
}
}, 10 * 1000, 5 * 1000);
System.out.println("===== Apache httpclient 初始化连接池===");
return client;
}
}
属性配置
feign:
client:
config:
default:
loggerLevel: BASIC
user-service:
loggerLevel: FULL
httpClient:
# 支持HttpClient的开关
enabled: true
# 最大连接数
max-connections: 200
# 单个路径的最大连接数
max-connections-per-route: 50
其他配置
feign:
compression:
# 配置请求GZIP压缩
request:
enabled: true
# 配置响应GZIP压缩
response:
enabled: true
client:
config:
feignName:
connectTimeout: 5000 # 相当于Request.Optionsn 连接超时时间
readTimeout: 5000 # 相当于Request.Options 读取超时时间
loggerLevel: full # 配置Feign的日志级别,相当于代码配置方式中的Logger
errorDecoder: com.example.SimpleErrorDecoder # Feign的错误解码器,相当于代码配置方式中的ErrorDecoder
retryer: com.example.SimpleRetryer # 配置重试,相当于代码配置方式中的Retryer
requestInterceptors: # 配置拦截器,相当于代码配置方式中的RequestInterceptor
- com.example.FooRequestInterceptor
- com.example.BarRequestInterceptor
# 是否对404错误解码
decode404: false
encode: com.example.SimpleEncoder
decoder: com.example.SimpleDecoder
contract: com.example.SimpleContract
配置优先级
属性配置大于代码配置,细粒度配置大于全局配置
优先级:细粒度属性配置 > 细粒度代码配置 > 全局属性配置 > 全局代码配置
坑:同时进行全局代码配置、细粒度代码配置如图,两个配置都不生效,原因可参考 Feign配置了全局日志后局部日志失效
错误原因:注入了两个Logger.Level对象,feign在获取上下文的Level对象时,因为有两个不知道取哪个所以直接返回一个null,拿feign的默认值
最佳实践(直接从ppt中copy的 理解即可)
Feign的最佳实践
方式一(继承):给消费者的FeignClient和提供者的controller定义统一的父接口作为标准。(不推荐)
缺点:
①、服务紧耦合
②、父接口参数列表中的映射不会被继承
方式二(抽取):将FeignClient抽取为独立模块,并且把接口有关的POJO、默认的Feign配置都放到这个模块中,提供给所有消费者使用
参考博客
https://juejin.cn/post/6844903961737035790
https://juejin.cn/post/6844903590159450126
https://blog.csdn.net/CSDN877425287/article/details/125026118