• Eureka 系列(03)Spring Cloud 自动装配原理


    Eureka 系列(03)Spring Cloud 自动装配原理

    0. Spring Cloud 系列目录 - Eureka 篇

    本文主要是分析 Spring Cloud 是如何整合 Eureka 的,但不会具体分析 Eureka 的源码,之后的文章会对 Eureka 的源码做一个比较具体的分析。

    1. Eureka Client 自动装配

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
    org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,
    org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration
    
    图1:Eureka Client 自动装配时序图
    sequenceDiagram participant EurekaClientAutoConfiguration participant EurekaDiscoveryClientConfiguration participant CloudEurekaClient participant EurekaAutoServiceRegistration EurekaClientAutoConfiguration ->> CloudEurekaClient : @Bean EurekaDiscoveryClientConfiguration ->> EurekaAutoServiceRegistration : @Bean EurekaAutoServiceRegistration ->> CloudEurekaClient : register

    总结: Eureka Client 的装配很简单,主要是组装 DiscoveryClient。

    • EurekaClientAutoConfiguration 主要是装配 EurekaClient
    • EurekaDiscoveryClientConfiguration 主要是在 Eureka Client 启动时立即将自身注册到 Eureka Server 上。

    1.1 装配 DiscoveryClient

    EurekaClientAutoConfiguration 主要是装配 CloudEurekaClient,CloudEurekaClient 继承了 DiscoveryClient,主要是增加了 Spring 的事件机制。

    @Bean(destroyMethod = "shutdown")
    public EurekaClient eurekaClient(ApplicationInfoManager manager,
    	EurekaClientConfig config, EurekaInstanceConfig instance,
    	@Autowired(required = false) HealthCheckHandler healthCheckHandler) {
        CloudEurekaClient cloudEurekaClient = new CloudEurekaClient(
            appManager, config, this.optionalArgs, this.context);
        cloudEurekaClient.registerHealthCheck(healthCheckHandler);
        return cloudEurekaClient;
    }
    

    1.2 启动时立即注册

    EurekaDiscoveryClientConfiguration 主要是实现了自动注册。在 DiscoveryClient 中默认是启动 40s 后才会注册,延迟太长,Spring Cloud 改变了这种默认实现,在启动时调用 EurekaAutoServiceRegistration.start() ,将自身实例注册到 Eureka Server 上。

    // EurekaAutoServiceRegistration 启动时自动注册
    public void start() {
        if (!this.running.get() && this.registration.getNonSecurePort() > 0) {
            // 启动时自动注册
            this.serviceRegistry.register(this.registration);
            this.context.publishEvent(new InstanceRegisteredEvent<>(this, this.registration.getInstanceConfig()));
            this.running.set(true);
        }
    }
    

    1.3 替换 EurekaHttpClient

    Spring Cloud 实现了自己的 RestTemplateEurekaHttpClient,可以替换默认的 JerseyApplicationClient。DiscoveryClientOptionalArgsConfiguration 中装配条件如下:

    @Bean
    @ConditionalOnMissingClass("com.sun.jersey.api.client.filter.ClientFilter")
    @ConditionalOnMissingBean(value = AbstractDiscoveryClientOptionalArgs.class, search = SearchStrategy.CURRENT)
    public RestTemplateDiscoveryClientOptionalArgs restTemplateDiscoveryClientOptionalArgs() {
        return new RestTemplateDiscoveryClientOptionalArgs();
    }
    

    查一下 com.sun.jersey 的依赖情况,可以看到 eureka-client 默认会引入 jersey-client,也就是说会使用默认的 JerseyApplicationClient。

    >mvn dependency:tree -Dincludes="com.sun.jersey"
    [INFO] com.github.binarylei.springcloud:user-consumer-eureka-client:jar:1.0.0
    [INFO] - org.springframework.cloud:spring-cloud-starter-netflix-eureka-client:jar:2.1.1.RELEASE:compile
    [INFO]    - com.netflix.eureka:eureka-client:jar:1.9.8:compile
    [INFO]       +- com.sun.jersey:jersey-core:jar:1.19.1:runtime
    [INFO]       - com.sun.jersey:jersey-client:jar:1.19.1:runtime
    

    既然知道了原因,要替换为 RestTemplateEurekaHttpClient 就很简单了。

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        <exclusions>
            <exclusion>
                <groupId>com.sun.jersey</groupId>
                <artifactId>jersey-client</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    

    分析了客户自动装配后,接下来继续分析 Eureka Server 服务端的启动原理,Eureka 服务端的启动同样依赖 DiscoverClient(个人感觉依赖有点混乱)。

    2. Eureka Server 自动装配

    在原生的 Eureka 中服务端的启动类是 EurekaBootStrap,Spring Cloud 中启动类是 EurekaServerBootstrap,原理大致都差不多。本文会以 EurekaServerBootstrap 为切入点进行分析。

    EurekaServerAutoConfiguration 是 Spring Cloud 自动装配入口,配置如下:

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
      org.springframework.cloud.netflix.eureka.server.EurekaServerAutoConfiguration
    

    注意: EurekaServerAutoConfiguration 需要配合 @EnableEurekaServer 使用。

    2.1 Eureka Server 自动装配流程

    图2:Eureka Server 自动装配时序图
    sequenceDiagram participant EurekaServerAutoConfiguration participant EurekaServerInitializerConfiguration participant PeerAwareInstanceRegistry participant PeerEurekaNodes participant EurekaServerBootstrap participant EurekaClient EurekaServerAutoConfiguration ->> PeerAwareInstanceRegistry : @Bean EurekaServerAutoConfiguration ->> PeerEurekaNodes : @Bean EurekaServerAutoConfiguration ->> EurekaServerBootstrap : @Bean EurekaServerAutoConfiguration ->> EurekaServerInitializerConfiguration : @Import loop Eureka Server 服务启动 EurekaServerInitializerConfiguration ->> EurekaServerInitializerConfiguration : start EurekaServerInitializerConfiguration ->> EurekaServerBootstrap : contextInitialized EurekaServerBootstrap ->> PeerAwareInstanceRegistry : 1. 从其它服务器同步数据:syncUp PeerAwareInstanceRegistry ->> EurekaClient : 获取其它服务器的数据:getApplications EurekaServerBootstrap ->> PeerAwareInstanceRegistry : 2. 启动自动过期定时任务:openForTraffic end loop Eureka Server 服务销毁 EurekaServerInitializerConfiguration ->> EurekaServerInitializerConfiguration : stop EurekaServerInitializerConfiguration ->> EurekaServerBootstrap : contextDestroyed end

    总结: Spring Cloud 有个特点,一般来说类的职责都很明确。

    1. EurekaServerAutoConfiguration 主要是装配 EurekaServerBootstrap
    2. EurekaServerInitializerConfiguration 则负责启动 EurekaServerBootstrap
    3. EurekaServerBootstrap 启动时主要完成两件事:一是从其它 Eureka Server 上同步数据;二是启动自动过期定时任务 EvictionTask。可以看到 Eureka 最核心的数据结构是 PeerAwareInstanceRegistry。

    Eureka Server 核心实现类:

    • PeerAwareInstanceRegistry 负责 Eureka Server 之间数据同步,其父类 AbstractInstanceRegistry 则管理所有的本地注册信息。
    • PeerEurekaNodes 负责 Eureka Server 服务器列表管理。
    • EurekaServerBootstrap 启动类。
    • EurekaClient 上文提到 Eureka Server 启动是要依赖 Eureka Client 客户端,所以也会自动装配 EurekaClient,启动时同步数据会依赖 EurekaClient。

    2.2 EurekaServerBootstrap

    EurekaServerInitializerConfiguration 实现了 SmartLifecycle 接口,也就是启动和销毁时会分别调用 start 和 stop 方法。

    public void start() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // TODO: is this class even needed now?
                    eurekaServerBootstrap.contextInitialized(
                        EurekaServerInitializerConfiguration.this.servletContext);
                    log.info("Started Eureka Server");
    
                    publish(new EurekaRegistryAvailableEvent(getEurekaServerConfig()));
                    EurekaServerInitializerConfiguration.this.running = true;
                    publish(new EurekaServerStartedEvent(getEurekaServerConfig()));
                }
                catch (Exception ex) {
                    // Help!
                    log.error("Could not initialize Eureka servlet context", ex);
                }
            }
        }).start();
    }
    
    public void stop() {
        this.running = false;
        eurekaServerBootstrap.contextDestroyed(this.servletContext);
    }
    

    继续关注 EurekaServerBootstrap 的 contextInitialized 和 contextDestroyed 方法分别完成了什么事情。

    public void contextInitialized(ServletContext context) {
        initEurekaEnvironment();
        initEurekaServerContext();
    }
    
    protected void initEurekaServerContext() throws Exception {
        ...
        // Copy registry from neighboring eureka node
        int registryCount = this.registry.syncUp();
        this.registry.openForTraffic(this.applicationInfoManager, registryCount);
    
        // Register all monitoring statistics.
        EurekaMonitors.registerAllStats();
    }
    

    总结: 可以看到 EurekaServerBootstrap 启动时主要步骤:一是同步数据;二是启动定时过期的任务 EvictionTask。具体的源码会在之后分析。


    每天用心记录一点点。内容也许不重要,但习惯很重要!

  • 相关阅读:
    Python3爬虫系列:理论+实验+爬取妹子图实战
    虚机安装后无网卡、网卡驱动
    Linux运维工程师面试题整理
    睡眠或者重启windows,无法ssh连接或者pingVMware的虚机
    W10: Warning: Changing a readonly file使用vi/vim报错问题解决
    keyboard-interactive authentication with the ssh2 server failed 的SecureCRT报错解决
    公网访问内网实现(内网穿透)
    Linux内网时钟同步问题(ntp和chrony)
    xshell的快捷复制粘贴设置
    Linux中shell去除空行的几种方法
  • 原文地址:https://www.cnblogs.com/binarylei/p/11610885.html
Copyright © 2020-2023  润新知