OpenFeign使用
在微服务的架构中,传统的http客户端如Httpclient Okhttp HttpURLConnection RestTemplate WebClient 显然不适合。毕竟需要动态的获取服务地址,和进行负载均衡调用。
RPC框架
PC 全称是 Remote Procedure Call ,即远程过程调用,其对应的是我们的本地调用。
RPC 的目的是:让我们调用远程方法像调用本地方法一样。
![](https://i-blog.csdnimg.cn/blog_migrate/a5651b041473072a4264448e7cb55554.png)
具体过程就是一个服务端调用本地方法一样调用服务,rpc框架客户端会根据相应的方法的注解生成代理对象,然后代理对象中对方法名称,参数对象信息进行序列化,根据服务名称从注册中心获取需要请求的服务的地址,更据配置的协议请求对应的服务地址,服务端接收到请求之后,会根据服务名称找到对应的接口进行调用,调用完成后将结果进行序列化响应给客户端。
常用的Rpc框架有dubbo,OpenFegin,Grpc等
OpenFegin介绍
官方文档:https://docs.spring.io/spring-cloud-openfeign/docs/3.1.5/reference/html/
Feign是Netflix开发的声明式、模板化的HTTP客户端,是一款早期的rpc框架。
Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。
Spring Cloud openfeign对Feign进行了增强,使其支持Spring MVC注解,另外还整合了Ribbon和Nacos,从而使得Feign的使用更加方便。
OpenFegin基础示例
1、引入依赖
我使用的springCloud版本是2021
<!--nacos-服务注册发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--1. 添加openfeign依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 客户端负载均衡 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
2、服务启动类上添加**@EnableFeignClients**
仅仅客户端添加,服务端只要能提供http接口即可
@SpringBootApplication
@Slf4j
// 用于开启Fegin客户端
@EnableFeignClients
public class OpenFeignApplication {
public static void main(String[] args) {
SpringApplication.run(OpenFeignApplication.class, args);
log.info("{} startup success", "OpenfeginApplication");
}
}
3、客服端和服务端代码示例
客户端代码示例
@RestController
@RequestMapping(value = "/feign")
public class OpenFeignController {
@Autowired
private FeignService feignService;
@RequestMapping("/test")
public String get() {
Store stores = feignService.getStores(2L);
feignService.delete(1L);
Store update = feignService.update(2L, new Store());
return "陈宫";
}
}
@FeignClient("nacos-producer")// 此处对应的是服务名称
public interface FeignService {
@RequestMapping(method = RequestMethod.GET, value = "/nacos-producer/stores/{storeId}")
Store getStores(@PathVariable("storeId") Long storeId);
@RequestMapping(method = RequestMethod.POST, value = "/nacos-producer/stores/{storeId}", consumes = "application/json")
Store update(@PathVariable("storeId") Long storeId, Store store);
@RequestMapping(method = RequestMethod.DELETE, value = "/nacos-producer/stores/{storeId}")
void delete(@PathVariable("storeId") Long storeId);
}
服务端代码示例
@RestController
@RequestMapping("/stores")
@Slf4j
public class StoreController {
@DeleteMapping("/{storeId}")
public void delete(@PathVariable Long storeId) {
log.info("删除成功");
}
@PostMapping("/{storeId}")
public Store update(@PathVariable("storeId") Long storeId , @RequestBody Store store) {
log.info("修改成功");
return store;
}
@GetMapping("/{storeId}")
public Store getStores2(@PathVariable Long storeId) {
log.info("1");
Store store = new Store();
return store;
}
}
说明
客户端调用是否成功和最终的拼接的请求路径是否和服务端接口的请求路径一致,返回对象不一致也只是客户端请求成功后反序列化失败而已。
配置优先级
@EnableFeignClients可以指定全局的配置类,或者@Configuration注解下被扫描到的Feign的配置都是全局配置
@EnableFeignClients(basePackages = {"cn.sry1201.*","cn.sry"},defaultConfiguration = FeignConfig.class)
局部的注解配置类
@FeignClient(name = "nacos-producer2",configuration = FeignConfig.class)// 可以指定配置类,配置类中进行一些配置
还有全局配置文件和局部的配置文件
默认的优先级是 局部文件配置>全局默认文件配置>局部注解配置>全局默认注解配置
@FeignClient属性
不通过注册中心调用接口
如果引入了注册中心依赖,以我这个版本为例,接口请求路径中的ip和端口都是服务名,最终客户端负载均衡器会从注册中心获取对一个服务名的ip地址,然后替换成实际ip进行访问
我们也可以直接通过ip地址访问,示例如下,将基础示例中的配置改成如下进行测试即可
@FeignClient(name = "nacos-producer2",url = "http://localhost:8004")
动态设置@FeignClient属性
@FeignClient(name = "${feign.name}", url = "${feign.url}")
public interface StoreClient {
//..
}
配置类
@FeignClient(name = "nacos-producer2",configuration = FeignConfig.class)// 可以指定配置类,配置类中进行一些配置
配置类分全局配置和局部配置,如果加了@Configuration注解那就是全局配置
feign.Logger
日志级别
这里的logger是feign.Logger
public class FeignConfig {
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
通过源码可以看到日志等级有 4 种,分别是:
- NONE【性能最佳,适用于生产】:不记录任何日志(默认值)。
- BASIC【适用于生产环境追踪问题】:仅记录请求方法、URL、响应状态代码以及执行时间。
- HEADERS:记录BASIC级别的基础上,记录请求和响应的header。
- FULL【比较适用于开发及测试环境定位问题】:记录请求和响应的header、body和元数据。
当然上述级别说的是在springboot打印debug级别日志的情况下,feign定义的日志级别来打印不同完整度的日志,所以需要指定@FeignClient所在类的日志级别为debug,似乎不需要到日志的配置文件中操作,外部指定对应的记录器日志级别同样生效
logging:
# 指定日志配置文件位置,指定之后,外部配置文件失效,但是可以被配置文件内部引用,注意logback-spring.xml这个名称不能修改
config: classpath:log/logback-spring.xml
level:
#指定根记录器的级别,
root: debug
# 单独指定某个记录器的日志级别
cn.sry1201.producer.service: debug
以下是FULL级别的日志
![](https://i-blog.csdnimg.cn/blog_migrate/512644038281f95819cca010017d4966.png)
支持Feign原生的注解
Spring Cloud 在 Feign 的基础上做了扩展,使用 Spring MVC 的注解来完成Feign的功能。原生的 Feign 是不支持 Spring MVC 注解的,如果你想在 Spring Cloud 中使用原生的注解方式来定义客户端也是可以的,通过配置契约来改变这个配置,Spring Cloud 中默认的是 SpringMvcContract。
1、配置类中添加配置
/**
* 修改契约配置,支持Feign原生的注解
* @return
@Bean
public Contract feignContract() {
return new Contract.Default();
}
2、使用feign原生注解示例
@FeignClient(value = "mall-order",path = "/order")
public interface OrderFeignService {
@RequestLine("GET /findOrderByUserId/{userId}")
public R findOrderByUserId(@Param("userId") Integer userId);
}
超时时间配置
配置类中添加配置
// 分别是连接超时时间和读取超时时间
@Bean
public Request.Options options() {
return new Request.Options(5000, 10000);
}
自定义请求拦截器
public class FeignAuthRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
// 业务逻辑
String access_token = UUID.randomUUID().toString();
template.header("Authorization",access_token);
}
}
@Configuration // 全局配置
public class FeignConfig {
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
/**
* 自定义拦截器
* @return
*/
@Bean
public FeignAuthRequestInterceptor feignAuthRequestInterceptor(){
return new FeignAuthRequestInterceptor();
}
}
配置文件
局部配置类中局部配置在配置文件中的实现
# feign日志局部配置
feign:
client:
config:
nacos-producer:
loggerLevel: BASIC
# contract: feign.Contract.Default #设置为默认的契约 (还原成原生注解)
# 连接超时时间,默认2s
connectTimeout: 5000
# 请求处理超时时间,默认5s
readTimeout: 10000
request-interceptors:
- cn.sry1201.producer.intercepter.feign.CustomFeignInterceptor
配置优先级验证
添加配置和配置类的情况下,打印日志如下,显然是配置文件中配置优先级高
![](https://i-blog.csdnimg.cn/blog_migrate/c45cdef31cb8ab6d6d7c7d2aa3d145e7.png)
客户端组件配置
Feign 中默认使用 JDK 原生的 URLConnection 发送 HTTP 请求,我们可以集成别的组件来替换掉 URLConnection,比如 Apache HttpClient,OkHttp。
feign:
#feign 使用 okhttp
httpclient:
enabled: false
okhttp:
enabled: true#### 配置Apache HttpClient
开启配置后引入相关依赖即可,总之我这里报错了,不管,这个就做个记录吧,知道有这个配置
PoolingHttpClientConnectionManager : Closing expired connections
GZIP 压缩配置(不建议,会导致传输过程出现数据错误等…)
仅做记录,未测试
官方文档:https://docs.spring.io/spring-cloud-openfeign/docs/3.1.5/reference/html/#feign-requestresponse-compression
开启压缩可以有效节约网络资源,提升接口性能,我们可以配置 GZIP 来压缩数据:
feign:
# 配置 GZIP 来压缩数据
compression:
request:
enabled: true
# 配置压缩的类型
mime-types: text/xml,application/xml,application/json
# 最小压缩值
min-request-size: 2048
response:
enabled: true
注意:只有当 Feign 的 Http Client 不是 okhttp3 的时候,压缩才会生效,配置源码在FeignAcceptGzipEncodingAutoConfiguration
![](https://i-blog.csdnimg.cn/blog_migrate/c663f22dfb8f1975d100f42162936437.png)
核心代码就是 @ConditionalOnMissingBean(type=“okhttp3.OkHttpClient”),表示 Spring BeanFactory 中不包含指定的 bean 时条件匹配,也就是没有启用 okhttp3 时才会进行压缩配置。
注意事项
1、需要注意的是FeignClient的name属性不可重复
关联信息
- 关联的主题:
- 上一篇:
- 下一篇:
- image: 20221021/1
- 转载自: