为什么添加了@EnableDiscoveryClient注解就可以实现服务注册

添加了nacos的maven依赖之后,只需要在启动类上加一个@EnableDiscoveryClient注解就可以实现服务注册,这个注解为什么可以实现?

@EnableDiscoveryClient注解

进去到@EnableDiscoveryClient注解之后,只有简单的几行代码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {boolean autoRegister() default true;}

在这里,唯一特殊的地方就是@Import(EnableDiscoveryClientImportSelector.class)这个注解,但是这个@Import注解又是起什么作用的?

@Import注解的作用

我实际操作下来,感觉@Import注解的作用其实和@Configuration注解,@Component等注解的作用差不多,都是将当前类交给Spring容器管理。

创建的测试类如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Import(TwoModuleClientImportSelect.class)
public @interface StartImport {boolean registerOther() default true;
}
public abstract class AbsTwoModuleFactoryImportSelector<T> implements ImportSelector {private Class<T> annotationClass;protected AbsTwoModuleFactoryImportSelector() {this.annotationClass = (Class<T>) GenericTypeResolver.resolveTypeArgument(this.getClass(), AbsTwoModuleFactoryImportSelector.class);}@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(this.annotationClass.getName(), true));return new String[0];}protected Class<T> getAnnotationClass() {return this.annotationClass;}
}
@Slf4j
public class TwoModuleClientImportSelect extends AbsTwoModuleFactoryImportSelector<StartImport> {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {String[] imports = super.selectImports(importingClassMetadata);AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(getAnnotationClass().getName(), true));Boolean auto = attributes.getBoolean("registerOther");if (auto) {List<String> addStr = new ArrayList<>(Arrays.asList(imports));addStr.add("com.zhuruilin.sample.testImport.TwoModuleOtherConfiguration");imports = addStr.toArray(new String[0]);}return imports;}
}
@Configuration(proxyBeanMethods = false)
@Slf4j
public class TwoModuleOtherConfiguration {@PostConstructpublic void testImport() {log.info("TwoModuleOtherConfiguration  使用   @PostConstruct 注解的地方");}
}

总共新建了四个类:

  • @StartImport 注解
  • 抽象类AbsTwoModuleFactoryImportSelector,实现了ImportSelector接口,并且使用了泛型
  • TwoModuleClientImportSelect继承了上面的抽象类,并且指定泛型为StartImport注解
  • TwoModuleOtherConfiguration配置类,在TwoModuleClientImportSelect中有使用到这个类的包路径。

操作如下:

  • 在启动类中不加@StartImport 注解,启动会打印 log.info(“TwoModuleOtherConfiguration 使用 @PostConstruct 注解的地方”)
  • TwoModuleOtherConfiguration 类中去掉@Configuration注解,在启动类中加上@StartImport ,还是会打印日志。
  • 去掉@Configuration注解,启动类中去掉@StartImport注解,不会打印日志
  • 加上@Configuration注解和@StartImport注解,会打印日志。

可以看出其实@Import的注解的作用就是将类交给spring容器管理,好处就是不用修改使用类的代码;如果需要将第三方jar包类的一个类可以直接使用@Autowired注解,那就可以在@Import注解中指定这个类,而不需要在jar包里加上@Component类似的注解。

@Import注解有三种使用方式,也可以直接指定一个类:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Import({TwoModuleClientImportSelect.class, TwoModuleDirectBean.class})
public @interface StartImport {boolean registerOther() default true;}

这里TwoModuleDirectBean类就是直接指定的,TwoModuleClientImportSelect则是使用实现ImportSelector接口的方式来,第三种方式可以通过实现ImportBeanDefinitionRegistrar 接口的方式来实现。

public class TwoModuleThirdWay implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {RootBeanDefinition rbd = new RootBeanDefinition(TwoModuleOtherConfiguration.class);registry.registerBeanDefinition("rootBeanDefinition", rbd);}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
//@Import({TwoModuleClientImportSelect.class, TwoModuleDirectBean.class, TwoModuleThirdWay.class})
@Import({TwoModuleDirectBean.class, TwoModuleThirdWay.class})
public @interface StartImport {boolean registerOther() default true;}

