自定义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

相关文章

Java中使用Java Mail实现邮件服务功能示例

《Java中使用JavaMail实现邮件服务功能示例》:本文主要介绍Java中使用JavaMail实现邮件服务功能的相关资料,文章还提供了一个发送邮件的示例代码,包括创建参数类、邮件类和执行结... 目录前言一、历史背景二编程、pom依赖三、API说明(一)Session (会话)(二)Message编程客

四种Flutter子页面向父组件传递数据的方法介绍

《四种Flutter子页面向父组件传递数据的方法介绍》在Flutter中,如果父组件需要调用子组件的方法,可以通过常用的四种方式实现,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录方法 1:使用 GlobalKey 和 State 调用子组件方法方法 2:通过回调函数(Callb

Vue项目中Element UI组件未注册的问题原因及解决方法

《Vue项目中ElementUI组件未注册的问题原因及解决方法》在Vue项目中使用ElementUI组件库时,开发者可能会遇到一些常见问题,例如组件未正确注册导致的警告或错误,本文将详细探讨这些问题... 目录引言一、问题背景1.1 错误信息分析1.2 问题原因二、解决方法2.1 全局引入 Element

Python调用另一个py文件并传递参数常见的方法及其应用场景

《Python调用另一个py文件并传递参数常见的方法及其应用场景》:本文主要介绍在Python中调用另一个py文件并传递参数的几种常见方法,包括使用import语句、exec函数、subproce... 目录前言1. 使用import语句1.1 基本用法1.2 导入特定函数1.3 处理文件路径2. 使用ex

windos server2022的配置故障转移服务的图文教程

《windosserver2022的配置故障转移服务的图文教程》本文主要介绍了windosserver2022的配置故障转移服务的图文教程,以确保服务和应用程序的连续性和可用性,文中通过图文介绍的非... 目录准备环境:步骤故障转移群集是 Windows Server 2022 中提供的一种功能,用于在多个

解决systemctl reload nginx重启Nginx服务报错:Job for nginx.service invalid问题

《解决systemctlreloadnginx重启Nginx服务报错:Jobfornginx.serviceinvalid问题》文章描述了通过`systemctlstatusnginx.se... 目录systemctl reload nginx重启Nginx服务报错:Job for nginx.javas

Idea调用WebService的关键步骤和注意事项

《Idea调用WebService的关键步骤和注意事项》:本文主要介绍如何在Idea中调用WebService,包括理解WebService的基本概念、获取WSDL文件、阅读和理解WSDL文件、选... 目录前言一、理解WebService的基本概念二、获取WSDL文件三、阅读和理解WSDL文件四、选择对接

vue解决子组件样式覆盖问题scoped deep

《vue解决子组件样式覆盖问题scopeddeep》文章主要介绍了在Vue项目中处理全局样式和局部样式的方法,包括使用scoped属性和深度选择器(/deep/)来覆盖子组件的样式,作者建议所有组件... 目录前言scoped分析deep分析使用总结所有组件必须加scoped父组件覆盖子组件使用deep前言

基于Qt Qml实现时间轴组件

《基于QtQml实现时间轴组件》时间轴组件是现代用户界面中常见的元素,用于按时间顺序展示事件,本文主要为大家详细介绍了如何使用Qml实现一个简单的时间轴组件,需要的可以参考下... 目录写在前面效果图组件概述实现细节1. 组件结构2. 属性定义3. 数据模型4. 事件项的添加和排序5. 事件项的渲染如何使用

Java调用Python代码的几种方法小结

《Java调用Python代码的几种方法小结》Python语言有丰富的系统管理、数据处理、统计类软件包,因此从java应用中调用Python代码的需求很常见、实用,本文介绍几种方法从java调用Pyt... 目录引言Java core使用ProcessBuilder使用Java脚本引擎总结引言python