Feign导航
简介
最近都在弄微服务的东西,现在来记录下收获。我从一知半解到现在能从0搭建使用最大的感触有两点
1.微服务各大组件的版本很多,网上很多博客内容不一定适合你的版本,很多时候苦苦琢磨都是无用功
2.网上博客参差不齐,有些甚至错误的。更离谱的是,好的文章阅读量除非高出天际,不然就都很低,比那些复制粘贴,随便应付的都低(这个搜索推荐算法不知道基于什么的)
通过这段时间学习,我觉得最重要是从好的博客入手,先不要着急怎么组件怎么使用,而是先了解组件的作用,大概的原理,然后才是使用,这样搭建和尝试的过程中才能更好的定位问题,最后再次回到原理和一些实际问题的处理(不知道实际问题怎样的,直接搜那个组件的面试题往往效果最好)
接下来的内容,都以导航的形式展现给大家(毕竟优秀的轮子很多,直接看大佬写的不香嘛),再顺带提些自己的理解
传送门
更多微服务的介绍可点击下方链接
微服务介绍、Nginx导航、Nacos导航、Gateway导航、Ribbon导航、Feign导航、Sentinel导航
博主微服务git练手项目:https://github.com/NiceJason/SpringCloudDemo
Feign导航
Feign详细讲解:https://blog.csdn.net/luanlouis/article/details/82821294
文中有几个地方的点提一下
1.将调用抽象为starter
文中提到,作者团队将远程调用抽象成接口,定义了服务端starter,服务消费者在使用的时候,只需要引入Starter,就可以调用服务。这个比较适合平台无关性,接口抽象出来的好处就是可以根据服务调用实现方式自有切换。这种思路跟Spring里面的log框架类似,我们调用log都是调用接口,Spring内部默认有一套日志类实现了此接口,我们经常自己指定log4j2去代替它,只要引用配置和相关starter就行,代码上丝毫不用动。
2.高版本Feign
@GetMapping,@PutMapping在高版本的Feign中也是可用的了(目前直接把Controller的方法直接复制到@FeignClient接口中调用是没问题)
3.让Feign支持文件传输
我们可以看到好的框架扩展性真的强,如Encode和Decode都是接口暴露出来,我们经常用JacksonEncoder,JacksonDecoder去替代它又或者SpringCloud这种框架有自己的替代方案。我们虽然写业务较多,没什么机会写这种牛逼的组件,但这设计思想还是可以用的。顺便提一下由于Feign默认的读取的配置FeignClientsConfiguration,里面的Encoder默认是springEncoder,该类型不支持文件格式,所以要换成以下
1 import feign.form.spring.SpringFormEncoder; 2 import org.springframework.beans.factory.ObjectFactory; 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.boot.autoconfigure.http.HttpMessageConverters; 5 import org.springframework.cloud.openfeign.support.SpringEncoder; 6 import org.springframework.context.annotation.Bean; 7 import org.springframework.context.annotation.Configuration; 8 9 /** 10 * @Author DiaoJianBin 11 * @Description Feign的通用配置 12 * @Date 2021/3/11 9:56 13 */ 14 @Configuration(proxyBeanMethods = false) 15 public class FeignConfig { 16 17 @Autowired 18 private ObjectFactory<HttpMessageConverters> messageConverters; 19 20 @Bean 21 public SpringFormEncoder feignFormEncoder(){ 22 return new SpringFormEncoder(new SpringEncoder(messageConverters)); 23 } 24 }
其中SpringFormEncoder的部分代码如下,可以看到开头判断了是否是MultipartFile类或者数组
1 @Override 2 public void encode (Object object, Type bodyType, RequestTemplate template) throws EncodeException { 3 if (bodyType.equals(MultipartFile[].class)) { 4 val files = (MultipartFile[]) object; 5 val data = new HashMap<String, Object>(files.length, 1.F); 6 for (val file : files) { 7 data.put(file.getName(), file); 8 } 9 super.encode(data, MAP_STRING_WILDCARD, template); 10 } else if (bodyType.equals(MultipartFile.class)) { 11 val file = (MultipartFile) object; 12 val data = singletonMap(file.getName(), object); 13 super.encode(data, MAP_STRING_WILDCARD, template); 14 } else if (isMultipartFileCollection(object)) { 15 val iterable = (Iterable<?>) object; 16 val data = new HashMap<String, Object>(); 17 for (val item : iterable) { 18 val file = (MultipartFile) item; 19 data.put(file.getName(), file); 20 } 21 super.encode(data, MAP_STRING_WILDCARD, template); 22 } else { 23 super.encode(object, bodyType, template); 24 } 25 }
4.Feign的重试注意点
文中讲了Feign的重试,一般微服务都会整合Ribbon,发送的负载均衡,重试等都是由Ribbon负责的,可以看Feign里的源码
我们想要启用Feign会在SpringbootApplication类上加注解@EnableFeignClients
这个注解里有如下说明,告诉我们默认配置看FeignClientsConfiguration
然后看FeignClientsConfiguration类可以看到,可以在这里打个断点,然后启动项目就能了解清楚啦
从这可以看到,Feign默认是关闭重试的
具体想开启重试,即要开启Ribbon的重试,具体内容可以在传送门点击Ribbon导航,里面有介绍
5.Feign开启OkHttpClient
目前效率最高的当属okHttpClient,以下是怎么在Feign中开启和配置相关内容
#使用okHttp作为客户端
feign.httpclient.enabled=false
feign.okhttp.enabled=true
#配置其中的属性,开启okhttp后下面几个无效
#默认最大连接数
#feign.httpclient.max-connections=1000
#单个调用最大连接数
#feign.httpclient.max-connections-per-route=100
#当http返回码为3xxx时,默认会重定向操作
#feign.httpclient.follow-redirect=false
#配置Sentinel
feign.hystrix.enabled=true
feign.sentinel.enabled=true
6.Feign的回退注意点
从上面的配置中,有人可能会问,为啥开启了hystrix又开启sentinel,两者不都是熔断限流的组件嘛,在我项目里用的是sentinel,所以sentinel需要开启
而hystrix开启是因为Feign的回退(fallbackFactory或者fallback)需要开启这个才能正常执行,像我们经常这样写
1 /** 2 * @Author DiaoJianBin 3 * @Description 访问BusinessService服务的接口 4 * 有2种回退策略 5 * 1.fallback = BusinessServiceTestClientFallback.class 6 * 2.fallbackFactory = BusinessServiceTestFallballFactory.class 7 * 当两者存在时,只能有一种生效,fallback优先级高于fallbackFactory 8 * 但是fallback无法处理异常,就是你不知道啥原因进入了降级 9 * 推荐用fallback优先级高于fallbackFactory 10 * @Date 2021/3/11 11:23 11 */ 12 @Primary 13 @FeignClient(value = "business-service",path = "/test",decode404 = true,fallbackFactory = BusinessServiceTestFallballFactory.class) 14 public interface BusinessServiceTestClient { 15 16 /** 17 * 即使目标实际Controller的方法有HttpServletRequst 18 * 但是不需要传此参数,就不用写 19 * @param message 20 * @return 21 */ 22 @PostMapping(value = "/getSlowMessage") 23 String getSlowMessage(@RequestBody String message); 24 }
如果用了fallbackFactory或者fallback,这里需要注意@Primary注解要加上,不然@Autowired注入不了,因为FeignClient会根据接口生成一个代理类,而fallbackFactory或者fallback指定的类又得@Component才行,这样注入Spring会混乱,但你没法指定代理类生成的名字
7.@FeignClient中的name和url参数
8.Feign自定义拦截器
1 /** 2 * @Author DiaoJianBin 3 * @Description openFeign的拦截器,可以在请求发送前做些处理 4 * @Date 2021/3/14 16:10 5 */ 6 public class UserFeignInterceptor implements RequestInterceptor { 7 @Override 8 public void apply(RequestTemplate template) { 9 System.out.println("例如在这里添加token"); 10 template.header("token","123"); 11 } 12 }
小结
本篇博客主要讲了Feign一些注意点,正常的Feign的使用大家可以自行搜索,很简单。目前个人使用Feign主要还是系统服务的内部调用,访问第三方服务(如微信支付)往往要SSL验证等,这个时候用RestTemplate比较方便。希望能帮到大家~