启动项目之后也是可以看到打印日志的,后两种感觉都是间接的方式来创建的。

EnableDiscoveryClientImportSelector类

EnableDiscoveryClientImportSelector类也是通过实现了ImportSelector接口的方式来管理AutoServiceRegistrationConfiguration类的,只不过中间又加了两层。

新建测试工程,并且加上nacos依赖,加上@EnableDiscoveryClient注解,在EnableDiscoveryClientImportSelector类中开始debug。运行到最后可以发现,最终返回的imports数组就只有一个元素,就是只有org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration。

spring.factories

在spring-cloud-starter-alibaba-nacos-discovery这个项目中就用到了spring.factories,具体内容如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration,\com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration,\com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration,\com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,\com.alibaba.cloud.nacos.discovery.reactive.NacosReactiveDiscoveryClientConfiguration,\com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration,\com.alibaba.cloud.nacos.loadbalancer.LoadBalancerNacosAutoConfiguration,\com.alibaba.cloud.nacos.NacosServiceAutoConfigurationorg.springframework.cloud.bootstrap.BootstrapConfiguration=\com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfigurationorg.springframework.context.ApplicationListener=\com.alibaba.cloud.nacos.discovery.logging.NacosLoggingListener

这里先看服务注册相关的,先关注 org.springframework.boot.autoconfigure.EnableAutoConfiguration 这个配置项的,这个配置项后面跟了一大堆nacos的对象,作用是在项目启动的时候,会扫描spring.factories文件,并且加载这些对象到容器中,从而实现了自定义的自动配置。
这里查看NacosServiceRegistryAutoConfiguration类,点进去可以看到:

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",matchIfMissing = true)
@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,AutoServiceRegistrationAutoConfiguration.class,NacosDiscoveryAutoConfiguration.class })
public class NacosServiceRegistryAutoConfiguration {@Beanpublic NacosServiceRegistry nacosServiceRegistry(NacosServiceManager nacosServiceManager,NacosDiscoveryProperties nacosDiscoveryProperties) {return new NacosServiceRegistry(nacosServiceManager, nacosDiscoveryProperties);}@Bean@ConditionalOnBean(AutoServiceRegistrationProperties.class)public NacosRegistration nacosRegistration(ObjectProvider<List<NacosRegistrationCustomizer>> registrationCustomizers,NacosDiscoveryProperties nacosDiscoveryProperties,ApplicationContext context) {return new NacosRegistration(registrationCustomizers.getIfAvailable(),nacosDiscoveryProperties, context);}@Bean@ConditionalOnBean(AutoServiceRegistrationProperties.class)public NacosAutoServiceRegistration nacosAutoServiceRegistration(NacosServiceRegistry registry,AutoServiceRegistrationProperties autoServiceRegistrationProperties,NacosRegistration registration) {return new NacosAutoServiceRegistration(registry,autoServiceRegistrationProperties, registration);}}

spring.factories的作用就是将当前项目的对象可以交给外部项目使用,就是A项目中包含B项目,但是B项目中的类不会被A项目管理,哪怕加上了@Configuration注解,但是在A项目中也是无法发现的,这个时候就可以在B项目中的spring.factories指定一些类,这些类就可以在A项目中使用@AutoWired注解来使用了。

并且在B类中spring.factories中加载的类,如果这个类中还使用了@Bean注解的方式来创建bean,在A项目中也是可以使用的。

@Configuration(proxyBeanMethods = false)

proxyBeanMethods的作用:

