SpringCloud Eureka Server源码解析(启动流程)

川长思鸟来 2022-09-08 10:28 331阅读 0赞

原创不易,转载请注明出处

文章目录

      • 前言
      • 1.spring cloud整合eureka server demo
        • 1.1 新建spring boot项目
        • 1.2 pom.xml文件添加
        • 1.3 配置文件
        • 1.4 启动类
        • 1.5 启动
      • 2.spring cloud自动装配eureka server源码解析
        • 2.1@EnableEurekaServer注解
        • 2.2 EurekaServerAutoConfiguration
          • 2.2.1 查找starter 自动装配类的技巧
          • 2.2.2 EurekaServerAutoConfiguration源码解析
      • 3.eureka server 初始化源码解析
        • 3.1 EurekaServerInitializerConfiguration
        • 3.2 DefaultEurekaServerContext

前言

本文主要看看spring cloud是怎样自动装配eureka server 并启动eureka server的并解析其关键源码。
首先我们会配置启动一个spring cloud eureka server 服务,接着看看是spring cloud怎样自动装配eureka的,并看看一些核心组件的创建源码,最后解析下eureka server 启动初始化流程,看看都干了些啥东西

1.spring cloud整合eureka server demo

1.1 新建spring boot项目

我这边spring boot 版本是2.1.6.RELEASE(比较老)

1.2 pom.xml文件添加

  1. <dependencyManagement>
  2. <!--引入springcloud依赖的-->
  3. <dependencies>
  4. <dependency>
  5. <groupId>org.springframework.cloud</groupId>
  6. <artifactId>spring-cloud-dependencies</artifactId>
  7. <version>Greenwich.RELEASE</version>
  8. <type>pom</type>
  9. <scope>import</scope>
  10. </dependency>
  11. </dependencies>
  12. </dependencyManagement>

用来规范spring cloud 的版本

  1. <dependencies>
  2. <!--web依赖-->
  3. <dependency>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-starter-web</artifactId>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-actuator</artifactId>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.springframework.cloud</groupId>
  13. <artifactId>spring-cloud-commons</artifactId>
  14. </dependency>
  15. <!--unit test-->
  16. <dependency>
  17. <groupId>org.springframework.boot</groupId>
  18. <artifactId>spring-boot-starter-test</artifactId>
  19. </dependency>
  20. <!--spring cloud eureka server 依赖-->
  21. <dependency>
  22. <groupId>org.springframework.cloud</groupId>
  23. <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
  24. </dependency>
  25. </dependencies>

添加用到的依赖

1.3 配置文件

  1. eureka:
  2. instance:
  3. hostname: localhost
  4. client:
  5. service-url: # eureka server 的地址, 咱们单实例模式就写自己好了
  6. defaultZone: http://localhost:9090/eureka
  7. register-with-eureka: false # 不向eureka server 注册自己
  8. fetch-registry: false # 不向eureka server 获取服务列表

1.4 启动类

  1. @SpringBootApplication
  2. @EnableEurekaServer
  3. public class SpringCloudEurekaServerApplication {
  4. public static void main(String[] args) {
  5. SpringApplication.run(SpringCloudEurekaServerApplication.class, args);
  6. }
  7. }

添加@EnableEurekaServer注解,表示它是个eureka server。

1.5 启动

在这里插入图片描述
注意:由于是源码解析的文章,更详细的配置可以查看《SpringCloud之Eureka使用篇》

2.spring cloud自动装配eureka server源码解析

2.1@EnableEurekaServer注解

上一节配置eureka server的时候我们在配置类上加了个@EnableEurekaServer注解,表示启动一个eureka server 。
我们看看这个注解

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Import(EurekaServerMarkerConfiguration.class)
  5. public @interface EnableEurekaServer {
  6. }

上面有个@Import(EurekaServerMarkerConfiguration.class) 注解导入了EurekaServerMarkerConfiguration配置类,我们看下配置类

  1. @Configuration
  2. public class EurekaServerMarkerConfiguration {
  3. @Bean
  4. public Marker eurekaServerMarkerBean() {
  5. return new Marker();
  6. }
  7. class Marker {
  8. }
  9. }

