Eureka Server源码分析(1)从@EnableEurekaServer注解开始分析

本文深入分析了Eureka Server的启动流程,从@EnableEurekaServer注解开始,详细解析了EurekaServerAutoConfiguration类中各Bean的启动顺序及作用,包括EurekaServerConfigBean初始化、EurekaController接口提供、PeerAwareInstanceRegistry节点同步服务、PeerEurekaNodes节点生命周期管理等关键组件的创建过程。

Eureka启动源码分析

我们从@EnableEurekaServer注解开始分析

1.Eureka Server启动分析

1.1找到@EnableEurekaServer的实现类 EurekaServerAutoConfiguration
1.2分析EurekaServerInitializerConfiguration(eureka配置的加载类)

@Configuration
//EurekaServer配置
@Import(EurekaServerInitializerConfiguration.class)
//启动配置。
@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)
//加载EurekaDashboardProperties和InstanceRegistryProperties配置
@EnableConfigurationProperties({ EurekaDashboardProperties.class,
		InstanceRegistryProperties.class })
@PropertySource("classpath:/eureka/server.properties")
public class EurekaServerAutoConfiguration extends WebMvcConfigurerAdapter {
	/**
	 * 省略大部分代码,仅抽取一些关键的代码片段
	 */

	//EurekaServerConfigBean初始化,设置Eureka相互注册 
	@Configuration
	protected static class EurekaServerConfigBeanConfiguration {
		@Bean
		@ConditionalOnMissingBean
		public EurekaServerConfig eurekaServerConfig(EurekaClientConfig clientConfig) {
			EurekaServerConfigBean server = new EurekaServerConfigBean();
			if (clientConfig.shouldRegisterWithEureka()) {
				// Set a sensible default if we are supposed to replicate
				server.setRegistrySyncRetries(5);
			}
			return server;
		}
	}
	//初始化EurekaController,提供访问接口 
	@Bean
	@ConditionalOnProperty(prefix = "eureka.dashboard", name = "enabled", matchIfMissing = true)
	public EurekaController eurekaController() {
		return new EurekaController(this.applicationInfoManager);
	}
	

	//省略编码和解码,json解析
	
	//实例化了eureka多个服务维持节点同步的bean(PeerAwareInstanceRegistry );以及每个eureka服务节点的生命周期管理(PeerEurekaNodes );
	@Bean
	public PeerAwareInstanceRegistry peerAwareInstanceRegistry(
			ServerCodecs serverCodecs) {
		this.eurekaClient.getApplications(); // force initialization
		return new InstanceRegistry(this.eurekaServerConfig, this.eurekaClientConfig,
				serverCodecs, this.eurekaClient,
				this.instanceRegistryProperties.getExpectedNumberOfRenewsPerMin(),
				this.instanceRegistryProperties.getDefaultOpenForTrafficCount());
	}

	@Bean
	@ConditionalOnMissingBean
	public PeerEurekaNodes peerEurekaNodes(PeerAwareInstanceRegistry registry,
			ServerCodecs serverCodecs) {
		return new RefreshablePeerEurekaNodes(registry, this.eurekaServerConfig,
				this.eurekaClientConfig, serverCodecs, this.applicationInfoManager);
	}
	

	static class RefreshablePeerEurekaNodes extends PeerEurekaNodes
			implements ApplicationListener<EnvironmentChangeEvent> {

		public RefreshablePeerEurekaNodes(
				final PeerAwareInstanceRegistry registry,
				final EurekaServerConfig serverConfig,
				final EurekaClientConfig clientConfig, 
				final ServerCodecs serverCodecs,
				final ApplicationInfoManager applicationInfoManager) {
			super(registry, serverConfig, clientConfig, serverCodecs, applicationInfoManager);
		}

		@Override
		public void onApplicationEvent(final EnvironmentChangeEvent event) {
			if (shouldUpdate(event.getKeys())) {
				updatePeerEurekaNodes(resolvePeerUrls());
			}
		}
		
		/*
		 * 检查配置是否发生变化,
		 */
		protected boolean shouldUpdate(final Set<String> changedKeys) {
			assert changedKeys != null;
			
			// if eureka.client.use-dns-for-fetching-service-urls is true, then
			// service-url will not be fetched from environment.
			if (clientConfig.shouldUseDnsForFetchingServiceUrls()) {
				return false;
			}
			
			if (changedKeys.contains("eureka.client.region")) {
				return true;
			}
			
			for (final String key : changedKeys) {
				// property keys are not expected to be null.
				if (key.startsWith("eureka.client.service-url.") ||
					key.startsWith("eureka.client.availability-zones.")) {
					return true;
				}
			}
			
			return false;
		}
	}