首先引出两个概念:Full 全模式,Lite 轻量级模式
Full(proxyBeanMethods = true) :proxyBeanMethods参数设置为true时即为:Full 全模式。 该模式下注入容器中的同一个组件无论被取出多少次都是同一个bean实例,即单实例对象,在该模式下SpringBoot每次启动都会判断检查容器中是否存在该组件
Lite(proxyBeanMethods = false) :proxyBeanMethods参数设置为false时即为:Lite 轻量级模式。该模式下注入容器中的同一个组件无论被取出多少次都是不同的bean实例,即多实例对象,在该模式下SpringBoot每次启动会跳过检查容器中是否存在该组件
什么时候用Full全模式,什么时候用Lite轻量级模式?
当在你的同一个Configuration配置类中,注入到容器中的bean实例之间有依赖关系时,建议使用Full全模式
当在你的同一个Configuration配置类中,注入到容器中的bean实例之间没有依赖关系时,建议使用Lite轻量级模式,以提高springboot的启动速度和性能

@EnableConfigurationProperties

这个注解的作用是将使用了@ConfigurationProperties(prefix = “xx”)注解的类创建对象;也就是如果在A类上加上了@ConfigurationProperties注解,B类上只有@Configuration注解,并没有在B类上加上@EnableConfigurationProperties(A.class)注解,那么这个时候其实还是不能用A类对象的,因为并没有将A类创建。解决的办法可以是直接在A类上加上@Component类似的注解;也可以在加了@Configuration类似的注解类上,比如B类中,再加上@EnableConfigurationProperties(A.class)注解,也可以实现一样的效果。

但是在NacosServiceRegistryAutoConfiguration类上,可以看见并没有指定类名,刚开始我也这么干的,但是启动会报错(因为我有直接使用@Autowired来注入A对象的代码),提示找不到这个A类。之后我就发现在@AutoConfigureAfter注解中的AutoServiceRegistrationConfiguration类上,有了@EnableConfigurationProperties(AutoServiceRegistrationProperties.class)的注解,所以在NacosServiceRegistryAutoConfiguration类中可以使用AutoServiceRegistrationProperties配置类;

NacosServiceRegistryAutoConfiguration

在NacosServiceRegistryAutoConfiguration类中,使用@Bean创建来了三个bean对象,一个是NacosServiceRegistry,一个是NacosRegistration,还有一个是NacosAutoServiceRegistration;并且可以看到第三个bean创建的方法参数,就用到了前两个bean对象。

NacosServiceRegistryAutoConfiguration类实现了抽象类AbstractAutoServiceRegistration(后面为了省事就叫自动注册抽象类),而这个自动注册抽象类又实现了AutoServiceRegistration, ApplicationContextAware, ApplicationListener< WebServerInitializedEvent >接口。

  • AutoServiceRegistration: 这个类就是NacosServiceRegistryAutoConfiguration和自动注册抽象类的顶级接口
  • ApplicationContextAware: 实现了这个接口,就可以取到所有创建的bean对象。
  • ApplicationListener< WebServerInitializedEvent >: 监听web 容器启动事件,启动默认内置容器tomcat的时候会触发监听器的onApplicationEvent方法。

在创建NacosAutoServiceRegistration对象的时候,有使用到了NacosServiceRegistry这个对象,这个对象实现了ServiceRegistry接口,这个接口是spring.cloud开放的,如果是用eureka的,也会有一个类去实现这个接口。只要看NacosServiceRegistry中的register(Registration registration)方法。主要流程就是根据serverAddr,spring.application.name等等配置的信息构建出一个Instance对象,这个Instance对象就是表示当前服务的信息的,最后再发送一个POST请求到nacos服务端,这样就大致完成了一个服务注册的过程。

总结过程

  • 在spring.factories文件中加上配置类NacosServiceRegistryAutoConfiguration
  • 在NacosServiceRegistryAutoConfiguration配置类中使用@Bean的方式创建出NacosServiceRegistry,NacosRegistration,NacosAutoServiceRegistration三个bean。
  • NacosAutoServiceRegistration继承了抽象类AbstractAutoServiceRegistration,这个抽象类实现了ApplicationListener< WebServerInitializedEvent >接口,监听了容器启动事件
  • 在容器启动的时候,会收到通知,触发抽象类的onApplicationEvent方法,最终会调用NacosAutoServiceRegistration构造函数中的ServiceRegistry对象,也就是nacos中的具体实现类NacosServiceRegistry,调用了NacosServiceRegistry类中的egister(Registration registration)方法
  • 之后会将当前服务信息,和nacos服务端信息整合成一个Instance实例对象,用这个Instance实例对象来表示当前服务信息。
  • 最后会发送一个POST请求,将Instance中存储的信息发送给nacos服务端,完成服务注册。

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

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

