在開始本篇文章之前,我想你對SpringCloud和SpringBoot的基本使用已經比較熟悉了,如果不熟悉的話可以參考我之前寫過的文章 本篇文章的源碼基於SpringBoot2.0,SpringCloud的Finchley.RELEASE 註解 我們知道,在使用Eureka作為註冊中心的時候,我們 ...
在開始本篇文章之前,我想你對SpringCloud和SpringBoot的基本使用已經比較熟悉了,如果不熟悉的話可以參考我之前寫過的文章
本篇文章的源碼基於SpringBoot2.0,SpringCloud的Finchley.RELEASE
@EnableEurekaServer
註解
我們知道,在使用Eureka作為註冊中心的時候,我們會在啟動類中增加一個@EnableEurekaServer
註解,這個註解我們是一個自定義的EnableXXX系列的註解,主要作用我們之前也多次提到了,就是引入配置類而已。看一下源碼吧
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({EurekaServerMarkerConfiguration.class})
public @interface EnableEurekaServer {
}
引入了一個配置類EurekaServerMarkerConfiguration
,看一下這個類的具體內容
@Configuration
public class EurekaServerMarkerConfiguration {
@Bean
public Marker eurekaServerMarkerBean() {
return new Marker();
}
class Marker {
}
}
現在看這裡好像難以理解,這是啥意思,搞個空的類幹啥的,不要著急,接著往下看
自動裝配
既然註解上沒有找到我們想要的東西,那麼就看一下spring.factories
文件吧,這裡自動配置的實現類是EurekaServerAutoConfiguration
由於這個類涉及的代碼實在是太多了,這裡就不貼了,咱們直接來解析這個類:
1. 引入EurekaServerInitializerConfiguration類
看名字就知道了這個類是負責Eureka的初始化工作的,這個類實現了SmartLifecycle
介面,所以在spring初始化和銷毀的時候,就會分別調用它的start和stop方法
首先看一下start方法
public void start() {
new Thread(new Runnable() {
@Override
public void run() {
try {
//啟動EurekaServer
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();
}
這個代碼好像比較直接了當啊,直接就起個線程啟動了EurekaServer,然後發佈了一些啟動事件,來看啟動的過程吧
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);
}
}
這裡一共包含初始化環境和初始化上下文兩個分支
初始化執行環境
這個不是很重要,可以過濾掉
protected void initEurekaEnvironment() throws Exception {
log.info("Setting the eureka configuration..");
//AWS相關的東西,可以忽略
String dataCenter = ConfigurationManager.getConfigInstance()
.getString(EUREKA_DATACENTER);
if (dataCenter == null) {
log.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);
}
//設置 Eureka 環境,預設為test
String environment = ConfigurationManager.getConfigInstance()
.getString(EUREKA_ENVIRONMENT);
if (environment == null) {
ConfigurationManager.getConfigInstance()
.setProperty(ARCHAIUS_DEPLOYMENT_ENVIRONMENT, TEST);
log.info(
"Eureka environment value eureka.environment is not set, defaulting to test");
}
else {
ConfigurationManager.getConfigInstance()
.setProperty(ARCHAIUS_DEPLOYMENT_ENVIRONMENT, environment);
}
}
初始化上下文
protected void initEurekaServerContext() throws Exception {
// 設置json與xml序列化工具
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");
// 同步Eureka集群數據
int registryCount = this.registry.syncUp();
this.registry.openForTraffic(this.applicationInfoManager, registryCount);
// 註冊監控統計信息
EurekaMonitors.registerAllStats();
}
這個方法中同步集群數據和註冊監控信息都涉及的內容比較多,所以本篇文章就不再展開了,請關註我留意後續文章
@ConditionalOnBean({Marker.class})
看到這裡就揭開了開篇@EnableEurekaServer
註解註入的那個bean的含義了。也就是說如果咱們的啟動類沒有使用@EnableEurekaServer
註解的話,這個自動配置類就不會執行,那也就沒有Eureka的事了
@EnableConfigurationProperties({EurekaDashboardProperties.class, InstanceRegistryProperties.class})
深入這個註解發現這個還是使用的@Import
註解的機制引入了兩個類,這個註解在之前的源碼解析文章中也多次提到了,這裡就不展開了
EurekaDashboardProperties
這個類比較簡單,主要是Eureka的控制台的相關配置
//控制台預設路徑
private String path = "/";
//是否開啟控制台
private boolean enabled = true;
InstanceRegistryProperties
,這個類是控制Eureka的註冊時的配置信息
//每分鐘續約次數
@Value("${eureka.server.expectedNumberOfRenewsPerMin:1}")
private int expectedNumberOfRenewsPerMin = 1;
//預設打開的通信數量
@Value("${eureka.server.defaultOpenForTrafficCount:1}")
private int defaultOpenForTrafficCount = 1;
@PropertySource("classpath:/eureka/server.properties")
相信大家比較熟悉這個註解,載入Eureka的配置文件而已
配置文件中也僅僅只包含這個信息
spring.http.encoding.force=false
自動註入的bean
EurekaServerAutoConfiguration
類上幾個註解就解析完了,接著看一下這個類中註入的幾個比較重要的類吧
配置類EurekaServerConfigBeanConfiguration
EurekaServerConfig
如果當前應用允許註冊到其他Eureka服務中時,也就是屬性eureka.client.fetch-registry
為true時。就設置屬性registrySyncRetries
的值為5,這個屬性的意思是當Eureka伺服器啟動時嘗試去獲取集群里其他伺服器上的註冊信息的次數
EurekaController
這個就是Eureka自己的controller了,控制台的相關信息就是從這裡獲取的
ServerCodecs
設置Eureka的序列化工具
PeerAwareInstanceRegistry
集群註冊信息同步相關的類,請期待後續深入解析文章
FilterRegistrationBean
EurekaServer接受請求的一個攔截器,感興趣的同學可以研究一下