springcloud==openfeign+springboot仿照openfeign自定义注解和使用

我的目的是参照原本openfeign的注解,但是我想实现每个外部服务的URL可以自己指定生成的规则。

自定义EnableMyFeignClients

自定义MyImportBeanDefinitionRegistrar,更改获取URL的逻辑。这个应该是个可行的方式,但是RIBBON的视线方式应该会更好之后再看。

                //TODO modify here to set the rule to get the url
            factoryBean.setUrl(getUrl(beanFactory, attributes));

自定义MyFeignClient

package com.example.demospringboot3.FactoryBean;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;import org.springframework.context.annotation.Import;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MyImportBeanDefinitionRegistrar.class)
public @interface EnableMyFeignClients {String[] value() default {};String[] basePackages() default {};Class<?>[] basePackageClasses() default {};Class<?>[] defaultConfiguration() default {};Class<?>[] clients() default {};}
package com.example.demospringboot3.FactoryBean;import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.config.*;
import org.springframework.beans.factory.support.*;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.FeignClientFactoryBean;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;//注意这里不能加注解,要通过Import导入进去。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {registerFeignClients(metadata, registry);通过工具类生成一个bd,只是这个Db对象比较纯洁没有绑定任何类//BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition();为什么要转成GenericBeanDefinition这种类型。因为GenericBeanDefinition有更多修改bd属性的方法。后面我会介绍为什么要修改属性。//GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanDefinitionBuilder.getBeanDefinition();//这里很重要。getConstructorArgumentValues是为了获取该bd的所有构造方法,因为我们重写了有参构造方法,所有我们需要带参数过去不然spring没法帮我们实例化,addGenericArgumentValue是添加参数,该代码会执行两步第一步是匹配对应的构造方法,第二步是实例化。//beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(UserServiceTestInterface.class.getName());因为代理对象类型的,实例化的时候走的是代理类的构造方法//beanDefinition.setBeanClass(MyFactoryBean.class);注册bd//registry.registerBeanDefinition("userServiceTest", beanDefinition);}private void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {//扫描指定的包下,包含MyFeignClient注解的接口LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableMyFeignClients.class.getName());final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients");if (clients == null || clients.length == 0) {ClassPathScanningCandidateComponentProvider scanner = getScanner();scanner.setResourceLoader(this.resourceLoader);scanner.addIncludeFilter(new AnnotationTypeFilter(MyFeignClient.class));Set<String> basePackages = getBasePackages(metadata);for (String basePackage : basePackages) {candidateComponents.addAll(scanner.findCandidateComponents(basePackage));}} else {for (Class<?> clazz : clients) {candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz));}}for (BeanDefinition candidateComponent : candidateComponents) {if (candidateComponent instanceof AnnotatedBeanDefinition) {//获取包含MyFeignClient注解的接口 的各项参数AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface");Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(MyFeignClient.class.getCanonicalName());String name = getClientName(attributes);registerFeignClient(registry, annotationMetadata, attributes);}}}private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata,Map<String, Object> attributes) {String className = annotationMetadata.getClassName();Class clazz = ClassUtils.resolveClassName(className, null);ConfigurableBeanFactory beanFactory = registry instanceof ConfigurableBeanFactory? (ConfigurableBeanFactory) registry : null;String contextId = getContextId(beanFactory, attributes);String name = getName(attributes);FeignClientFactoryBean factoryBean = new FeignClientFactoryBean();factoryBean.setBeanFactory(beanFactory);factoryBean.setName(name);factoryBean.setContextId(contextId);factoryBean.setType(clazz);factoryBean.setRefreshableClient(Boolean.FALSE);BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> {//TODO modify here to set the rule to get the urlfactoryBean.setUrl(getUrl(beanFactory, attributes));factoryBean.setPath(getPath(beanFactory, attributes));factoryBean.setDecode404(Boolean.parseBoolean(String.valueOf(attributes.get("decode404"))));Object fallback = attributes.get("fallback");if (fallback != null) {factoryBean.setFallback(fallback instanceof Class ? (Class<?>) fallback: ClassUtils.resolveClassName(fallback.toString(), null));}Object fallbackFactory = attributes.get("fallbackFactory");if (fallbackFactory != null) {factoryBean.setFallbackFactory(fallbackFactory instanceof Class ? (Class<?>) fallbackFactory: ClassUtils.resolveClassName(fallbackFactory.toString(), null));}return factoryBean.getObject();});definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);definition.setLazyInit(true);//validate(attributes);AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);beanDefinition.setAttribute("feignClientsRegistrarFactoryBean", factoryBean);// has a default, won't be nullboolean primary = (Boolean) attributes.get("primary");beanDefinition.setPrimary(primary);String[] qualifiers = getQualifiers(attributes);if (ObjectUtils.isEmpty(qualifiers)) {qualifiers = new String[]{contextId + "FeignClient"};}BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers);BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);//registerOptionsBeanDefinition(registry, contextId);}private String[] getQualifiers(Map<String, Object> client) {if (client == null) {return null;}List<String> qualifierList = new ArrayList<>(Arrays.asList((String[]) client.get("qualifiers")));qualifierList.removeIf(qualifier -> !StringUtils.hasText(qualifier));if (qualifierList.isEmpty() && getQualifier(client) != null) {qualifierList = Collections.singletonList(getQualifier(client));}return !qualifierList.isEmpty() ? qualifierList.toArray(new String[0]) : null;}private String getQualifier(Map<String, Object> client) {if (client == null) {return null;}String qualifier = (String) client.get("qualifier");if (StringUtils.hasText(qualifier)) {return qualifier;}return null;}private String getUrl(ConfigurableBeanFactory beanFactory, Map<String, Object> attributes) {String url = resolve(beanFactory, (String) attributes.get("url"));return getUrl(url);}private String getPath(ConfigurableBeanFactory beanFactory, Map<String, Object> attributes) {String path = resolve(beanFactory, (String) attributes.get("path"));return getPath(path);}static String getName(String name) {if (!StringUtils.hasText(name)) {return "";}String host = null;try {String url;if (!name.startsWith("http://") && !name.startsWith("https://")) {url = "http://" + name;} else {url = name;}host = new URI(url).getHost();} catch (URISyntaxException e) {}Assert.state(host != null, "Service id not legal hostname (" + name + ")");return name;}static String getUrl(String url) {if (StringUtils.hasText(url) && !(url.startsWith("#{") && url.contains("}"))) {if (!url.contains("://")) {url = "http://" + url;}try {new URL(url);} catch (MalformedURLException e) {throw new IllegalArgumentException(url + " is malformed", e);}}return url;}static String getPath(String path) {if (StringUtils.hasText(path)) {path = path.trim();if (!path.startsWith("/")) {path = "/" + path;}if (path.endsWith("/")) {path = path.substring(0, path.length() - 1);}}return path;}private String getContextId(ConfigurableBeanFactory beanFactory, Map<String, Object> attributes) {String contextId = (String) attributes.get("contextId");if (!StringUtils.hasText(contextId)) {return getName(attributes);}contextId = resolve(beanFactory, contextId);return getName(contextId);}/* for testing */ String getName(Map<String, Object> attributes) {return getName(null, attributes);}String getName(ConfigurableBeanFactory beanFactory, Map<String, Object> attributes) {String name = (String) attributes.get("serviceId");if (!StringUtils.hasText(name)) {name = (String) attributes.get("name");}if (!StringUtils.hasText(name)) {name = (String) attributes.get("value");}name = resolve(beanFactory, name);return getName(name);}private String resolve(ConfigurableBeanFactory beanFactory, String value) {if (StringUtils.hasText(value)) {if (beanFactory == null) {return this.environment.resolvePlaceholders(value);}BeanExpressionResolver resolver = beanFactory.getBeanExpressionResolver();String resolved = beanFactory.resolveEmbeddedValue(value);if (resolver == null) {return resolved;}Object evaluateValue = resolver.evaluate(resolved, new BeanExpressionContext(beanFactory, null));if (evaluateValue != null) {return String.valueOf(evaluateValue);}return null;}return value;}private String getClientName(Map<String, Object> client) {if (client == null) {return null;}String value = (String) client.get("contextId");if (!StringUtils.hasText(value)) {value = (String) client.get("value");}if (!StringUtils.hasText(value)) {value = (String) client.get("name");}if (!StringUtils.hasText(value)) {value = (String) client.get("serviceId");}if (StringUtils.hasText(value)) {return value;}throw new IllegalStateException("Either 'name' or 'value' must be provided in @" + FeignClient.class.getSimpleName());}private Environment environment;private ResourceLoader resourceLoader;@Overridepublic void setEnvironment(Environment environment) {this.environment = environment;}@Overridepublic void setResourceLoader(ResourceLoader resourceLoader) {this.resourceLoader = resourceLoader;}protected Set<String> getBasePackages(AnnotationMetadata importingClassMetadata) {Map<String, Object> attributes = importingClassMetadata.getAnnotationAttributes(EnableFeignClients.class.getCanonicalName());Set<String> basePackages = new HashSet<>();for (String pkg : (String[]) attributes.get("value")) {if (StringUtils.hasText(pkg)) {basePackages.add(pkg);}}for (String pkg : (String[]) attributes.get("basePackages")) {if (StringUtils.hasText(pkg)) {basePackages.add(pkg);}}for (Class<?> clazz : (Class[]) attributes.get("basePackageClasses")) {basePackages.add(ClassUtils.getPackageName(clazz));}if (basePackages.isEmpty()) {basePackages.add(ClassUtils.getPackageName(importingClassMetadata.getClassName()));}return basePackages;}protected ClassPathScanningCandidateComponentProvider getScanner() {return new ClassPathScanningCandidateComponentProvider(false, this.environment) {@Overrideprotected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {boolean isCandidate = false;if (beanDefinition.getMetadata().isIndependent()) {if (!beanDefinition.getMetadata().isAnnotation()) {isCandidate = true;}}return isCandidate;}};}
}

