Spring Cloud Netflix Eureka項目將Netflix公司的Eureka項目加以封裝,以適配Spring Boot自動化配置的機制,通過注解在Spring Boot項目啟動時啟動Eureka Server。
我們通過閱讀相關源碼,看看這一過程是如何實現的。
回顧我們的eureka-demo中的eureka-server項目,在我們的項目啟動類Server上有一個@EnableEurekaServer注解。
@SpringBootApplication
@EnableEurekaServer
public class Server {
//...
}
查看這個注解的定義
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EurekaServerMarkerConfiguration.class)
public @interface EnableEurekaServer {
}
可以看到它Import導入了EurekaServerMarkerConfiguration類
@Configuration
public class EurekaServerMarkerConfiguration {
@Bean
public Marker eurekaServerMarkerBean() {
return new Marker();
}
class Marker {
}
}
這個EurekaServerMarkerConfiguration會往Spring容器中注入一個eurekaServerMarkerBean,這個Marker是一個空類,那在這里起到什么作用呢?
仔細查看這個類的注釋,可以看到它只是一個開關標記,用來激活EurekaServerAutoConfiguration類的。
/**
* Responsible for adding in a marker bean to activate
* {@link EurekaServerAutoConfiguration}
*
* @author Biju Kunjummen
*/
查看EurekaServerAutoConfiguration類的定義
@Configuration
@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)
@EnableConfigurationProperties({ EurekaDashboardProperties.class,
InstanceRegistryProperties.class })
@PropertySource("classpath:/eureka/server.properties")
public class EurekaServerAutoConfiguration extends WebMvcConfigurerAdapter
- @Configuration注解表示這是一個配置類,通過@Bean注解聲明一些注入到Spring IOC容器中的Bean。
- @ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class),表示只要Spring容器中有EurekaServerMarkerConfiguration.Marker.class類的實例存在,那么就會將這個EurekaServerAutoConfiguration也注入到Spring容器中。
- @Import(EurekaServerInitializerConfiguration.class)表明它導入了EurekaServerInitializerConfiguration這個類。
- 此外,這個EurekaServerAutoConfiguration繼承自WebMvcConfigurer,可以用來定義Spring MVC的一些配置。
在這個類中,我們并沒有發現與啟動Eureka相關的代碼,那么我們來看看它引入的這個EurekaServerInitializerConfiguration。
@Configuration
public class EurekaServerInitializerConfiguration
implements ServletContextAware, SmartLifecycle, Ordered {
可以看到,這也是一個配置類,同時它實現了ServletContextAware接口,可以在Servlet容器啟動后得到ServletContext容器上下文;它還實現了SmartLifecycle,這樣在spring 生命周期中會調用這個類相關的方法。比如在spring初始化時,會調用它start方法。
@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();
}
start方法中啟動了一個后臺線程,它會執行這一行代碼。
eurekaServerBootstrap.contextInitialized(EurekaServerInitializerConfiguration.this.servletContext);
eurekaServerBootstrap是EurekaServerInitializerConfiguration類的成員變量,對應的類是EurekaServerBootstrap。
來看看這個類的contextInitialized方法
public void contextInitialized(ServletContext context) {
try {
initEurekaEnvironment();//初始化Eureka運行環境
initEurekaServerContext();//初始化Eureka運行上下文
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(),初始化Eureka運行環境;調用了initEurekaServerContext(),初始化Eureka運行上下文。關于這兩個方法的細節,我們在后面的文章再細說。
至此Eureka Server就隨著Spring容器的一起啟起了。
相關流程圖如下: