SpringCloud-Eureka服务端启动过程源码分析(4)

1.入口EurekaServerAutoConfiguration

在第一节中,我们在启动类中使用EnableEurekaServer 标注该项目为Eureka注册中心服务端,而该类是在org.springframework.cloud:spring-cloud-netflix-eureka-server依赖包下,那么根据springboot自动装配原理 ,我们在META-INF 文件夹下的spring.factoryies下发现,自动装配类为org.springframework.cloud.netflix.eureka.server.EurekaServerAutoConfiguration 那么一切的故事将这个类开始。

2.EurekaServerAutoConfiguration装配前提条件

EurekaServerAutoConfiguration 的注解中,存在ConditionalOnBean 注解标注:只有当满足存在

EurekaServerMarkerConfiguration.Marker 时,才会去自动装配。

而我们可以看到EurekaServerMarkerConfiguration 是被@Configuration注解,通过一下代码进行实例化Marker对象

@Bean
	public Marker eurekaServerMarkerBean() {
		return new Marker();
	}

但是未被扫描的EurekaServerMarkerConfiguration 如何进行实例化呢?我们在EnableEurekaServer 注解上看到Import 注解中中标注了,EnableEurekaServer使用时,需要先实例化EurekaServerMarkerConfiguration 到容器管理中。由此可见,我们为啥要在启动类上加上EnableEurekaServer 注解了。

Import的的作用请参照:Spring-Import注解

3.EurekaServerInitializerConfiguration初始化

EurekaServerAutoConfiguration 上通过Import引入了EurekaServerInitializerConfiguration 实例。那我们先解析一下EurekaServerInitializerConfiguration 源码

/**
 * 1.EurekaServerInitializerConfiguration 实现了ServletContextAware,代表着会自动注入ServletContext实例到该类中(EurekaServer启动需要)
 * 2.SmartLifecycle 是一个接口。当Spring容器加载所有bean并完成初始化之后,会接着回调实现该接口的类中对应的start()方法(参照org.springframework.context.support.DefaultLifecycleProcessor#doStart(java.util.Map, java.lang.String, boolean))
 */
@Configuration
public class EurekaServerInitializerConfiguration
        implements ServletContextAware, SmartLifecycle, Ordered {

    private static final Log log = LogFactory.getLog(EurekaServerInitializerConfiguration.class);
    /**
     * eureka 服务端配置
     */
    @Autowired
    private EurekaServerConfig eurekaServerConfig;
    /**
     * 通过ServletContextAware注入的servletContext
     */
    private ServletContext servletContext;
    /**
     * 通过Autowired自动注入ApplicationContext
     */
    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 见名知意,Eureka服务端的启动引导类
     */
    @Autowired
    private EurekaServerBootstrap eurekaServerBootstrap;

    private boolean running;

    private int order = 1;

    @Override
    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    /**
     * 当Spring容器加载所有bean并完成初始化之后,会接着回调SmartLifecycle中的start方法
     * 参照org.springframework.context.support.DefaultLifecycleProcessor#doStart(java.util.Map, java.lang.String, boolean)
     *
     */
    @Override
    public void start() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //TODO: is this class even needed now?
                    // eureka服务端启动引导类开始上下文初始化 (重点关注)
                    eurekaServerBootstrap.contextInitialized(EurekaServerInitializerConfiguration.this.servletContext);
                    // 清晰明了的日志告诉我们,Eureka Server 启动了。所以上面那个就是Eureka启动的核心步骤
                    // 我们可以慢慢解析
                    log.info("Started Eureka Server");
                    // 发布 Eureka 注册可用事件 (暂不关注)
                    publish(new EurekaRegistryAvailableEvent(getEurekaServerConfig()));
                    // 线程状态修改为运行中
                    EurekaServerInitializerConfiguration.this.running = true;
                    // 发布 Eureka 服务端已启动事件 (暂不关注)
                    publish(new EurekaServerStartedEvent(getEurekaServerConfig()));
                }
                catch (Exception ex) {
                    // Help!
                    log.error("Could not initialize Eureka servlet context", ex);
                }
            }
        }).start();
    }

    private EurekaServerConfig getEurekaServerConfig() {
        return this.eurekaServerConfig;
    }

    private void publish(ApplicationEvent event) {
        this.applicationContext.publishEvent(event);
    }
		... 删除部分不想解析的代码
}