相关文章

【新版】系统架构设计师 - 案例分析 - 信息安全

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 案例分析 - 信息安全安全架构安全模型分类BLP模型Biba模型Chinese Wall模型 信息安全整体架构设计WPDRRC模型各模型安全防范功能 网络安全体系架构设计开放系统互联安全体系结构安全服务与安全机制…

mysql workbench常用操作

1、No database selected Select the default DB to be used by double-clicking its name in the SCHEMAS list in the sidebar 方法一&#xff1a;双击你要使用的库 方法二&#xff1a;USE 数据库名 2、复制表名&#xff0c;字段名 3、保存链接

简单趋势策略研究

交易对象&#xff1a;目前使用各种主力合约进行交易。 交易平台&#xff1a;易盛极星极星产品网 手续费研究:白糖期货手续费和保证金2023年09月更新 - 九期网 本人使用的期货交易公司&#xff1a;中信期货&#xff08;幸亏资金量大&#xff0c;返还高&#xff0c;不然就是给…

vue3+ts 实现移动端分页

current 开始页码 pageSize 结束页码 const sizeref<number>(10) //一页显示十条 const eachCurrentPageref<number>(1) //默认是第一页interface ITdata {current: number,pageSize: number,// xxxx 其他参数... } const selectApplyList ref<…

联想电脑打开exe提示要在Microsoft Store中搜索应用

问题&#xff1a; 你需要为此任务安装应用。 是否要在Microsoft Store中搜索一个&#xff1f; 如图&#xff1a; 出现此情况&#xff0c;仅需要做如下操作&#xff0c;在要打开的exe文件上右键&#xff0c;属性&#xff1a; 如图箭头所示&#xff0c;点击“解除锁定”出现对钩&…

题解:ABC321D - Set Menu

题解&#xff1a;ABC321D - Set Menu 题目 链接&#xff1a;Atcoder。 链接&#xff1a;洛谷。 难度 算法难度&#xff1a;B。 思维难度&#xff1a;C。 调码难度&#xff1a;B。 综合评价&#xff1a;见洛谷链接。 算法 枚举二分查找。 思路 先对b升序排序&#x…

C++提高编程:02 STL入门

这里写目录标题 STL初识1 STL的诞生2 STL基本概念3 STL六大组件4 STL中容器、算法、迭代器5 容器算法迭代器初识5.1 vector存放内置数据类型5.2 Vector存放自定义数据类型5.3 Vector容器嵌套容器 STL初识 1 STL的诞生 长久以来&#xff0c;软件界一直希望建立一种可重复利用的…

<十二>objectARX开发:Arx注册命令类型的含义以及颜色索引对应RGB值

1、注册命令类型 我们经常在acrxEntryPoint.cpp中看到注册命令如下: 那么各个宏定义代表什么意思呢? 主标识:(常用的) ACRX_CMD_MODAL: 在别的命令执行的时候该命令不会在其中执行。ACRX_CMD_TRANSPARENT: 命令可以再其它命令中执行,但在该标志下ads_sssetfirst()不能使…

SELECT * from t_user where user_id = xxx,可以从那几个点去优化这句sql

优化SQL查询可以从以下几个方面入手&#xff1a; 1. 索引优化&#xff1a;通过为查询涉及的列添加合适的索引&#xff0c;可以提高查询的效率。在该SQL语句中&#xff0c; user_id 列被用作查询条件&#xff0c;可以为 user_id 列创建一个索引。 2. 避免使用 SELECT *&#xf…

LeetCode 494.目标和 (动态规划 + 性能优化)二维数组 压缩成 一维数组

494. 目标和 - 力扣&#xff08;LeetCode&#xff09; 给你一个非负整数数组 nums 和一个整数 target 。 向数组中的每个整数前添加 或 - &#xff0c;然后串联起所有整数&#xff0c;可以构造一个 表达式 &#xff1a; 例如&#xff0c;nums [2, 1] &#xff0c;可以在 2…