就是创建了一个EurekaServerMarkerConfiguration.Marker 对象,交给spring保管,一看就是个标记,标识,仅仅是个标识。

2.2 EurekaServerAutoConfiguration

2.2.1 查找starter 自动装配类的技巧

spring boot的starter基本都会自动装配类,也就是AutoConfiguration 结尾的类,如果我们找不到某个starter的自动装配类是那个,可以去starter对应jar 包里面META-INF 文件夹下面找spring.factories (这是spring spi 配置文件)文件
在这里插入图片描述
比如说我可以在spring-cloud-netflix-eureka-server 这个项目下找到META-INF 文件夹下面找spring.factories文件。
在这里插入图片描述
文件内容就是上图里面的,可以看到自动装配类就是EurekaServerAutoConfiguration。

2.2.2 EurekaServerAutoConfiguration源码解析

首先,看看 EurekaServerAutoConfiguration 自动配置类里面都干了啥。

  1. @Configuration
  2. @Import(EurekaServerInitializerConfiguration.class)
  3. @ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)
  4. @EnableConfigurationProperties({ EurekaDashboardProperties.class,
  5. InstanceRegistryProperties.class })
  6. @PropertySource("classpath:/eureka/server.properties")
  7. public class EurekaServerAutoConfiguration extends WebMvcConfigurerAdapter{ }

先看看类上面声明的这一堆注解。

  1. @Import(EurekaServerInitializerConfiguration.class) : 导入(装配)配置类EurekaServerInitializerConfiguration,这个我们后面看下,属于初始化流程。
  2. @ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class) 就是是否存在EurekaServerMarkerConfiguration.Marker 类的bean实例,这个肯定存在的,我们在@EnableEurekaServer 注解中就创建了这么一个bean 交给spring 管理了。存在就会往下走,不存在就拉倒了,不会再加载配置类里面别的东西了,也就是不会自动启动eureka server了。
  3. @EnableConfigurationProperties({ EurekaDashboardProperties.class,
    InstanceRegistryProperties.class }) 这个就是装配这两个配置类,一个是关于Dashboard 的,一个是关于instance 的配置,也就是eureka server的配置, 就是将我们写在application.yml配置文件中关于eureka 的配置set到这里面的属性中。
  4. @PropertySource(“classpath:/eureka/server.properties”) 加载/eureka/server.properties 配置文件,这个没啥意思。

然后,看看里面成员有哪些。

  1. @Autowired
  2. private ApplicationInfoManager applicationInfoManager;
  3. @Autowired
  4. private EurekaServerConfig eurekaServerConfig;
  5. @Autowired
  6. private EurekaClientConfig eurekaClientConfig;
  7. @Autowired
  8. private EurekaClient eurekaClient;
  9. @Autowired
  10. private InstanceRegistryProperties instanceRegistryProperties;

ApplicationInfoManager / EurekaClientConfig / EurekaClient 这几个bean 一看就是eureka client 里面的,我们这里是eureka server ,为啥能够注入进来呢?
原因是 eureka server 的starter 里面依赖了eureka client starter,eureka client starter自动装配的这些实例bean 。有些小伙伴可能会有疑问,我启用(自动装配)eureka client,不需要在配置类上面添加@EnableEurekaClient注解嘛。其实从spring cloud netflix 1.4版本往后主要引入了这个 eureka client starter 依赖,就会自动装配,不需要添加@EnableEurekaClient 注解也是可以的。

接着,看看创建了哪些核心组件

  1. dashboard 的controller

    @Bean
    @ConditionalOnProperty(prefix = “eureka.dashboard”, name = “enabled”, matchIfMissing = true)
    public EurekaController eurekaController() {
    return new EurekaController(this.applicationInfoManager);
    }

  2. 注册表创建

    @Bean
    public PeerAwareInstanceRegistry peerAwareInstanceRegistry(

    1. ServerCodecs serverCodecs) {
    2. this.eurekaClient.getApplications(); // force initialization
    3. return new InstanceRegistry(this.eurekaServerConfig, this.eurekaClientConfig,
    4. serverCodecs, this.eurekaClient,
    5. this.instanceRegistryProperties.getExpectedNumberOfClientsSendingRenews(),
    6. this.instanceRegistryProperties.getDefaultOpenForTrafficCount());

    }