从上文我所备注的信息中我们可以看到很核心的3个点

  1. EurekaServerBootstrapeureka server的启动引导类,且需要servlet方面的支持
  2. 继承自SmartLifecycle后,会在所有的bean被初始化完成后会调用start方法
  3. eurekaServerBootstrap.contextInitialized 是Eureka服务启动的核心

这里定一个传送门 Spring的SmartLifecycle调用机制

在第3点中,我们可以看到EurekaServerBootstrap 作为Eureka服务端启动引导类,那他是在哪里实例化的呢?

参照:org.springframework.cloud.netflix.eureka.server.EurekaServerAutoConfiguration#eurekaServerBootstrap

4.contextInitialized 初始化

public void contextInitialized(ServletContext context) {
		try {
			// 初始化 eureka环境(配置加载,不做深入)
			initEurekaEnvironment();
			//初始化 eureka上下文 (重点关注)
			initEurekaServerContext();
			// 将eureka上下文保存到servlet上下文中,便于提供管理界面数据和提供接口
			context.setAttribute(EurekaServerContext.class.getName(), this.serverContext);
		}
		catch (Throwable e) {
			log.error("Cannot bootstrap eureka server :", e);
			throw new RuntimeException("Cannot bootstrap eureka server :", e);
		}
	}

从上面我们可知,我们现在应该重点关注

org.springframework.cloud.netflix.eureka.server.EurekaServerBootstrap#initEurekaServerContext 方法

5. initEurekaServerContext初始化上下文

protected void initEurekaServerContext() throws Exception {
		// For backward compatibility
		//json解析器 添加Eureka V1版本实例信息转化器
		JsonXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(),
				XStream.PRIORITY_VERY_HIGH);
		//xml解析器 添加Eureka V1版本实例信息转化器
		XmlXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(),
				XStream.PRIORITY_VERY_HIGH);
		// 嗯,没错,这里是亚马逊特别加持对EIP和Router53的加持
		if (isAws(this.applicationInfoManager.getInfo())) {
			// 亚马逊绑定器
			this.awsBinder = new AwsBinderDelegate(this.eurekaServerConfig,
					this.eurekaClientConfig, this.registry, this.applicationInfoManager);
			this.awsBinder.start();
		}
		// EurekaServerContext 用来提供给非spring管理的类来使用eurekaServerContext
		EurekaServerContextHolder.initialize(this.serverContext);
		
		log.info("Initialized server context");

		// Copy registry from neighboring eureka node
		// 获取集群中的其他节点,注册到当前节点上(重点,在后面服务端集群同步中会进行讲解)
		int registryCount = this.registry.syncUp();
		// 记录自身上线时间,标记自身状态为UP以便集群中其他节点进行同步,统计副本数量,开启失效实例剔除任务等 
		this.registry.openForTraffic(this.applicationInfoManager, registryCount);
		// 注册所有监控统计信息
		// Register all monitoring statistics.
		EurekaMonitors.registerAllStats();
	}

从上面注释信息中,我们可以看到,初始化过程为:

  1. 首先Eureka集群中,会进行向下兼容,即V2兼容V1版本
  2. 由于亚马逊路由的特殊性,所以添加亚马逊相关判断
  3. 对外提供非spring实例访问方式
  4. 同步集群其他服务端信息
  5. 自身信息构建,并开启实例失效剔除定时任务
  6. 注册各种监控指标到监控中心

到此完成Eureka的服务端启动,当然在 EurekaServerAutoConfiguration 还有很多东西我们没有讲,在那里面实例化了很多有用的东西。为了控制篇幅,我决定留在下一节继续梳理。希望能对你有帮助~

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欢谷悠扬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值