feignclient各种使用技巧说明
FeignClient常见用法
常规的FeignClient的创建与使用我相信只要使用过spring cloud全家桶的套件的基本上都是非常熟悉了,我们只需定义一个interface,然后定义相关的远程接口方法签名及在方法上标记相关的请求映射的注解指明请求URL及方式,最后在该接口类上方标记@FeignClient注解,并设置相关参数即可,示例模板如下所示:
/**
* 自定义一个FeignClient标准接口类
* @author zuowenjunn.cn
*/
@FeignClient(name = "baidu",url = "http://www.baidu.com")
public interface DemoFeignClient {
@RequestMapping(value = "/s",produces ="text/html",consumes = "text/html")
String searchBaiDu(@RequestParam("wd") String wd);
}
用法就比较简单了,直接把上述标记为@FeignClient的接口类(如:DemoFeignClient)当成普通BEAN的接口进行依赖注入即可,如下示例代码:
@Autowired
private DemoFeignClient demoFeignClient;
String searchResultResp = demoFeignClient.searchBaiDu("梦在旅途");
System.out.println("searchBaiDu Result:" + searchResultResp);
注意了,如上述示例代码均只是为了便于演示而创建的,确实可以拿来(复制到JAVA的spring cloud项目中)即可执行,但实际生产项目中使用则应根据实际的微服务的名称及URL来灵活配置,具体配置与使用可参见我(梦在旅途)之前的文章:玩转Spring Cloud之服务注册发现(eureka)及负载均衡消费(ribbon、feign)
上述通过定义接口+@FeignClient注解的方式是最常见也是最简单的使用的方式,那大家知悉原理吗?其实原理我在之前文章也讲过,核心点就是:在Spring IOC容器初始化时,会通过@EnableFeignClients中的@Import(FeignClientsRegistrar.class)最终执行FeignClientsRegistrar.registerBeanDefinitions方法,把所有标记有@FeignClient注解的接口包装成FeignClientFactoryBean并注册为BEAN,当项目中实际依赖FeignClient接口类时,则会通过FeignClientFactoryBean.getObject来生成真实的FeignClient接口的实现类BEAN,详细源码解读可参见:https://blog.csdn.net/forezp/article/details/83896098 这里面最关键的其实就是FeignClientFactoryBean.getObject方法,而这个方法本质又是调getTarget方法,这个方法最终返回的就是一个Targeter接口的实现类。如果我们想动态自定义一个FeignClient接口,增加一些自定义的逻辑(比如:额外装饰一些逻辑),那么我们只需要自行创建Targeter接口的实现类即可。这种方案是可行的,而且框架也提供了这种自定义的扩展能力:Feign.Builder,Feign.Builder类就是可以实现动态构建FeignClient的利器,下面我将基于这种思路实现动态自定义构建FeignClient。
动态自定义构建FeignClient实现方式一(直接指明服务的URL地址【如果是实际项目中这应该是网关的负载均衡地址哦】)
/**
* 自定义一个FeignClient接口类,除了不用加@FeignClient注解外,其余均相同
* @author zuowenjunn.cn
*/
public interface CustomApiFeignClient {
@RequestMapping(value = "/s",produces ="text/html",consumes = "text/html")
String searchBaiDu(@RequestParam("wd") String wd);
}
/**
* 定义配置类,集中动态配置自定义的FeignClient代理类BEAN
* @author zuowenjun.cn
*/
@Configuration
@Import(FeignClientsConfiguration.class)
public class FeignClientConfig {
@Bean
public CustomApiFeignClient customApiFeignClient(Contract contract, Decoder decoder, Encoder encoder) {
return Feign.builder().contract(contract).encoder(encoder).decoder(decoder).target(CustomApiFeignClient.class, "http://www.baidu.com");
}
}
用法就比较简单了,如常规用法一样,把视为FeignClient接口(如:CustomApiFeignClient)依赖注入到相关的BEAN中即可,代码如下所示:
CustomApiFeignClient feignClient = SpringUtils.getBean(CustomApiFeignClient.class); //这里使用工具类获取BEAN,当然也可以使用@Autowired注解方式获得
String searchResultResp = feignClient.searchBaiDu("梦在旅途");
System.out.println("searchBaiDu Result:" + searchResultResp);
动态自定义构建FeignClient实现方式二(直接指明服务名,并进行装饰,支持自定义负载均衡、更换请求API的组件等功能)
/**
* 自定义一个FeignClient接口类,除了不用加@FeignClient注解外,其余均相同
* @author zuowenjunn.cn
*/
public interface CategoryTreeConfigFeignClient {
@RequestMapping(value = "/categoryTreeConfig/getCategoryInfo", method = RequestMethod.POST)
ResponseData<Object> getCategoryInfo(CategoryTreeConfigBO categoryTreeConfigBO);
}
/**
* 定义配置类,集中动态配置自定义的FeignClient代理类BEAN
* @author zuowenjun.cn
*/
@Configuration
@Import(FeignClientsConfiguration.class)
public class FeignClientConfig {
@Bean
public CustomApiFeignClient customApiFeignClient(Contract contract, Decoder decoder, Encoder encoder) {
return Feign.builder().contract(contract).encoder(encoder).decoder(decoder).target(CustomApiFeignClient.class, "http://www.baidu.com");
}
@Bean
public CategoryTreeConfigFeignClient categoryTreeConfigFeignClient(@Qualifier("feignClient") Client client, SpringClientFactory clientFactory, Contract contract, Decoder decoder, Encoder encoder) {
Client customClient = new Client.Default(null, null) {
@Override
public Response execute(Request request, Request.Options options) throws IOException {
return super.execute(request, options);
}
@Override
public HttpURLConnection getConnection(URL url) throws IOException {
String serviceName = url.getHost();
String rawUrl= url.toString();
List<Server> upServers= clientFactory.getLoadBalancer(serviceName).getReachableServers();
//TODO:自定义客户端负载均衡策略,这里只是举例选第1个
Server bestServer= upServers.stream().findFirst().orElse(null);
Assert.notNull(bestServer,serviceName +":从注册中心没有找到可用的Server实例.");
url=new URL(url.getProtocol(),bestServer.getHost(),bestServer.getPort(),url.getFile());
return super.getConnection(url);
}
};
return Feign.builder().client(customClient).contract(contract).encoder(encoder).decoder(decoder).target(CategoryTreeConfigFeignClient.class, "http://微服务名");
}
}
实际用法与上述实现方式一相同,如下:
CategoryTreeConfigFeignClient categoryTreeConfigFeignClient=SpringUtils.getBean(CategoryTreeConfigFeignClient.class);//这里使用工具类获取BEAN,当然也可以使用@Autowired注解方式获得
ResponseData<Object> responseData= categoryTreeConfigFeignClient.getCategoryInfo(new CategoryTreeConfigBO(){
{
setId("50");
setIncludeChild(0);
}
});
除了上述通过Feign.builder()的方式来直接进行额外自定义处理处,还可以在常规用法的基础上增加个性化配置的方式来实现,即:给@FeignClient注解属性configuration赋值自定义的配置类,在配置类中可以定义相关的BEAN以替换全局默认的BEAN,具体方法请参见网上的相关文章介绍。
feignclient各种使用技巧说明的更多相关文章
- 通过实现仿照FeignClient框架原理的示例来看清FeignClient的本质
前言 FeignClient的实现原理网上一搜一大把,此处我就不详细再说明,比如:Feign原理 (图解) - 疯狂创客圈 - 博客园 (cnblogs.com),而且关于FeignClient的使用 ...
- 编程小技巧之 Linux 文本处理命令
合格的程序员都善于使用工具,正所谓君子性非异也,善假于物也.合理的利用 Linux 的命令行工具,可以提高我们的工作效率. 本文简单的介绍三个能使用 Linux 文本处理命令的场景,给大家开阔一下思路 ...
- 探究javascript对象和数组的异同,及函数变量缓存技巧
javascript中最经典也最受非议的一句话就是:javascript中一切皆是对象.这篇重点要提到的,就是任何jser都不陌生的Object和Array. 有段时间曾经很诧异,到底两种数据类型用来 ...
- 前端极易被误导的css选择器权重计算及css内联样式的妙用技巧
记得大学时候,专业课的网页设计书籍里面讲过css选择器权重的计算:id是100,class是10,html标签是5等等,然后全部加起来的和进行比较... 我只想说:真是误人子弟,害人不浅! 最近,在前 ...
- 前端网络、JavaScript优化以及开发小技巧
一.网络优化 YSlow有23条规则,中文可以参考这里.这几十条规则最主要是在做消除或减少不必要的网络延迟,将需要传输的数据压缩至最少. 1)合并压缩CSS.JavaScript.图片,静态资源CDN ...
- 工欲善其事,必先利其器 之 VS2013全攻略(安装,技巧,快捷键,插件)!
如有需要WPF工具的朋友可以移步 工欲善其事,必先利其器 之 WPF篇: 随着开发轨迹来看高效WPF开发的工具和技巧 之前一篇<c++的性能, c#的产能?!鱼和熊掌可以兼得,.NET NATI ...
- 15个关于Chrome的开发必备小技巧[译]
谷歌Chrome,是当前最流行且被众多web开发人员使用的浏览器.最快六周就更新发布一次以及伴随着它不断强大的开发组件,使得Chrome成为你必备的开发工具.例如,在线编辑CSS,console以及d ...
- Git小技巧 - 指令别名及使用Beyond Compare作为差异比较工具
前言 本文主要写给使用命令行来操作Git的用户,用于提高Git使用的效率.至于使用命令还是GUI(Tortoise Git或VS的Git插件)就不在此讨论了,大家根据自己的的喜好选择就好.我个人是比较 ...
- 【工具使用】mac电脑使用技巧
本文地址 分享提纲: 1. mac命令行和finder的交互 2. 一些mac的插件 3. 一些开发的配置 1.mac命令行和findder交互 1)命令行中打开当前文件夹: o ...
随机推荐
- 12306抢票算法居然被曝光了!!!居然是redis实现的
导读 相信大家应该都有抢火车票的经验,每年年底,这都是一场盛宴.然而你有没有想过抢火车票这个算法是怎么实现的呢? 应该没有吧,咱们今天就来一一探讨.其实并没有你想的那么难 bitmap与位运算 red ...
- ElasticSearch搜索引擎
官网:Elasticsearch:官方分布式搜索和分析引擎 | Elastic Elaticsearch,简称为es,es是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储.检索数据;本身扩 ...
- IP多播与NAT地址转化
IP多播 与单播相比,在一对多的通信中,多播可以大大减少网络资源.在互联网上进行多播就叫做IP多播,IP多播所传送的分组需要使用IP多播地址. 如果某台主机想要收到某个特定的多播分组,那么怎样才能是这 ...
- 踩坑系列《十一》完美解决阿里云vod视频点播无法播放音频和视频点播控制台里的媒资库里面的视频无法播放
刚开始项目部署的时候,音频还是正常播放,后面直接报了 获取m3u8文件失败(manifestLoadError) 的错误,原因是 我的域名 xxx.com 这个域名没有解析到点播提供的CNAME上,所 ...
- 当一个 Pod 被调度时,Kubernetes 内部发生了什么?
在 Kubernetes 中,调度是指将 Pod 放置到合适的 Node 上,然后对应 Node 上的 Kubelet 才能够运行这些 Pod . kube-scheduler 是集群控制平面的主要组 ...
- golang引用第三方包的报错:no required module provides package [完美解决]
关于golang第三方包的引用报错:no required module provides package : go.mod file not found in current directory o ...
- Java(8)详解Random使用
作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201556.html 博客主页:https://www.cnblogs.com/testero ...
- ThreadLocalRandom类原理分析
1.Random类及其局限性 public int nextInt(int bound) { if (bound <= 0) throw new IllegalArgumentException ...
- Django Model字段加密的优雅实现
早前的一篇文章Django开发密码管理表实例有写我们写了个密码管理工具来实现对密码的管理,当时加密解密的功能在view层实现,一直运行稳定所以也没有过多关注实现是否优雅的问题.最近要多加几个密码表再次 ...
- 【UE4 C++】碰撞检测与事件绑定
概念 碰撞对象通道与预设 默认提供碰撞对象类型,如 WorldStatic.WorldDynamic等.允许用户自定义 默认提供碰撞预设,如 NoCollision.BloackAll.Overlap ...