用Redis做数据排名

1.背景 用Redis做数据缓存用的比较多&#xff0c;大家都能熟练使用String和Hash结构去存储数据&#xff0c;今天讲下如何使用ZSet来做数据排名。 假设场景是需要按天存储全国城市的得分数据&#xff0c;可以查询前十名的城市排名。 这个case可以使用传统关系型数据库做…

如何修复wmvcore.dll缺失问题,wmvcore.dll下载修复方法分享

近年来&#xff0c;电脑使用的普及率越来越高&#xff0c;人们在日常生活中离不开电脑。然而&#xff0c;有时候我们可能会遇到一些问题&#xff0c;其中之一就是wmvcore.dll缺失的问题。wmvcore.dll是Windows平台上用于支持Windows Media Player的动态链接库文件&#xff0c;如…

MATLAB算法实战应用案例精讲-【概念篇】用户画像(补充篇)

目录 前言 几个相关概念 算法原理 用户画像是什么? 用户画像种类

SD-MTSP:萤火虫算法(FA)求解单仓库多旅行商问题MATLAB(可更改数据集,旅行商的数量和起点)

一、萤火虫算法&#xff08;FA&#xff09;简介 萤火虫算法(Firefly Algorithm&#xff0c;FA)是Yang等人于2009年提出的一种仿生优化算法。 参考文献&#xff1a;田梦楚, 薄煜明, 陈志敏, et al. 萤火虫算法智能优化粒子滤波[J]. 自动化学报, 2016, 42(001):89-97. 二、单仓…

代码随想录Day42 | 01背包问题| 416. 分割等和子集

01背包问题&#xff08;Acwing&#xff09; 有 N 件物品和一个容量是 V的背包。每件物品只能使用一次。 第 i 件物品的体积是 vi&#xff0c;价值是 wi。 求解将哪些物品装入背包&#xff0c;可使这些物品的总体积不超过背包容量&#xff0c;且总价值最大。 输出最大价值。 输入…

数量关系(刘文超)

解题技巧 代入排除法 数字特性法 整除特性 比例倍数特性&#xff08;找比例&#xff0c;比例不明显时找等式&#xff09; 看不懂式子时&#xff0c;把所有的信息像表格一样列出来 看不懂式子时&#xff0c;把所有的信息像表格一样列出来

【机器学习】期望最大算法(EM算法)解析:Expectation Maximization Algorithm

【机器学习】期望最大算法&#xff08;EM算法&#xff09;&#xff1a;Expectation Maximization Algorithm 文章目录 【机器学习】期望最大算法&#xff08;EM算法&#xff09;&#xff1a;Expectation Maximization Algorithm1. 介绍2. EM算法数学描述3. EM算法流程4. 两个问…

性能测试 —— Tomcat监控与调优:Jconsole监控

JConsole的图形用户界面是一个符合Java管理扩展(JMX)规范的监测工具&#xff0c;JConsole使用Java虚拟机(Java VM)&#xff0c;提供在Java平台上运行的应用程序的性能和资源消耗的信息。在Java平台&#xff0c;标准版(Java SE平台)6&#xff0c;JConsole的已经更新到目前的外观…

Linux查看哪些进程占用的系统 buffer/cache 较高 (hcache,lsof)命令

1、什么是buffer/cache &#xff1f; buffer/cache 其实是作为服务器系统的文件数据缓存使用的&#xff0c;尤其是针对进程对文件存在 read/write 操作的时候&#xff0c;所以当你的服务进程在对文件进行读写的时候&#xff0c;Linux内核为了提高服务的读写速度&#xff0c;则将…

如何正确选择研究方向?如何实现论文创新?

学术评价是遵循“质量第一”原则的,所以对于研究生来说,从一开始就要把路子走正,自觉树立精品意识,把精力高度集中到提高学位论文的质量上来。这里,根据本人多年来指导博士和硕士研究生的体会,就人文社科研究生学位论文的选题与创新略述管见。 学位论文选题的两个层面 …