	@Bean
	public EurekaServerContext eurekaServerContext(ServerCodecs serverCodecs,
			PeerAwareInstanceRegistry registry, PeerEurekaNodes peerEurekaNodes) {
		return new DefaultEurekaServerContext(this.eurekaServerConfig, serverCodecs,
				registry, peerEurekaNodes, this.applicationInfoManager);
	}

	// EurekaServer的引导程序(提供其他类调用,去实现),通过tomcat管理eureka的生命周期;
	@Bean
	public EurekaServerBootstrap eurekaServerBootstrap(){}


	//省略Jersey,类似于springmvc的框架,restFul风格
}

2. EurekaServerInitializerConfiguration(eureka配置文件的加载逻辑)

2.1启动一个线程去读取配置文件,主要初始化服务环境,配置信息;初始化了eureka服务端的上下文,并发布通知eureka注册成功事件和eureka启动事件。初始化EurekaRegistryAvailableEvent和EurekaServerStartedEvent

@Override
public void start() {
new Thread(new Runnable() {
	@Override
	public void run() {
		try {
			
			
			//1.上下文初始化
			eurekaServerBootstrap.contextInitialized(EurekaServerInitializerConfiguration.this.servletContext);
			log.info("Started Eureka Server");
			//2.广播注册事件
			publish(new EurekaRegistryAvailableEvent(getEurekaServerConfig()));
			EurekaServerInitializerConfiguration.this.running = true;
			//3.广播EurekaServer启动事件
			publish(new EurekaServerStartedEvent(getEurekaServerConfig()));
		}
		catch (Exception ex) {
			// Help!
			log.error("Could not initialize Eureka servlet context", ex);
		}
	}
}).start();
}

//1.上下文初始化
public void contextInitialized(ServletContext context) {
		try {
			//1.1初始化环境配置文件
			initEurekaEnvironment();
			//这个方法中有一个syncUp()函数用于注册peer实例
			//1.2初始化EurekaServer上下文
			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);
		}
	}
	
	//1.2初始化EurekaServer上下文
	protected void initEurekaServerContext() throws Exception {
		//1.2.1省略Json流和XMl流解析器的初始化
		
		//1.2.2省略aws事件
		
		//1.2.3真正初始化server context
		EurekaServerContextHolder.initialize(this.serverContext);

		log.info("Initialized server context");

		//1.2.4 从相邻的Eureka节点复制注册表(重要)
		int registryCount = this.registry.syncUp();
		//1.2.5 设置一些参数和打印日志,设置从其他Server中获取的服务状态为up,
		//开启一些定时任务。(重要)
		this.registry.openForTraffic(this.applicationInfoManager, registryCount);

		//1.2.6 监控jmx支持的注册表.
		EurekaMonitors.registerAllStats();
	}
	//1.2.4 从相邻的Eureka节点复制注册表(重要),有过期时间的就不修改,没有则创建
	@Override
    public int syncUp() {
        //计算获取的注册实例数目
        int count = 0;
		//1.2.4.1将注册实例注册
        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;
    }
    //1.2.5 开启的定时任务
    protected void postInit() {
        renewsLastMin.start();
        if (evictionTaskRef.get() != null) {
            evictionTaskRef.get().cancel();
        }
        evictionTaskRef.set(new EvictionTask());
        evictionTimer.schedule(evictionTaskRef.get(),
                serverConfig.getEvictionIntervalTimerInMs(),
                serverConfig.getEvictionIntervalTimerInMs());
    }

介绍一下EurekaServerAutoConfiguration类中的Bean的启动顺序

  1. eurekaServerConfig
  2. jerseyApplication
  3. jerseyFilterRegistration
  4. traceFilterRegistration
  5. peerAwareInstanceRegistry
  6. peerEurekaNodes
  7. RefreshablePeerEurekaNodes
  8. eurekaServerContext
  9. eurekaServerBootstrap
  10. EurekaController
  11. EurekaServerInitializerConfiguration
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值