小编目前大一,刚开始着手学习微服务的相关知识,小编会把它们整理成知识点发布出来。我认为同为初学者,我把我对知识点的理解以这种代码加观点的方式分享出来不仅加深了我的理解,或许在某个时候对你也有所帮助,同时也欢迎大家在评论区分享你们的观点。
知不足而奋进,望远山而前行。
目录
简介
在前面我们已经清楚并且学会使用远程调用以及注册中心Nacos,现在让我们来学习一下OpenFeign它会给你带来意想不到的惊喜。OpenFeign是一个声明式的Http客户端,是SpringCloud在Eureka公司开源的Feign基础上改造而来。其作用就是基于SpringMVC的常见注解,帮助我们优雅的实现http请求的发送。官方网站如下:
Spring Cloud OpenFeign 中文文档 (springdoc.cn)
我们知道了OpenFeign是帮助我们优雅的实现http请求的发送,我们先来看看之前我们是怎么做的。首先根据服务名称拉去服务的实例列表,接着通过负载均衡获得单个实例服务,然后告诉它请求方式,请求路径,返回值类型,请求参数。
// 2.1 根据服务名称获取服务的实例列表
List<ServiceInstance> instances = discoveryClient.getInstances("item-service");
if (CollUtil.isEmpty(instances)) {
return;
}
// 2.2 手写负载均衡,从实例列表中挑选一个实例
ServiceInstance instance = instances.get(RandomUtil.randomInt(instances.size()));
// 2.3 利用RestTemplate发起http请求,得到http的响应
ResponseEntity<List<ItemDTO>> response = restTemplate.exchange(
instance.getUri() + "/items?ids={ids}",
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<ItemDTO>>() {
},
Map.of("ids", CollUtil.join(itemIds, ","))
);
快速入门
那现在上面这些繁琐的步骤我们不想做了,我们想让OpenFeign来帮我们实现,那我们来看一下该怎么做。
首先第一步引入依赖,包括OpenFeign和负载均衡组件SpringCloudLoadBalancer,接着第二步通过@EnableFeignClients注解,启用OpenFeign功能,第三步编写FeignClient,第四步使用FeignClient,实现远程调用。
第一步引入依赖也就没有什么好说的了。
<!--openFeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--负载均衡器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
第二步我们要在启动类上加上 @EnableFeignClients注解,这相当于打开OpenFeign的开关。
@SpringBootApplication
@EnableFeignClients
public class CartlApplication {
public static void main(String[] args) {
SpringApplication.run(CartlApplication.class, args);
}
}
第三步就是编写FeignClient,这个接口就相当于我们之前的exchange方法。@FeignClient注解用来指定服务的名字,有了服务的名字后,又因为我们之前引入了负载均衡器的依赖,所以他就可以给我们一个服务,@GetMapping注解指定了请求方式,后面跟的以及@RequestParam注解就是请求路径和请求参数以及方法返回值。那么现在OpenFeign就知道了该怎么发请求,给谁发请求这些信息,所以现在OpenFeign就可以帮我们去优雅的发送请求。
@FeignClient("item-service")
public interface ItemClient {
@GetMapping("/items")
List<ItemDTO> queryItemByIds(@RequestParam("ids") Set<Long> ids);
}
同样写完FeignClient接口后并不需要去实现,将来OpenFeign动态代理会帮我们去实现。
第四步使用FeignClient,实现远程调用,就这么一行,就已经实现了远程调用。
// 2.查询商品
List<ItemDTO> items = itemClient.queryItemByIds(itemIds);
同样我们也可以去启动服务测试一下,也是没有问题的。
底层原理
在了解完OpenFeign的使用后,相信大家都很疑惑它的底层是怎么实现的呢。现在我们来了解它的底层原理,同时还可以做一点简单优化。
我们知道itemClient是OpenFeign动态代理去实现的,我们可以通过断点模式观察到它是一个Proxy101,证明他就是一个代理对象,我们又知道动态代理对象底层都是由InvocationHandler去实现的,正如下面h所示。我们接下来就去看看h的类型FeignInvocataionHandler看看。
在FeignInvocataionHandler内部,invoke方法就是来做代理的。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (!"equals".equals(method.getName())) {
if ("hashCode".equals(method.getName())) {
return this.hashCode();
} else {
return "toString".equals(method.getName()) ? this.toString() : ((InvocationHandlerFactory.MethodHandler)this.dispatch.get(method)).invoke(args);
}
} else {
try {
Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
return this.equals(otherHandler);
} catch (IllegalArgumentException var5) {
return false;
}
}
}
其中我们再往下面的invoke方法进行跟进,它就会对我们的FeignClient进行请求拼接。
最终请求路径,请求方式,参数这些准备好后,会交给一个叫delegate的代理对象去发送请求。delegate是一个client接口,client接口是专门用来发http请求的,默认是采用的是HttpURLConnection这种方式来发送的,这种方式每次都要手动创建连接,再用stream流去书写,效率非常低。所以我们可以对其进行一点优化。
连接池优化
OpenFeign对Http请求做了优雅的伪装,不过其底层发起http请求,依赖于其它的框架。这些框架可以自己选择,包括以下三种:HttpURLConnection,Apache HttpClient OKHttp,这三种不同之处参考下图。
这里我们就使用OKHttp来优化,具体步骤也就两步,非常简单。
首先第一步引入OKHttp的依赖,第二步开启连接池功能。
<!-- ok-http-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
开启连接池功能其实也容易,只要把一个开关打开就好了。
feign:
okhttp:
enabled: true # 开启OKHttp连接池支持
这样我们就实现好了通过连接池对OpenFeign性能的优化。
最佳实践
在实际开发中我们如果要使用OpenFeign,我们一般是把他放到另一个api模块中,因为这样能减少代码的重复,但是这也增加了一定的耦合性。另外我们还可以把一些经常被调用的服务模块拆分成dto,api,biz模块,dto模块就负责存放实体类,api模块负责定义FeignClient接口,biz模块就负责存放当前服务层的业务代码。
以上这两种方案都是OpenFeign的最佳实践,具体选择哪种方案还得看实际情况决定
日志输出
我们都知道在开发当中日志输出是非常重要的,所以我们也有必要去了解一下OpenFeign的日志输出。
OpenFeign只会在FeignClient所在包的日志级别为DEBUG时,才会输出日志。而且其日志级别有四级:NONE,BASIC,HEADERS,FULL。具体的区别看下图。
我们当前所在的整个父工程都是DEBUG已经达到了第一个要求,接下来我们还要去设置OpenFeign自己的日志级别。这个设置还是和以往设置日志级别有所不同,我们需要声明一个类型为Logger.Level的Bean ,在其中定义日志级别。
public class DefaultFeignConfig {
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
但此时这个Bean并未生效,要想配置某个FeignClient的日志,可以在@FeignClient注解中声明:
但是这只是局部配置,如果想要全局配置,让所有的FeignClient都按照这个日志配置,则需要在@EnableFeignClients注解中声明:
@EnableFeignClients(defaultConfiguration = DefaultFeignConfig.class, basePackages = "com.hmall.api.client")
接着你就可以去开启项目观看一下日志了。
以上就是OpenFeign的相关知识。
带着决心起床,带着满意入睡。