Spring中的EurekaServer启动详解
作者:dalianpai
EurekaServer启动
看方法上的注释,初始化eureka,包含eureka集群的同步和发布注册,这个方法时重写ServletContextListener#contextInitialized,是eureka启动的入口了。
在 Servlet 容器( 例如 Tomcat、Jetty )启动时,调用 #contextInitialized() 方法。
/** * Initializes Eureka, including syncing up with other Eureka peers and publishing the registry. * * @see * javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent) */ @Override public void contextInitialized(ServletContextEvent event) { try { //初始化eureka环境信息 initEurekaEnvironment(); //初始化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); } }
初始化eureka的环境
private static final String TEST = "test"; private static final String ARCHAIUS_DEPLOYMENT_ENVIRONMENT = "archaius.deployment.environment"; private static final String EUREKA_ENVIRONMENT = "eureka.environment"; private static final String CLOUD = "cloud"; private static final String DEFAULT = "default"; private static final String ARCHAIUS_DEPLOYMENT_DATACENTER = "archaius.deployment.datacenter"; private static final String EUREKA_DATACENTER = "eureka.datacenter"; 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"); } }
在ConfigurationManager.getConfigInstance()中,其实就是初始化ConfigurationManager的实例
(1)创建一个ConcurrentCompositeConfiguration实例,代表了所谓的配置,包括了eureka需要的所有的配置。在初始化这个实例的时候,调用了clear()方法,fireEvent()发布了一个事件(EVENT_CLEAR),fireEvent()这个方法其实是父类的方法,牵扯比较复杂的另外一个项目(ConfigurationManager本身不是属于eureka的源码,是属于netflix config项目的源码)。
/** * Creates an empty CompositeConfiguration object which can then * be added some other Configuration files */ public ConcurrentCompositeConfiguration() { clear(); } @Override public final void clear() { fireEvent(EVENT_CLEAR, null, null, true); configList.clear(); namedConfigurations.clear(); // recreate the in memory configuration containerConfiguration = new ConcurrentMapConfiguration(); containerConfiguration.setThrowExceptionOnMissing(isThrowExceptionOnMissing()); containerConfiguration.setListDelimiter(getListDelimiter()); containerConfiguration.setDelimiterParsingDisabled(isDelimiterParsingDisabled()); containerConfiguration.addConfigurationListener(eventPropagater); configList.add(containerConfiguration); overrideProperties = new ConcurrentMapConfiguration(); overrideProperties.setThrowExceptionOnMissing(isThrowExceptionOnMissing()); overrideProperties.setListDelimiter(getListDelimiter()); overrideProperties.setDelimiterParsingDisabled(isDelimiterParsingDisabled()); overrideProperties.addConfigurationListener(eventPropagater); fireEvent(EVENT_CLEAR, null, null, false); containerConfigurationChanged = false; invalidate(); }
(2)就是往上面的那个ConcurrentCompositeConfiguration实例加入了一堆别的config,然后搞完了以后,就直接返回了这个实例,就是作为所谓的那个配置的单例
(3)初始化数据中心的配置,如果没有配置的话,就是DEFAULT data center
(4)初始化eurueka运行的环境,如果你没有配置的话,默认就给你设置为test环境
(5)initEurekaEnvironment的初始化环境的逻辑
初始化eureka的上下文
/** * init hook for server context. Override for custom logic. */ protected void initEurekaServerContext() throws Exception { //加载eureka-server。properties文件的配置 EurekaServerConfig eurekaServerConfig = new DefaultEurekaServerConfig(); // 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,对应的其实是一个eureka-client。 ApplicationInfoManager applicationInfoManager = null; //初始化eureka-server内部的一个eureka-client,用来和其他eureka-server节点用来注册通信的 if (eurekaClient == null) { //CommonConstants. 用来获取client信息 EurekaInstanceConfig instanceConfig = isCloud(ConfigurationManager.getDeploymentContext()) ? new CloudInstanceConfig() : new MyDataCenterInstanceConfig(); applicationInfoManager = new ApplicationInfoManager( instanceConfig, new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get()); EurekaClientConfig eurekaClientConfig = new DefaultEurekaClientConfig(); eurekaClient = new DiscoveryClient(applicationInfoManager, eurekaClientConfig); } else { applicationInfoManager = eurekaClient.getApplicationInfoManager(); } //处理注册的相关事情 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 ); } //处理peer节点 PeerEurekaNodes peerEurekaNodes = getPeerEurekaNodes( registry, eurekaServerConfig, eurekaClient.getEurekaClientConfig(), serverCodecs, applicationInfoManager ); //完成eureka-server上下文的构建以及初始化过程 serverContext = new DefaultEurekaServerContext( eurekaServerConfig, serverCodecs, registry, peerEurekaNodes, applicationInfoManager ); EurekaServerContextHolder.initialize(serverContext); serverContext.initialize(); logger.info("Initialized server context"); // 第六步,处理一点善后的事情,从相邻的eureka节点拷贝注册信息 int registryCount = registry.syncUp(); //这个方法就是打开注册表,可以接收请求 registry.openForTraffic(applicationInfoManager, registryCount); // 注册所有的监控 EurekaMonitors.registerAllStats(); }
配置文件读取
public DefaultEurekaServerConfig() { init(); } private void init() { String env = ConfigurationManager.getConfigInstance().getString( EUREKA_ENVIRONMENT, TEST); ConfigurationManager.getConfigInstance().setProperty( ARCHAIUS_DEPLOYMENT_ENVIRONMENT, env); String eurekaPropsFile = EUREKA_PROPS_FILE.get(); try { // ConfigurationManager // .loadPropertiesFromResources(eurekaPropsFile); ConfigurationManager .loadCascadedPropertiesFromResources(eurekaPropsFile); } catch (IOException e) { logger.warn( "Cannot find the properties specified : {}. This may be okay if there are other environment " + "specific properties or the configuration is installed with a different mechanism.", eurekaPropsFile); } }
加载eureka-server.properties的过程
(1)创建了一个DefaultEurekaServerConfig对象
(2)创建DefaultEurekaServerConfig对象的时候,在里面会有一个init方法
(3)先是将eureka-server.properties中的配置加载到了一个Properties对象中,然后将Properties对象中的配置放到ConfigurationManager中去,此时ConfigurationManager中去就有了所有的配置了
(4)然后DefaultEurekaServerConfig提供的获取配置项的各个方法,都是通过硬编码的配置项名称,从DynamicPropertyFactory中获取配置项的值,DynamicPropertyFactory是从ConfigurationManager那儿来的,所以也包含了所有配置项的值
(5)在获取配置项的时候,如果没有配置,那么就会有默认的值,全部属性都是有默认值的
创建 Eureka-Server 请求和响应编解码器
logger.info("Initializing the eureka client..."); logger.info(eurekaServerConfig.getJsonCodecName()); ServerCodecs serverCodecs = new DefaultServerCodecs(eurekaServerConfig);
创建Eureka-Client
//初始化一个ApplicationInfoManager,对应的其实是一个eureka-client。 ApplicationInfoManager applicationInfoManager = null; //初始化eureka-server内部的一个eureka-client,用来和其他eureka-server节点用来注册通信的 if (eurekaClient == null) { //CommonConstants. 用来获取client信息 EurekaInstanceConfig instanceConfig = isCloud(ConfigurationManager.getDeploymentContext()) ? new CloudInstanceConfig() : new MyDataCenterInstanceConfig(); applicationInfoManager = new ApplicationInfoManager( instanceConfig, new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get()); EurekaClientConfig eurekaClientConfig = new DefaultEurekaClientConfig(); eurekaClient = new DiscoveryClient(applicationInfoManager, eurekaClientConfig); } else { applicationInfoManager = eurekaClient.getApplicationInfoManager(); }
在new MyDataCenterInstanceConfig()这个无参构造中,最终会去读取eureka-client.properties的配置,去提供一些默认值。
因为eureka-server本身也是一个eureka-client,因为当组成集群的时候,它自己也要向别的服务端进行注册
//初始化一个ApplicationInfoManager,对应的其实是一个eureka-client。 ApplicationInfoManager applicationInfoManager = null; //初始化eureka-server内部的一个eureka-client,用来和其他eureka-server节点用来注册通信的 if (eurekaClient == null) { //CommonConstants. 用来获取client信息 EurekaInstanceConfig instanceConfig = isCloud(ConfigurationManager.getDeploymentContext()) ? new CloudInstanceConfig() : new MyDataCenterInstanceConfig(); applicationInfoManager = new ApplicationInfoManager( instanceConfig, new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get()); EurekaClientConfig eurekaClientConfig = new DefaultEurekaClientConfig(); eurekaClient = new DiscoveryClient(applicationInfoManager, eurekaClientConfig); } else { applicationInfoManager = eurekaClient.getApplicationInfoManager(); }
初始化 EurekaServerContextHolder
EurekaServerContextHolder.initialize(serverContext);
初始化 Eureka-Server 上下文
@PostConstruct @Override public void initialize() { logger.info("Initializing ..."); //启动 Eureka-Server 集群节点集合(复制) peerEurekaNodes.start(); try { // 初始化 应用实例信息的注册表 registry.init(peerEurekaNodes); } catch (Exception e) { throw new RuntimeException(e); } logger.info("Initialized"); }
从其他 Eureka-Server 拉取注册信息
// 第六步,处理一点善后的事情,从相邻的eureka节点拷贝注册信息 int registryCount = registry.syncUp(); //这个方法就是打开注册表,可以接收请求 registry.openForTraffic(applicationInfoManager, registryCount);
注册监控
EurekaMonitors.registerAllStats();
到此这篇关于Spring中的EurekaServer启动详解的文章就介绍到这了,更多相关EurekaServer启动内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!