SpringCloud源码:客户端分析(一)- SpringBootApplication注解类加载流程

news2024/11/18 0:33:37

d7ff2a7b73efb4479d3640f21159b9bb.jpeg

总结一句话

用@EnableDiscoveryClient注解客户端-启动类,配合@springbootapplication,完成两个步骤:

  • 自动读取spring-factories文件的全限定类名内容

  • 通过selectImport对这些类进行初始化

背景

spring.factories作用

在maven依赖:

spring-cloud-netflix-eureka-client/2.2.6.RELEASE/spring-cloud-netflix-eureka-client-2.2.6.RELEASE.jar!的 META-INF 目录下,有一个spring.factories文件:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaClientConfigServerAutoConfiguration,\
org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,\
org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration,\
org.springframework.cloud.netflix.eureka.reactive.EurekaReactiveDiscoveryClientConfiguration,\
org.springframework.cloud.netflix.eureka.loadbalancer.LoadBalancerEurekaAutoConfiguration


org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaConfigServerBootstrapConfiguration

@SpringBootApplication为一个组合注解,通过@EnableAutoConfiguration开启自动装配。

spring.factories文件位于JAR包的META-INF目录下。

当Spring Boot应用启动时,它会自动扫描所有的spring.factories文件,并根据里面的配置加载相应的类。

在上述例子中,当应用启动时,EurekaClientAutoConfiguration 类将会被自动注册为一个bean,并可以通过依赖注入在其他组件中使用。

@SpringBootApplication注解

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
}

@EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}

AutoConfigurationImportSelector资源类

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
      ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {


    // ....
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
       List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
             getBeanClassLoader());
       Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
             + "are using a custom packaging, make sure that file is correct.");
       return configurations;
    }
}

分析:

  • getCandidateConfigurations:此处是自动导入spring.factories文件的全部实现类

我们从debug可以看到,已经读出了spring.factories的配置类,包括了EurekaClientAutoConfiguration和EurekaDiscoveryClientConfiguration 两个自动装配类。

76ba7229984bcc9d74452b2db24b6e4e.png

小结

EurekaClientAutoConfiguration和EurekaDiscoveryClientConfiguration在Spring Cloud Eureka中扮演着不同的角色,它们的主要区别在于功能和职责的不同。

自动化配置类
功能职责
EurekaClientAutoConfiguration配置EurekaClient确保了Eureka客户端能够正确地:
- 注册到Eureka服务端
- 周期性地发送心跳信息来更新服务租约
- 下线时通知Eureka服务端
- 获取服务实例列表;

更侧重于Eureka客户端的基本配置和功能实现
EurekaDiscoveryClientConfiguration配置EurekaDiscoveryClient创建RefreshScopeRefreshedEvent事件的监听类,用于重启注册;
更多地涉及到服务的自动注册、健康检查以及事件处理等方面

这两个配置类共同工作,确保了Spring Boot应用能够顺利地与Eureka服务注册中心进行交互,实现服务的注册和发现。

所以下文我们讨论客户端的4个功能(注册租约、更新租约、下线租约、获取服务列表),都是倾向于分析EurekaClient的代码。

EurekaClientAutoConfiguration自动配置类

自动化装配EurekaClient的相关bean,

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConditionalOnClass(EurekaClientConfig.class)
@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
@ConditionalOnDiscoveryEnabled
@AutoConfigureBefore({ NoopDiscoveryClientAutoConfiguration.class,
      CommonsClientAutoConfiguration.class, ServiceRegistryAutoConfiguration.class })
@AutoConfigureAfter(name = {
      "org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration",
      "org.springframework.cloud.autoconfigure.RefreshAutoConfiguration",
      "org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration",
      "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration" })
public class EurekaClientAutoConfiguration {


    // 【1】EurekaClientConfigBean:Eureka客户端bean,保存了环境配置信息
    @Bean
    @ConditionalOnMissingBean(value = EurekaClientConfig.class, search = SearchStrategy.CURRENT)
    public EurekaClientConfigBean eurekaClientConfigBean(ConfigurableEnvironment env) {
       return new EurekaClientConfigBean();
    }


