序
本文主要研究一下spring cloud的EurekaServerInitializerConfiguration
EurekaServerInitializerConfiguration
spring-cloud-netflix-eureka-server-2.0.0.RC1-sources.jar!/org/springframework/cloud/netflix/eureka/server/EurekaServerInitializerConfiguration.java
@Configurationpublic class EurekaServerInitializerConfiguration implements ServletContextAware, SmartLifecycle, Ordered { //...... @Override 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(); } @Override public void stop() { this.running = false; eurekaServerBootstrap.contextDestroyed(this.servletContext); }}复制代码
这里start的时候调用了contextInitialized方法,然后stop的时候,调用contextDestroyed
EurekaServerBootstrap.contextInitialized
spring-cloud-netflix-eureka-server-2.0.0.RC1-sources.jar!/org/springframework/cloud/netflix/eureka/server/EurekaServerBootstrap.java
public void contextInitialized(ServletContext context) { try { initEurekaEnvironment(); initEurekaServerContext(); 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); } }复制代码
这里initEurekaEnvironment初始化环境配置,重点是initEurekaServerContext
EurekaServerBootstrap.initEurekaServerContext
protected void initEurekaServerContext() throws Exception { // For backward compatibility JsonXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), XStream.PRIORITY_VERY_HIGH); XmlXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), XStream.PRIORITY_VERY_HIGH); if (isAws(this.applicationInfoManager.getInfo())) { this.awsBinder = new AwsBinderDelegate(this.eurekaServerConfig, this.eurekaClientConfig, this.registry, this.applicationInfoManager); this.awsBinder.start(); } EurekaServerContextHolder.initialize(this.serverContext); log.info("Initialized server context"); // Copy registry from neighboring eureka node int registryCount = this.registry.syncUp(); this.registry.openForTraffic(this.applicationInfoManager, registryCount); // Register all monitoring statistics. EurekaMonitors.registerAllStats(); }复制代码
这里调用了EurekaServerContextHolder.initialize(this.serverContext),registry.syncUp(),然后registry.openForTraffic
EurekaServerContextHolder.initialize(this.serverContext)
eureka-core-1.8.8-sources.jar!/com/netflix/eureka/EurekaServerContextHolder.java
/** * A static holder for the server context for use in non-DI cases. * * @author David Liu */public class EurekaServerContextHolder { private final EurekaServerContext serverContext; private EurekaServerContextHolder(EurekaServerContext serverContext) { this.serverContext = serverContext; } public EurekaServerContext getServerContext() { return this.serverContext; } private static EurekaServerContextHolder holder; public static synchronized void initialize(EurekaServerContext serverContext) { holder = new EurekaServerContextHolder(serverContext); } public static EurekaServerContextHolder getInstance() { return holder; }}复制代码
主要是给非IOC容器引用EurekaServerContext
syncUp
eureka-core-1.8.8-sources.jar!/com/netflix/eureka/registry/PeerAwareInstanceRegistryImpl.java
/** * Populates the registry information from a peer eureka node. This * operation fails over to other nodes until the list is exhausted if the * communication fails. */ @Override public int syncUp() { // Copy entire entry from neighboring DS node int count = 0; for (int i = 0; ((i < serverConfig.getRegistrySyncRetries()) && (count == 0)); i++) { if (i > 0) { try { Thread.sleep(serverConfig.getRegistrySyncRetryWaitMs()); } catch (InterruptedException e) { logger.warn("Interrupted during registry transfer.."); break; } } Applications apps = eurekaClient.getApplications(); for (Application app : apps.getRegisteredApplications()) { for (InstanceInfo instance : app.getInstances()) { try { if (isRegisterable(instance)) { register(instance, instance.getLeaseInfo().getDurationInSecs(), true); count++; } } catch (Throwable t) { logger.error("During DS init copy", t); } } } } return count; }复制代码
这里通过client获取其他一个eureka server的实例信息,然后isReplication=true执行instance的注册操作
openForTraffic
Override public void openForTraffic(ApplicationInfoManager applicationInfoManager, int count) { // Renewals happen every 30 seconds and for a minute it should be a factor of 2. this.expectedNumberOfRenewsPerMin = count * 2; this.numberOfRenewsPerMinThreshold = (int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold()); logger.info("Got {} instances from neighboring DS node", count); logger.info("Renew threshold is: {}", numberOfRenewsPerMinThreshold); this.startupTime = System.currentTimeMillis(); if (count > 0) { this.peerInstancesTransferEmptyOnStartup = false; } DataCenterInfo.Name selfName = applicationInfoManager.getInfo().getDataCenterInfo().getName(); boolean isAws = Name.Amazon == selfName; if (isAws && serverConfig.shouldPrimeAwsReplicaConnections()) { logger.info("Priming AWS connections for all replicas.."); primeAwsReplicas(applicationInfoManager); } logger.info("Changing status to UP"); applicationInfoManager.setInstanceStatus(InstanceStatus.UP); super.postInit(); }复制代码
openForTraffic主要是把自身(
eureka server
)标识为UP状态,然后可以开始接收请求。
eurekaServerBootstrap.contextDestroyed
public void contextDestroyed(ServletContext context) { try { log.info("Shutting down Eureka Server.."); context.removeAttribute(EurekaServerContext.class.getName()); destroyEurekaServerContext(); destroyEurekaEnvironment(); } catch (Throwable e) { log.error("Error shutting down eureka", e); } log.info("Eureka Service is now shutdown..."); } /** * Server context shutdown hook. Override for custom logic */ protected void destroyEurekaServerContext() throws Exception { EurekaMonitors.shutdown(); if (this.awsBinder != null) { this.awsBinder.shutdown(); } if (this.serverContext != null) { this.serverContext.shutdown(); } }复制代码
这里销毁上下文和环境变量,注意这里有个this.serverContext != null判断,也就是如果serverContext已经被销毁了,那就不会再调用了。
小结
EurekaServerInitializerConfiguration主要是实现了Lifecycle方法,初始化servlet相关上下文,在start的时候调用EurekaServerBootstrap.contextInitialized,在stop的时候调用eurekaServerBootstrap.contextDestroyed,都是借助eurekaServerBootstrap类来实现。而eurekaServerBootstrap里头部分调用了EurekaServerContext。
EurekaServerBootstrap.contextInitialized这里有两个重要的动作registry.syncUp()以及registry.openForTraffic
- registry.syncUp()从其他eureka server获取实例信息,然后注册到本server,然后复制到其他server
- registry.openForTraffic()标识自身server的状态为UP,表示可以开始接收请求