自定义BeanPostProcessor之Feign组件服务间优雅调用

2023-12-07 08:44

本文主要是介绍自定义BeanPostProcessor之Feign组件服务间优雅调用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Feign是什么

feign是声明式的web service客户端,它让微服务之间的调用变得更简单了,类似controller调用service。Spring Cloud集成了Ribbon和Eureka,可在使用Feign时提供负载均衡的http客户端。

Feign怎么使用

@FeignClient(value = "service-name")
public interface CartFeignClient {@PostMapping("/cart/{productId}")Long addCart(@PathVariable("productId")Long productId);
}

上面是最简单的feign client的使用,声明完为feign client后,其他spring管理的类,如service就可以直接注入使用了,例如:

//这里直接注入feign client
@Autowired
private CartFeignClient cartFeignClient;@PostMapping("/toCart/{productId}")
public ResponseEntity addCart(@PathVariable("productId") Long productId){Long result = cartFeignClient.addCart(productId);return ResponseEntity.ok(result);
}

可以看到,使用feign之后,我们调用eureka 注册的其他服务,在代码中就像各个service之间相互调用那么简单。

常规Feign服务间调用

在本地研发环境开发时候可能需要调用其他服务,例如通过service-name的方式调用,但是如果经过注册中心,并且服务有多实例的情况下会出现超时的情况。可以通过指定服务ip的方式调用。

@FeignClient(value="service-name", url = "http://127.0.0.1:2607/")@FeignClient(value="service-name-1", url = "http://1.2.3.4:2607/")

Feign服务间调用更容易

如果引用的其他服务比较多,需要修改很多的url,这样比较浪费时间,通过重写@FeignClient的url,可进行统一处理,而不用一个一个的去修改。也可以配置研发环境,本地环境等多个环境的服务地址。
具体的实现方式是通过自定义BeanPostProcessor的方式,在bean初始化的时候动态替换。
BeanPostProcessor的原理可以看spring相关文章。

@Component
public class FeignClientsServiceNameAppendBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {private ApplicationContext applicationContext;private AtomicInteger atomicInteger = new AtomicInteger();// 需要替换的服务名称和ip集合public static final Map<String, String> SERVICE_MAP = new HashMap<>();private static String beanNameOfFeignClientFactoryBean = "org.springframework.cloud.netflix.feign.FeignClientFactoryBean";static {SERVICE_MAP.put("service-name", "http://127.0.0.1:2607");SERVICE_MAP.put("service-name-1", "http://1.2.3.4:8081");}@Overridepublic Object postProcessBeforeInitialization(Object bean, String s) throws BeansException {return bean;}@SneakyThrows@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (atomicInteger.getAndIncrement() == 0) {Class beanNameClz = Class.forName(beanNameOfFeignClientFactoryBean);applicationContext.getBeansOfType(beanNameClz).forEach((feignBeanName, beanOfFeignClientFactoryBean) -> {try {setField(beanNameClz, "url", beanOfFeignClientFactoryBean);} catch (Exception e) {e.printStackTrace();}System.out.println(feignBeanName + "-->" + beanOfFeignClientFactoryBean);});}return bean;}private void setField(Class clazz,  Object obj) throws Exception {// 获取FeignClientFactoryBean的name属性,找到服务名称。例如:service-name-1Field name = ReflectionUtils.findField(clazz, "name");Object nameValue = null;if (Objects.nonNull(name)) {ReflectionUtils.makeAccessible(name);nameValue = name.get(obj);}// 获取FeignClientFactoryBean的url字段Field field = ReflectionUtils.findField(clazz, "url");if (Objects.nonNull(field) && Objects.nonNull(nameValue)) {ReflectionUtils.makeAccessible(field);Object value = field.get(obj);// 找到指定配置替换url的值if (Objects.nonNull(value) && SERVICE_MAP.containsKey(nameValue)) {value = SERVICE_MAP.get(nameValue);ReflectionUtils.setField(field, obj, value);}}}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}

这篇关于自定义BeanPostProcessor之Feign组件服务间优雅调用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/465228

相关文章

关于DNS域名解析服务

《关于DNS域名解析服务》:本文主要介绍关于DNS域名解析服务,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录DNS系统的作用及类型DNS使用的协议及端口号DNS系统的分布式数据结构DNS的分布式互联网解析库域名体系结构两种查询方式DNS服务器类型统计构建DNS域

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

Linux中SSH服务配置的全面指南

《Linux中SSH服务配置的全面指南》作为网络安全工程师,SSH(SecureShell)服务的安全配置是我们日常工作中不可忽视的重要环节,本文将从基础配置到高级安全加固,全面解析SSH服务的各项参... 目录概述基础配置详解端口与监听设置主机密钥配置认证机制强化禁用密码认证禁止root直接登录实现双因素

java向微信服务号发送消息的完整步骤实例

《java向微信服务号发送消息的完整步骤实例》:本文主要介绍java向微信服务号发送消息的相关资料,包括申请测试号获取appID/appsecret、关注公众号获取openID、配置消息模板及代码... 目录步骤1. 申请测试系统2. 公众号账号信息3. 关注测试号二维码4. 消息模板接口5. Java测试

Python中Tensorflow无法调用GPU问题的解决方法

《Python中Tensorflow无法调用GPU问题的解决方法》文章详解如何解决TensorFlow在Windows无法识别GPU的问题,需降级至2.10版本,安装匹配CUDA11.2和cuDNN... 当用以下代码查看GPU数量时,gpuspython返回的是一个空列表,说明tensorflow没有找到

Java实现自定义table宽高的示例代码

《Java实现自定义table宽高的示例代码》在桌面应用、管理系统乃至报表工具中,表格(JTable)作为最常用的数据展示组件,不仅承载对数据的增删改查,还需要配合布局与视觉需求,而JavaSwing... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

一文详解Java Stream的sorted自定义排序

《一文详解JavaStream的sorted自定义排序》Javastream中的sorted方法是用于对流中的元素进行排序的方法,它可以接受一个comparator参数,用于指定排序规则,sorte... 目录一、sorted 操作的基础原理二、自定义排序的实现方式1. Comparator 接口的 Lam

python如何调用java的jar包

《python如何调用java的jar包》这篇文章主要为大家详细介绍了python如何调用java的jar包,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以参考一下... 目录一、安装包二、使用步骤三、代码演示四、自己写一个jar包五、打包步骤六、方法补充一、安装包pip3 install

SpringBoot服务获取Pod当前IP的两种方案

《SpringBoot服务获取Pod当前IP的两种方案》在Kubernetes集群中,SpringBoot服务获取Pod当前IP的方案主要有两种,通过环境变量注入或通过Java代码动态获取网络接口IP... 目录方案一:通过 Kubernetes Downward API 注入环境变量原理步骤方案二:通过

如何自定义一个log适配器starter

《如何自定义一个log适配器starter》:本文主要介绍如何自定义一个log适配器starter的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录需求Starter 项目目录结构pom.XML 配置LogInitializer实现MDCInterceptor