注册表,就是存放我们注册的实例信息的,这个是个非常核心的组件。这里直接创建了一个InstanceRegistry 对象,这个InstanceRegistry继承eureka server 里面PeerAwareInstanceRegistryImpl 类。

  1. 集群节点信息类对象

    @Bean
    @ConditionalOnMissingBean
    public PeerEurekaNodes peerEurekaNodes(PeerAwareInstanceRegistry registry,

    1. ServerCodecs serverCodecs) {
    2. return new RefreshablePeerEurekaNodes(registry, this.eurekaServerConfig,
    3. this.eurekaClientConfig, serverCodecs, this.applicationInfoManager);

    }

PeerEurekaNodes 这个类,从名字上也能看出来是集群节点的类,而且是Nodes ,表示多个节点,其实里面就是封装eureka server 集群的节点们。这里是创建RefreshablePeerEurekaNodes 对象,RefreshablePeerEurekaNodes继承PeerEurekaNodes 类,实现spring 的ApplicationListener 事件监听接口,自然而然的RefreshablePeerEurekaNodes类具有了刷新集群节点信息功能(能力)。

  1. @Bean
    public EurekaServerContext eurekaServerContext(ServerCodecs serverCodecs,

    1. PeerAwareInstanceRegistry registry, PeerEurekaNodes peerEurekaNodes) {
    2. return new DefaultEurekaServerContext(this.eurekaServerConfig, serverCodecs,
    3. registry, peerEurekaNodes, this.applicationInfoManager);

    }

EurekaServerContext 从字面上是eureka server 上下文,其实就是eureka server 启动的时候会初始化PeerEurekaNodes 与PeerAwareInstanceRegistry 注册表,销毁的是否停止这2个组件

  1. @Bean
    public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry registry,

    1. EurekaServerContext serverContext) {
    2. return new EurekaServerBootstrap(this.applicationInfoManager,
    3. this.eurekaClientConfig, this.eurekaServerConfig, registry,
    4. serverContext);

    }

一般叫Bootstrap 的类都是那种掌管项目启动与停止的,EurekaServerBootstrap 也不例外,它里面就有contextInitialized 项目启动与contextDestroyed项目停止/销毁的方法。

  1. 关于jersey框架的东西,eureka server 对外暴露rest ful接口,使用的框架就是jersey(这玩意国内很少用),作用/定位就跟我们常用的springmvc 框架差不多。

3.eureka server 初始化源码解析

3.1 EurekaServerInitializerConfiguration

