- 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
1、整体流程图 2、相应的类概念说明 2.1 ConfigurationManagereureka server 启动的话,其实就相当于根据 web.xml 启动容器,然后对外提供服务,所以我们就从启动类作为入口分析
2.2 AbstractConfiguration配置管理器,通过他去获取构造 Configuration
抽象配置类,他有很多个实现类,ConfigurationManager 构造的时候返回他,其实实例化的时候由子类来做。
- 下图是类图,可以看一下他们的关系
2.4 ApplicationInfoManagerEureka Server 的配置类,默认用 DefaultEurekaServerConfig 来实例化,主要是涵盖了 server 的相关配置,用接口的形式对外提供其配置信息
2.5 EurekaClientConfig应用管理器,持有 InstanceInfo、EurekaInstanceConfig 的引用,主要是对应用实例做相关的 *** 作
2.6 DiscoveryClient客户端的配置,因为 eureka server 其实本身就是一个服务,他自己作为一个客户端向自己注册,如果集群的话,会向其他节点注册
2.7 PeerAwareInstanceRegistry客户端组件,初始化配置,持有 ApplicationInfoManager 的引用、EurekaClientConfig的引用,还初始化了很多定时任务
2.8 PeerEurekaNodesPeerAware,可以识别eureka server集群的:peer,多个同样的东西组成的一个集群,peers集群,peer就是集群中的一个实例
InstanceRegistry:实例注册,服务实例注册,注册表,这个里面放了所有的注册到这个eureka server上来的服务实例,就是一个服务实例的注册表
PeerAwareInstanceRegistry:可以感知eureka server集群的服务实例注册表,eureka client(作为服务实例)过来注册的注册表,而且这个注册表是可以感知到eureka server集群的。假如有一个eureka server集群的话,这里包含了其他的eureka server中的服务实例注册表的信息的。
2.9 EurekaServerContextPeerEurekaNodes,代表了eureka server集群,peers大概来说多个相同的实例组成的一个集群,peer就是peers集群中的一个实例,PeerEurekaNodes,应该是代表的是eureka server集群
1、com.netflix.eureka.EurekaBootStrapEureka Server 的上下文对象。持有了 EurekaServcerConfig、ServerCodecs、PeerAwareInstanceRegistry、PeerEurekaNodes、ApplicationInfoManager 的引用。
// 从类定义可以看出来,实现了 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、总结(需要注意的点)
5.1 实例化DiscoveryClientcontextInitialized 方法执行完后,服务启动相关的主流程代码就结束了。针对上面的流程主要关注以下几点:
5.2 实例化 PeerAwareInstanceRegistryImpl拉取注册表,后面我们要着重分析一下拉取注册表是一个什么样的逻辑
5.3 serverContext.initialize()定时任务的开启,我们要关注一下这些定时任务是干啥的?他 *** 作的数据是做啥的?比如 recentCanceledQueue、recentRegisteredQueue
5.4 registry.openForTrafficeureka 上下文初始化(主要有 eureka server 节点信息的更新、节点更新的定时任务、初始化缓存信息->缓存干啥的怎么用、续约/过期定时任务
开启心跳统计的定时任务、以及心跳相关的参数配置 (这些配置跟 eureka 自身的保护机制、以及服务实例的摘除都有密切的关系,后续我们会一一分析)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)