springcloud 之 eureka 源码解析(2)-Eureka Server 启动流程分析

springcloud 之 eureka 源码解析(2)-Eureka Server 启动流程分析,第1张

springcloud 之 eureka 源码解析(2)-Eureka Server 启动流程分析

文章目录
  • Eureka Server 启动流程分析
    • 前言
      • 1、整体流程图
      • 2、相应的类概念说明
        • 2.1 ConfigurationManager
        • 2.2 AbstractConfiguration
        • 2.3 EurekaServerConfig
        • 2.4 ApplicationInfoManager
        • 2.5 EurekaClientConfig
        • 2.6 DiscoveryClient
        • 2.7 PeerAwareInstanceRegistry
        • 2.8 PeerEurekaNodes
        • 2.9 EurekaServerContext
    • 1、com.netflix.eureka.EurekaBootStrap
    • 2、contextInitialized 方法分析
    • 3、initEurekaEnvironment 分析
    • 4、**initEurekaServerContext(核心逻辑,重点看一下)**
    • 5、总结(需要注意的点)
      • 5.1 实例化DiscoveryClient
      • 5.2 实例化 PeerAwareInstanceRegistryImpl
      • 5.3 serverContext.initialize()
      • 5.4 registry.openForTraffic

Eureka Server 启动流程分析 前言

eureka server 启动的话,其实就相当于根据 web.xml 启动容器,然后对外提供服务,所以我们就从启动类作为入口分析

1、整体流程图

2、相应的类概念说明 2.1 ConfigurationManager

配置管理器,通过他去获取构造 Configuration

2.2 AbstractConfiguration

抽象配置类,他有很多个实现类,ConfigurationManager 构造的时候返回他,其实实例化的时候由子类来做。

  • 下图是类图,可以看一下他们的关系
2.3 EurekaServerConfig

Eureka Server 的配置类,默认用 DefaultEurekaServerConfig 来实例化,主要是涵盖了 server 的相关配置,用接口的形式对外提供其配置信息

2.4 ApplicationInfoManager

应用管理器,持有 InstanceInfo、EurekaInstanceConfig 的引用,主要是对应用实例做相关的 *** 作

2.5 EurekaClientConfig

客户端的配置,因为 eureka server 其实本身就是一个服务,他自己作为一个客户端向自己注册,如果集群的话,会向其他节点注册

2.6 DiscoveryClient

客户端组件,初始化配置,持有 ApplicationInfoManager 的引用、EurekaClientConfig的引用,还初始化了很多定时任务

2.7 PeerAwareInstanceRegistry

PeerAware,可以识别eureka server集群的:peer,多个同样的东西组成的一个集群,peers集群,peer就是集群中的一个实例

InstanceRegistry:实例注册,服务实例注册,注册表,这个里面放了所有的注册到这个eureka server上来的服务实例,就是一个服务实例的注册表

PeerAwareInstanceRegistry:可以感知eureka server集群的服务实例注册表,eureka client(作为服务实例)过来注册的注册表,而且这个注册表是可以感知到eureka server集群的。假如有一个eureka server集群的话,这里包含了其他的eureka server中的服务实例注册表的信息的。

2.8 PeerEurekaNodes

PeerEurekaNodes,代表了eureka server集群,peers大概来说多个相同的实例组成的一个集群,peer就是peers集群中的一个实例,PeerEurekaNodes,应该是代表的是eureka server集群

2.9 EurekaServerContext

Eureka Server 的上下文对象。持有了 EurekaServcerConfig、ServerCodecs、PeerAwareInstanceRegistry、PeerEurekaNodes、ApplicationInfoManager 的引用。

1、com.netflix.eureka.EurekaBootStrap
// 从类定义可以看出来,实现了 ServletContextListener,所以启动的时候就会调用 contextInitialized 方法
public class EurekaBootStrap implements ServletContextListener
    

public interface ServletContextListener extends EventListener {
	