第二节介绍 spring cloud eureka server 启动的时候自动装配的一些组件,本小节就看下eureka server的初始化流程
在自动装配类EurekaServerAutoConfiguration 类上面声明了@Import(EurekaServerInitializerConfiguration.class) ,我们介绍说是导入(加载)EurekaServerInitializerConfiguration 这个配置,一看这个类名字就是eureka server 初始化用的。

  1. @Configuration
  2. public class EurekaServerInitializerConfiguration
  3. implements ServletContextAware, SmartLifecycle, Ordered {

@Configuration是个配置类,实现ServletContextAware,SmartLifecycle,Ordered 接口
ServletContextAware 作用是自动注入ServletContext 实例。
SmartLifecycle接口 属于spring 声明周期的,start 方法执行时机是,当spring 的bean都实例化,初始化完事后,会调用SmartLifecycle 的start方法,isAutoStartup 方法返回的true 或者false 决定要不要执行start方法,这里isAutoStartup方法返回的true。
stop 方法就是项目停止,容器销毁的时候会调用。
先来看下start 方法干了啥

  1. @Override
  2. public void start() {
  3. new Thread(new Runnable() {
  4. @Override
  5. public void run() {
  6. try {
  7. //TODO: is this class even needed now?
  8. eurekaServerBootstrap.contextInitialized(EurekaServerInitializerConfiguration.this.servletContext);
  9. log.info("Started Eureka Server");
  10. publish(new EurekaRegistryAvailableEvent(getEurekaServerConfig()));
  11. EurekaServerInitializerConfiguration.this.running = true;
  12. publish(new EurekaServerStartedEvent(getEurekaServerConfig()));
  13. }
  14. catch (Exception ex) {
  15. // Help!
  16. log.error("Could not initialize Eureka servlet context", ex);
  17. }
  18. }
  19. }).start();
  20. }

创建了一个线程,先是执行eurekaServerBootstrap 的contextInitialized 初始化方法。接着就是发布
EurekaRegistryAvailableEvent 事件,设置running 为true ,最后就是发布EurekaServerStartedEvent 事件。
这里我们只关心eurekaServerBootstrap的contextInitialized 方法。

  1. public void contextInitialized(ServletContext context) {
  2. initEurekaEnvironment();
  3. initEurekaServerContext();
  4. context.setAttribute(EurekaServerContext.class.getName(), this.serverContext);
  5. }

初始化eureka environment, 接着初始化context,最后是将context塞到 ServletContext的属性中。
initEurekaEnvironment这个我们就不看了。
主要看下initEurekaServerContext 方法

  1. if (isAws(this.applicationInfoManager.getInfo())) {
  2. this.awsBinder = new AwsBinderDelegate(this.eurekaServerConfig,
  3. this.eurekaClientConfig, this.registry, this.applicationInfoManager);
  4. this.awsBinder.start();
  5. }
  6. EurekaServerContextHolder.initialize(this.serverContext);
  7. log.info("Initialized server context");
  8. // Copy registry from neighboring eureka node
  9. int registryCount = this.registry.syncUp();
  10. this.registry.openForTraffic(this.applicationInfoManager, registryCount);
  11. // Register all monitoring statistics.
  12. EurekaMonitors.registerAllStats();

isAws 是亚马逊云环境的时候执行if里面的那一堆,这个不看了。
EurekaServerContextHolder.initialize(this.serverContext);这行代码没干啥。

  1. int registryCount = this.registry.syncUp();
  2. this.registry.openForTraffic(this.applicationInfoManager, registryCount);

这个就是去集群中的其他节点拉取注册表。

3.2 DefaultEurekaServerContext

我们在介绍自动装配类EurekaServerAutoConfiguration 装配组件的时候,介绍过EurekaServerContext ,说他字面上是eureka server 上下文,其实就是eureka server 启动的时候会初始化PeerEurekaNodes 与PeerAwareInstanceRegistry 注册表,销毁的是否停止这2个组件
我们来看下 @PostConstruct 注解修饰的initialize 方法

  1. @PostConstruct
  2. public void initialize() {
  3. this.peerEurekaNodes.start();
  4. this.registry.init(this.peerEurekaNodes);
  5. }

干了2件事,启动peerEurekaNodes ,初始化注册表。
peerEurekaNodes#start

  1. public void start() {
  2. updatePeerEurekaNodes(resolvePeerUrls());
  3. Runnable peersUpdateTask = new Runnable() {
  4. @Override
  5. public void run() {
  6. updatePeerEurekaNodes(resolvePeerUrls());
  7. }
  8. };
  9. taskExecutor.scheduleWithFixedDelay(
  10. peersUpdateTask,
  11. serverConfig.getPeerEurekaNodesUpdateIntervalMs(),
  12. serverConfig.getPeerEurekaNodesUpdateIntervalMs(),
  13. TimeUnit.MILLISECONDS
  14. );
  15. }

先是更新集群节点信息,就是创建节点对象。
接着就是创建一个定时任务更新,默认是10分钟。

注册表初始化:

  1. @Override
  2. public void init(PeerEurekaNodes peerEurekaNodes) throws Exception {
  3. this.numberOfReplicationsLastMin.start();
  4. this.peerEurekaNodes = peerEurekaNodes;
  5. initializedResponseCache();
  6. scheduleRenewalThresholdUpdateTask();
  7. initRemoteRegionRegistry();
  8. }

numberOfReplicationsLastMin 这是记录续约次数的一个组件,用在服务剔除。
initializedResponseCache 初始化响应cache ,这个其实就是 服务发现的时候三级缓存。

发表评论

表情:
评论列表 (有 0 条评论,331人围观)

还没有评论,来说两句吧...

相关阅读