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的啓動順序
- eurekaServerConfig
- jerseyApplication
- jerseyFilterRegistration
- traceFilterRegistration
- peerAwareInstanceRegistry
- peerEurekaNodes
- RefreshablePeerEurekaNodes
- eurekaServerContext
- eurekaServerBootstrap
- EurekaController
- EurekaServerInitializerConfiguration