    public void contextInitialized ( ServletContextEvent sce );

	
    public void contextDestroyed ( ServletContextEvent sce );
}
2、contextInitialized 方法分析
@Override
public void contextInitialized(ServletContextEvent event) {
    try {
        //1、初始化 eureka 环境
        initEurekaEnvironment();
        
        // 2、初始化 eureka 上下文
        initEurekaServerContext();

        ServletContext sc = event.getServletContext();
        sc.setAttribute(EurekaServerContext.class.getName(), serverContext);
    } catch (Throwable e) {
        logger.error("Cannot bootstrap eureka server :", e);
        throw new RuntimeException("Cannot bootstrap eureka server :", e);
    }
}
3、initEurekaEnvironment 分析
protected void initEurekaEnvironment() throws Exception {
    logger.info("Setting the eureka configuration..");
	
    // 这个方法就是初始化配置类。
    String dataCenter = ConfigurationManager.getConfigInstance().getString(EUREKA_DATACENTER);
    if (dataCenter == null) {
        logger.info("Eureka data center value eureka.datacenter is not set, defaulting to default");
        ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_DATACENTER, DEFAULT);
    } else {
        ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_DATACENTER, dataCenter);
    }
    String environment = ConfigurationManager.getConfigInstance().getString(EUREKA_ENVIRONMENT);
    if (environment == null) {
        ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_ENVIRONMENT, TEST);
        logger.info("Eureka environment value eureka.environment is not set, defaulting to test");
    }
}
public static AbstractConfiguration getConfigInstance() {
    // 这里是 double check,单例模式的其中一种方法创建的时候就是这样子的,可以学习一下。
    if (instance == null) {
        synchronized (ConfigurationManager.class) {
            if (instance == null) {
                instance = getConfigInstance(Boolean.getBoolean(DynamicPropertyFactory.DISABLE_DEFAULT_CONFIG));
            }
        }
    }
    return instance;
}

private static AbstractConfiguration getConfigInstance(boolean defaultConfigDisabled) {
    if (instance == null && !defaultConfigDisabled) {	  
        // 创建默认的配置实例
        instance = createDefaultConfigInstance();

        // 注册配置实例
        registerConfigBean();
    }
    return instance;        
}

private static AbstractConfiguration createDefaultConfigInstance() {
    // 这里就是根据配置添加各种 configuration 
    ConcurrentCompositeConfiguration config = new ConcurrentCompositeConfiguration();  
    try {
        DynamicURLConfiguration defaultURLConfig = new DynamicURLConfiguration();
        config.addConfiguration(defaultURLConfig, URL_CONFIG_NAME);
    } catch (Throwable e) {
        logger.warn("Failed to create default dynamic configuration", e);
    }
    if (!Boolean.getBoolean(DISABLE_DEFAULT_SYS_CONFIG)) {
        SystemConfiguration sysConfig = new SystemConfiguration();
        config.addConfiguration(sysConfig, SYS_CONFIG_NAME);
    }
    if (!Boolean.getBoolean(DISABLE_DEFAULT_ENV_CONFIG)) {
        EnvironmentConfiguration envConfig = new EnvironmentConfiguration();
        config.addConfiguration(envConfig, ENV_CONFIG_NAME);
    }
    ConcurrentCompositeConfiguration appOverrideConfig = new ConcurrentCompositeConfiguration();
    config.addConfiguration(appOverrideConfig, APPLICATION_PROPERTIES);
    config.setContainerConfigurationIndex(config.getIndexOfConfiguration(appOverrideConfig));
    return config;
}

至此,初始化环境的方法就执行完成了,其实这个方法就是做一些准备工作,没有太多的核心逻辑。

4、initEurekaServerContext(核心逻辑,重点看一下)
protected void initEurekaServerContext() throws Exception {
		//1、new 一个 EurekaServerConfig 的实例
		
		EurekaServerConfig eurekaServerConfig = new DefaultEurekaServerConfig();

		// 2、下面就是一些 json、xml 相关的东西。这些呢主要是针对请求、响应体作一些转换、序列化 *** 作,不用太多关注
		// For backward compatibility
		JsonXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), XStream.PRIORITY_VERY_HIGH);
		XmlXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), XStream.PRIORITY_VERY_HIGH);

		logger.info("Initializing the eureka client...");
		logger.info(eurekaServerConfig.getJsonCodecName());
		ServerCodecs serverCodecs = new DefaultServerCodecs(eurekaServerConfig);

		ApplicationInfoManager applicationInfoManager = null;

		// 3、实例化 DiscoveryClient
		if (eurekaClient == null) {
			// 3.1 实例化 EurekaInstanceConfig(实例配置)
			EurekaInstanceConfig instanceConfig = isCloud(ConfigurationManager.getDeploymentContext())
							? new CloudInstanceConfig()
							: new MyDataCenterInstanceConfig();

			//3.2 这里就是实例化一个 ApplicationInfoManager(持有 InstanceConfig、InstanceInfo 的引用,主要就是用于实例的一些管理 *** 作)
			applicationInfoManager = new ApplicationInfoManager(
							instanceConfig, new EurekaConfigbasedInstanceInfoProvider(instanceConfig).get());

			// 3.3 实例化 EurekaClientConfig(client 的配置 -> eureka.client.properties 的配置、网络组件的配置-> DefaultEurekaTransportConfig)
			EurekaClientConfig eurekaClientConfig = new DefaultEurekaClientConfig();

			// 3.4 实例化 DiscoveryClient
			
			eurekaClient = new DiscoveryClient(applicationInfoManager, eurekaClientConfig);
		} else {
			applicationInfoManager = eurekaClient.getApplicationInfoManager();
		}

		// 4、实例化 PeerAwareInstanceRegistry(初始化变量赋值、开启 DeltaRetentionTask -> 主要用于过期队列中的实例信息)
		PeerAwareInstanceRegistry registry;
		if (isAws(applicationInfoManager.getInfo())) {
			registry = new AwsInstanceRegistry(
							eurekaServerConfig,
							eurekaClient.getEurekaClientConfig(),
							serverCodecs,
							eurekaClient
			);
			awsBinder = new AwsBinderDelegate(eurekaServerConfig, eurekaClient.getEurekaClientConfig(), registry, applicationInfoManager);
			awsBinder.start();
		} else {
			registry = new PeerAwareInstanceRegistryImpl(
							eurekaServerConfig,
							eurekaClient.getEurekaClientConfig(),
							serverCodecs,
							eurekaClient
			);
		}

		// 5、实例化 PeerEurekaNodes(Eureka 节点信息)
		PeerEurekaNodes peerEurekaNodes = getPeerEurekaNodes(
						registry,
						eurekaServerConfig,
						eurekaClient.getEurekaClientConfig(),
						serverCodecs,
						applicationInfoManager
		);

		// 6、实例化 DefaultEurekaServerContext(Eureka 服务上下文)
		serverContext = new DefaultEurekaServerContext(
						eurekaServerConfig,
						serverCodecs,
						registry,
						peerEurekaNodes,
						applicationInfoManager
		);

		EurekaServerContextHolder.initialize(serverContext);


		// 7、初始化 Eureka 服务上下文
		
		serverContext.initialize();
		logger.info("Initialized server context");

		// 8、从其他的节点 copy 注册表信息
		// Copy registry from neighboring eureka node
		int registryCount = registry.syncUp();

		// 9、开启服务的运行
		
		registry.openForTraffic(applicationInfoManager, registryCount);

		// 10、注册所有的监控、统计
		// Register all monitoring statistics.
		EurekaMonitors.registerAllStats();
	}
5、总结(需要注意的点)

contextInitialized 方法执行完后,服务启动相关的主流程代码就结束了。针对上面的流程主要关注以下几点:

5.1 实例化DiscoveryClient

拉取注册表,后面我们要着重分析一下拉取注册表是一个什么样的逻辑

5.2 实例化 PeerAwareInstanceRegistryImpl

定时任务的开启,我们要关注一下这些定时任务是干啥的?他 *** 作的数据是做啥的?比如 recentCanceledQueue、recentRegisteredQueue

5.3 serverContext.initialize()

eureka 上下文初始化(主要有 eureka server 节点信息的更新、节点更新的定时任务、初始化缓存信息->缓存干啥的怎么用、续约/过期定时任务

5.4 registry.openForTraffic

开启心跳统计的定时任务、以及心跳相关的参数配置 (这些配置跟 eureka 自身的保护机制、以及服务实例的摘除都有密切的关系,后续我们会一一分析)

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5685062.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存