package com.example.demospringboot3.FactoryBean;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;import org.springframework.core.annotation.AliasFor;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyFeignClient {@AliasFor("name")String value() default "";String contextId() default "";@AliasFor("value")String name() default "";@DeprecatedString qualifier() default "";String[] qualifiers() default {};String url() default "";/*** @return whether 404s should be decoded instead of throwing FeignExceptions*/boolean decode404() default false;Class<?>[] configuration() default {};Class<?> fallback() default void.class;Class<?> fallbackFactory() default void.class;String path() default "";boolean primary() default true;}

使用

启动类加上

@EnableMyFeignClients(basePackages = {"com.example"})

package com.example.demospringboot3.openfeign;import com.example.demospringboot3.FactoryBean.MyFeignClient;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;@MyFeignClient(name = "baiduMyFeignClient", url = "http://127.0.0.1:8888")
public interface BaiduMyFeignClient {@RequestMapping("/test")void getMy1();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/791618.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LangChain入门:11.Pydantic(JSON)解析器实战

摘要 在数字化营销的浪潮中&#xff0c;自动化内容生成成为了提升效率和用户参与度的利器。本文将详细介绍如何利用LangChain的自然语言处理能力和Pydantic的数据验证特性&#xff0c;构建一个自动化的花店文案生成器。通过这个工具&#xff0c;您可以快速为各种花卉生成吸引人…

Gateway是什么?(SpringCloudAlibaba组件)

1、网关介绍 **网关(Gateway)又称网间连接器、协议转换器。网关在传输层上以实现网络互连&#xff0c;是最复杂的网络互连设备&#xff0c;仅用于两个高层协议不同的网络互连。**网关的结构也和路由器类似&#xff0c;不同的是互连层。网关既可以用于广域网互连&#xff0c;也可…

截稿倒计时 CCF-B COCOON’24论文延期至4月8日提交

会议之眼 快讯 第30届COCOON 2024 (International Computing and Combinatorics Conference)即国际计算与组合学会议将于 2024 年 8月23日-25日在中国上海举行&#xff01;COCOON是一个专注于计算机科学理论领域的国际性学术会议&#xff01;COCOON会议自1995年起举办&#xf…

Promise-以往的异步编程模式

要理解这个 double 函数在调度异步操作后为什么会立即退出&#xff0c;我们可以一步一步拆解它的执行流程。 首先&#xff0c;看一下 double 函数的定义&#xff1a; function double(value) {setTimeout(() > setTimeout(console.log, 0, value * 2), 1000); }当你调用 d…

JDK下载安装配置

一.JDK安装配置。 1.安装注意路径,其他直接下一步。 2.配置。 下接第4步. 代码复制: JAVA_HOME D:\Program Files\Java\jdk1.8.0_91 D:\Program Files\Java\jdk1.8.0_91\bin 3.验证(CMD)。 java javac java -version 二.下载 1.下载JDK1.5-1.9(所有版本)下载: https://www.…

docker环境中宿主机防火墙添加ssh无法生效的问题分析

背景 在部署了docker容器的环境中&#xff0c;要在防火墙开通22端口&#xff0c;即ssh服务&#xff0c;以便在终端可以正常登陆。使用firewall-cmd在docker区域添加了22端口&#xff0c;但是没有起作用。后再public区域添加22端口才起作用。为什么docker区域不起作用&#xff…

使用vuepress搭建个人的博客(一):基础构建

前言 vuepress是一个构建静态资源网站的库 地址:VuePress 一般来说,这个框架非常适合构建个人技术博客,你只需要把自己写好的markdown文档准备好,完成对应的配置就可以了 搭建 初始化和引入 创建文件夹press-blog npm初始化 npm init 引入包 npm install -D vuepress…

蓝桥杯_数学模板

1.试除法判定质数 #include <iostream> using namespace std;bool is_zs(int x) {if(x<2) return false;for(int i2;i<x/i;i)if(x%i0)return false;return true; }int main() {int n; cin>>n;while(n--){int x; cin>>x;if(is_zs(x)) cout<<&quo…

windows下安装iteliij Idea2023.3

首先从官网下载 下载 IntelliJ IDEA – 领先的 Java 和 Kotlin IDE 双击打开进行安装&#xff1a; 安装完成后&#xff0c;需要对Idea进行稍微处理下。使用我分享给大家的文件&#xff0c;操作以下步骤&#xff1a; 注意&#xff1a;不能打开IDEA软件。 进入到scripts中点击un…

C语言存储⽅式有哪⼏种?分别是什么?

一、问题 什么叫存储⽅式&#xff1f;存储⽅式有⼏种&#xff1f;分别是什么&#xff1f; 二、解答 因变量存储⽅式不同⽽产⽣的特性称作变量的⽣存期。⽣存期表示了变量存在的时间。⽣存期加上前⾯讲过的作⽤域是从时间和空间这两个不同的⻆度来描述变量的特性&#xff0c; 这…

[技术闲聊]我对电路设计的理解(一)

讲点题外话&#xff0c;也算回忆&#xff0c;捋一捋过往的生活。 大学毕业后&#xff0c;进入公司实习&#xff0c;从产线开始&#xff0c;为期一个月&#xff0c;当时课室负责人说&#xff0c;进入一家公司&#xff0c;首先了解公司的产品&#xff0c;产线是最直接最合适最近距…

独孤思维:高客单价项目,必须来一个

01 上次和水龙聊完以后&#xff0c;完成了图书电商项目小报童的梳理。 而且还让我规划后端低转高产品的设计。 目前独孤&#xff0c;准备以图书电商项目私教作为切入点&#xff0c;捆绑自己的合伙人。 设计高客单价项目。 所以&#xff0c;独孤4月的副业规划目标&#xff…

AI绘图:Stable Diffusion WEB UI 详细操作介绍:基础篇

接上一篇《AI绘图体验&#xff1a;Stable Diffusion本地化部署详细步骤》本地部署完了SD后&#xff0c;大家肯定想知道怎么用&#xff0c;接下来补一篇Stable Diffusion WEB UI 详细操作&#xff0c;如果大家还没有完成SD的部署&#xff0c;请参考上一篇文章进行本地化的部署。…

2.2.1.2-网格交易(python网格交易附实战交易记录)

跳转到根目录&#xff1a;知行合一&#xff1a;投资篇 已完成&#xff1a; 1、投资&技术   1.1.1 投资-编程基础-numpy   1.1.2 投资-编程基础-pandas   1.2 金融数据处理   1.3 金融数据可视化 2、投资方法论   2.1.1 预期年化收益率   2.1.2 一个关于yaxb的…

C++之STL的algorithm(4)之拷贝相关算法(copy、replace、swap)整理

C之STL的algorithm&#xff08;4&#xff09;之拷贝相关算法&#xff08;copy、replace、swap&#xff09;整理 注&#xff1a;整理一些突然学到的C知识&#xff0c;随时mark一下 例如&#xff1a;忘记的关键字用法&#xff0c;新关键字&#xff0c;新数据结构 C 的查找算法整理…

多线程--深入探究多线程的重点,难点以及常考点线程安全问题

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…

Redis高可用主从复制与哨兵模式

前言 在生产环境中&#xff0c;除了采用持久化方式实现 Redis 的高可用性&#xff0c;还可以采用主从复制、哨兵模式和 Cluster 集群的方法确保数据的持久性和可靠性。 目录 一、主从复制 1. 概述 2. 作用 3. 主从复制流程 4. 部署 4.1 安装 redis 4.2 编辑 master 节…

物联网实战--入门篇之(七)嵌入式-MQTT

目录 一、MQTT简介 二、MQTT使用方法 三、MQTT驱动设计 四、代码解析 五、使用过程 六、总结 一、MQTT简介 MQTT因为其轻量、高效和稳定的特点&#xff0c;特别适合作为物联网系统的数据传输协议&#xff0c;已经成为物联网事实上的通信标准了。关于协议的具体内容看看这…

后端前行Vue之路(三):计算属性和监视属性

1.概述 书接上回&#xff0c;我们讲述了《后端前行Vue之路(二)&#xff1a;模版语法之插值与指令》谈到了Vue的模板语法很强大&#xff0c;支持复杂表达式&#xff0c;如下&#xff1a; <div id"example">{{ message.split().reverse().join() }} </div&g…

Supervised Fine-tuning in turn Improves Visual Foundation Models

简介 从NLP中的监督微调&#xff08;Supervised Fine-tuning&#xff09;获得的灵感&#xff0c;本文探索了细粒度SFT在预训练后增强视觉基础模型潜力。本文提出了一种二阶段方法ViSFT释放视觉基础模型细粒度知识。具体地&#xff0c;通过一些域内任务执行视觉联合学习增强视觉…