    //【2】EurekaInstanceConfigBean:Eureka客户端实例bean,保存了实例信息
    @Bean
    @ConditionalOnMissingBean(value = EurekaInstanceConfig.class,
          search = SearchStrategy.CURRENT)
    public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils,
          ManagementMetadataProvider managementMetadataProvider) {
       String hostname = getProperty("eureka.instance.hostname");
       boolean preferIpAddress = Boolean
             .parseBoolean(getProperty("eureka.instance.prefer-ip-address"));
       String ipAddress = getProperty("eureka.instance.ip-address");
       boolean isSecurePortEnabled = Boolean
             .parseBoolean(getProperty("eureka.instance.secure-port-enabled"));


       String serverContextPath = env.getProperty("server.servlet.context-path", "/");
       int serverPort = Integer.parseInt(
             env.getProperty("server.port", env.getProperty("port", "8080")));


       Integer managementPort = env.getProperty("management.server.port", Integer.class);
       String managementContextPath = env
             .getProperty("management.server.servlet.context-path");
       Integer jmxPort = env.getProperty("com.sun.management.jmxremote.port",
             Integer.class);
       EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils);


       instance.setNonSecurePort(serverPort);
       instance.setInstanceId(getDefaultInstanceId(env));
       instance.setPreferIpAddress(preferIpAddress);
       instance.setSecurePortEnabled(isSecurePortEnabled);
       if (StringUtils.hasText(ipAddress)) {
          instance.setIpAddress(ipAddress);
       }


       if (isSecurePortEnabled) {
          instance.setSecurePort(serverPort);
       }


       if (StringUtils.hasText(hostname)) {
          instance.setHostname(hostname);
       }
       String statusPageUrlPath = getProperty("eureka.instance.status-page-url-path");
       String healthCheckUrlPath = getProperty("eureka.instance.health-check-url-path");


       // ....省略很多配置项赋值
       setupJmxPort(instance, jmxPort);
       return instance;
    }
}

分析:

  • 构造了EurekaInstanceConfigBean

    • EurekaClientConfigBean是一个配置类,会读取所有eureka.client打头的配置项,例如,eureka.client.serviceUrl.defaultZone=http://localhost:8881/eureka/,http://localhost2:8882/eureka/

  • 构造了EurekaClientConfigBean

EurekaClientConfiguration配置类

EurekaClientAutoConfiguration 内部有一个内部配置类EurekaClientConfiguration,它会继续初始化 CloudEurekaClient 和 ApplicationInfoManager 两个bean。

@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingRefreshScope
protected static class EurekaClientConfiguration {


    // 【3】
    @Bean(destroyMethod = "shutdown")
    @ConditionalOnMissingBean(value = EurekaClient.class,
          search = SearchStrategy.CURRENT)
    public EurekaClient eurekaClient(ApplicationInfoManager manager,
          EurekaClientConfig config) {
       return new CloudEurekaClient(manager, config, this.optionalArgs,
             this.context);
    }


    // 【4】
    @Bean
    @ConditionalOnMissingBean(value = ApplicationInfoManager.class,
          search = SearchStrategy.CURRENT)
    public ApplicationInfoManager eurekaApplicationInfoManager(
          EurekaInstanceConfig config) {
       InstanceInfo instanceInfo = new InstanceInfoFactory().create(config);
       return new ApplicationInfoManager(config, instanceInfo);
    }
}
小结

EurekaClientAutoConfiguration构造了EurekaClientConfigBean、EurekaInstanceConfigBean以及EurekaServiceRegistry,之后在这几个对象的基础上进一步构建ApplicationInfoManager、CloudEurekaClient等。

其中ApplicationInfoManager负责变更实例状态并发布StatusChangeEvent事件,而CloudEurekaClient继承了com.netflix.discovery.DiscoveryClient,里头包含了statusChangeListener用于响应StatusChangeEvent,最后触发的是DiscoveryClient.register方法,与远程的Eureka Server通信,同步实例状态。

另外,EurekaClientAutoConfiguration构建的EurekaClient-bean,会被EurekaDiscoveryClientConfiguration构建的EurekaDiscoveryClient,所注入使用

EurekaDiscoveryClientConfiguration自动配置类
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConditionalOnClass(EurekaClientConfig.class)
@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
@ConditionalOnDiscoveryEnabled
@ConditionalOnBlockingDiscoveryEnabled
public class EurekaDiscoveryClientConfiguration {


    // 【5】
    @Bean
    @ConditionalOnMissingBean
    public EurekaDiscoveryClient discoveryClient(EurekaClient client,
          EurekaClientConfig clientConfig) {
       return new EurekaDiscoveryClient(client, clientConfig);
    }


    // 【6】
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnProperty(value = "eureka.client.healthcheck.enabled", matchIfMissing = false)
    protected static class EurekaHealthCheckHandlerConfiguration {


        @Autowired(required = false)
        private StatusAggregator statusAggregator = new SimpleStatusAggregator();


        @Bean
        @ConditionalOnMissingBean(HealthCheckHandler.class)
        public EurekaHealthCheckHandler eurekaHealthCheckHandler() {
          return new EurekaHealthCheckHandler(this.statusAggregator);
        }
    }
}

分析:

  • 【5】构建EurekaDiscoveryClient,使用了EurekaClient 和 EurekaClientConfig

  • 【6】构建EurekaHealthCheckHandler

至此,完成了EurekaDiscoveryClient的创建

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

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

相关文章

学Python再学C++是走弯路?

随着编程教育的普及&#xff0c;越来越多的家长和学生开始选择学习编程语言。Python作为一种简洁易学、应用广泛的编程语言&#xff0c;成为许多编程初学者的首选。然而&#xff0c;随着学习的深入&#xff0c;很多人会考虑转向更复杂、更底层的语言&#xff0c;如C。这就引发了…

golang qq邮件发送验证码

验证码的使用场景 注册/登录&#xff1a;使用验证码可以有效减少垃圾账号注册和恶意登录&#xff1b;短信接口保护&#xff1a;高效减少防止短信接口被刷情况&#xff1b;提交/投票&#xff1a;有效减少恶意刷单、恶意提交、恶意投票等情况&#xff1b;密码找回&#xff1a;用…

JVS-Logic逻辑引擎:为外包项目需求变更提供80%的成本节约方案

在这个数字化时代&#xff0c;在当今数字化时代&#xff0c;业务逻辑在处理复杂性和多样性的应用程序和系统中都非常重要。逻辑引擎作为一种高效、灵活的工具&#xff0c;通过可视化编排和原子服务&#xff0c;实现了业务规则的自动化处理&#xff0c;极大地缩短了开发、部署和…

react crash course 2024(7) react router dom

安装 npm i react-router-dom 引入 import {Route,createBrowserRouter,createRoutesFromElements,RouterProvider} from react-router-dom 在app.jsx const router createBrowserRouter(createRoutesFromElements(<Route index element {<h1>My App</h1>…

客户文章|DAP-seq助力揭示GhSBI1调控棉花果枝节间伸长的分子机制

2024年7月26日&#xff0c;中国农业科学院棉花研究所张永山研究员团队在Plant Biotechnology Journal&#xff08;影响因子10.1&#xff09;杂志上发表了题为“GhSBI1, a CUP-SHAPED COTYLEDON 2 homologue, modulates branch internode elongation in cotton”的文章&#xff…

PMP与CMMI:两种管理方法的对比

PMP与CMMI&#xff1a;两种管理方法的对比 PMP&#xff1a;专注于项目管理CMMI&#xff1a;组织过程改进的框架总结&#xff1a;互补而非替代 在现代企业管理中&#xff0c;项目管理和组织能力成熟度模型集成&#xff08;CMMI&#xff09;是两个经常被提及的概念。虽然它们都是…

如何提升JavaScript安全性,保护应用程序免受威胁

JavaScript作为Web开发的主要开发语言&#xff0c;在前端应用开发中发挥着绝对主导的作用&#xff0c;保护我们的应用免受常见的安全威胁是每个前端开发人员应该掌握的基础知识。本文介绍了JavaScript基础的安全实践&#xff0c;了解如何防止XSS、CSRF等常见漏洞&#xff0c;实…

多人音视频房间 SDK

多人音视频房间 SDK 是音视频终端 SDK&#xff08;腾讯云视立方&#xff09;的子产品之一&#xff0c;基于企业培训、在线会议、网络研讨会等多人音视频会话场景定制&#xff0c;提供房间管理、成员管理、屏幕分享等会控功能&#xff0c;提供含 UI 快速集成方案&#xff0c;仅需…

【CSS】变换

空间概念translate ( 平移 )rotate ( 旋转 )scale ( 缩放 )skew ( 倾斜 )案例&#xff08; 六面骰子、旋转照片&#xff09; 空间概念 三维空间坐标 ( X&#xff0c;Y&#xff0c;Z ) 透视 ( perspective) 距离 ( 视距 ) d&#xff0c;近大远小&#xff0c;观众面向组件的距离 …

MATLAB案例 | Copula的密度函数和分布函数图

本文介绍各种类型&#xff08;Gaussian、t、Gumbel、Clayton、Frank&#xff09;Copula的密度函数和分布函数图的绘制 完整代码 clc close all clear%% ********************计算Copula的密度函数和分布函数图************************ [Udata,Vdata] meshgrid(linspace(0,1…

到时间没回家又不接电话?如何迅速确定孩子的位置?

当孩子未按时回家且无法通过电话联系时&#xff0c;家长往往会感到焦虑。此时&#xff0c;如何迅速确定孩子的位置成为许多家长迫切需要解决的问题。 利用智能手机定位技术是最常见的方法之一。大多数智能手机都内置GPS定位功能&#xff0c;通过“查找设备”应用&#xff0c;家…

你了解文档透明加密系统吗?介绍7款顶尖文档透明加密软件,热门推荐!

你了解文档透明加密系统吗&#xff1f; 文档透明加密系统&#xff0c;这一神奇的技术利器&#xff0c;正悄然守护着企业的核心机密。 它如同一位隐形的守护者&#xff0c;在你毫无察觉的情况下&#xff0c;对文档进行加密处理&#xff0c;确保数据在存储、传输及使用的全过程…

本地电脑基于nginx的https单向认证和双向认证(自制证书+nginx配置)保姆级

目录 1、背景 2、运行环境 3、工具下载 3.1、OpenSSL下载 3.2、nginx下载 4、制作https证书&#xff1a; 4.1、CA与自签名&#xff1a; 4.2、制作CA根证书&#xff08;公钥&#xff09; 4.3、制作服务端证书&#xff1a; 4.4、制作客户端证书&#xff1a; 4.5、制作…

openEuler 20.03,22.03,24.03一键部署Oracle23ai rpm

Oracle23ai前言 Oracle Database 23ai Free 让您可以充分体验 Oracle Database 的能力,世界各地的企业都依赖它来处理关键任务工作负载。 Oracle Database Free 的资源限制为 2 个 CPU(前台进程)、2 GB 的 RAM 和 12 GB 的磁盘用户数据。该软件包不仅易于使用,还可轻松下载…

智慧体育馆可视化:实时监控与智能管理

利用图扑可视化技术实现对体育馆的实时监控和数据分析&#xff0c;提升运营效率、观众体验和安全管理水平&#xff0c;打造智能化场馆环境。

Tomcat may not be running

一、问题背景 tomcat7运行在JDK1.7上&#xff0c;可启动tomcat&#xff0c;但是停止时报错误&#xff0c;如下&#xff1a; 二、适用条件 JDK1.7/JDK1.8 tomcat7 三、解决方法 1、查找java路径 which java 2、修改文件 找到/usr/lib/jvm/jdk1.7.0_80/jre/lib/security/j…

专业学习|《随机过程》学习笔记(二)(定义、分类及相关过程)

一、随机过程 &#xff08;一&#xff09;随机过程定义 &#xff08;1&#xff09;基本概念 随机过程是随机变量的延伸。 &#xff08;2&#xff09;描述随机过程的方法 &#xff08;3&#xff09;随机过程的分类和举例 &#xff08;4&#xff09;随机过程的数字特征 随机过…

【Python实操】淘宝商品详情数据采集返回并实现可视化处理

开发工具 Python版本&#xff1a;3.6.4 相关模块&#xff1a; DecryptLogin模块&#xff1b; pyecharts模块&#xff1b; 以及一些Python自带的模块。 环境搭建 安装Python并添加到环境变量&#xff0c;pip安装需要的相关模块即可。 数据爬取 既然说了是模拟登录相关的爬…

3519嵌入式如何通过ssh 或者telnet连接嵌入式设备

需求 PC电脑连接嵌入式设备&#xff0c;已经能够连接串口&#xff0c;想要额外连接嵌入式设备&#xff0c;查看终端信息。 尝试了两种方法&#xff1a;1.通过SSH登录(失败) 2.通过telnet登录(成功) 问题描述 1.SSH登录 3519通过网线和串口线连接PC windows&#xff0c;并在…

日本科学家利用AI技术在秘鲁纳斯卡沙漠地区找到303幅古代地画

据法新社24日报道&#xff0c;日本科学家利用 人工智能&#xff08; AI&#xff09;技术在秘鲁纳斯卡沙漠地区新发现了303幅古代地画。相关研究成果已于23日发表在《美国国家科学院院刊》上。 日本山形大学考古学家酒井正人23日在秘鲁首都利马宣布了这一新发现&#xff0c;他表…