Spring Cloud Netflix Eureka項(xiàng)目將Netflix公司的Eureka項(xiàng)目加以封裝彼水,以適配Spring Boot自動(dòng)化配置的機(jī)制阀趴,通過注解在Spring Boot項(xiàng)目啟動(dòng)時(shí)啟動(dòng)Eureka Server巫橄。
我們通過閱讀相關(guān)源碼,看看這一過程是如何實(shí)現(xiàn)的。
回顧我們的eureka-demo中的eureka-server項(xiàng)目壳坪,在我們的項(xiàng)目啟動(dòng)類Server上有一個(gè)@EnableEurekaServer注解暇昂。
@SpringBootApplication
@EnableEurekaServer
public class Server {
//...
}
查看這個(gè)注解的定義
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EurekaServerMarkerConfiguration.class)
public @interface EnableEurekaServer {
}
可以看到它Import導(dǎo)入了EurekaServerMarkerConfiguration類
@Configuration
public class EurekaServerMarkerConfiguration {
@Bean
public Marker eurekaServerMarkerBean() {
return new Marker();
}
class Marker {
}
}
這個(gè)EurekaServerMarkerConfiguration會(huì)往Spring容器中注入一個(gè)eurekaServerMarkerBean莺戒,這個(gè)Marker是一個(gè)空類,那在這里起到什么作用呢急波?
仔細(xì)查看這個(gè)類的注釋从铲,可以看到它只是一個(gè)開關(guān)標(biāo)記,用來激活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注解表示這是一個(gè)配置類名段,通過@Bean注解聲明一些注入到Spring IOC容器中的Bean阱扬。
- @ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class),表示只要Spring容器中有EurekaServerMarkerConfiguration.Marker.class類的實(shí)例存在伸辟,那么就會(huì)將這個(gè)EurekaServerAutoConfiguration也注入到Spring容器中麻惶。
- @Import(EurekaServerInitializerConfiguration.class)表明它導(dǎo)入了EurekaServerInitializerConfiguration這個(gè)類。
- 此外信夫,這個(gè)EurekaServerAutoConfiguration繼承自WebMvcConfigurer窃蹋,可以用來定義Spring MVC的一些配置。
在這個(gè)類中忙迁,我們并沒有發(fā)現(xiàn)與啟動(dòng)Eureka相關(guān)的代碼脐彩,那么我們來看看它引入的這個(gè)EurekaServerInitializerConfiguration。
@Configuration
public class EurekaServerInitializerConfiguration
implements ServletContextAware, SmartLifecycle, Ordered {
可以看到姊扔,這也是一個(gè)配置類惠奸,同時(shí)它實(shí)現(xiàn)了ServletContextAware接口,可以在Servlet容器啟動(dòng)后得到ServletContext容器上下文恰梢;它還實(shí)現(xiàn)了SmartLifecycle佛南,這樣在spring 生命周期中會(huì)調(diào)用這個(gè)類相關(guān)的方法。比如在spring初始化時(shí)嵌言,會(huì)調(diào)用它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方法中啟動(dòng)了一個(gè)后臺(tái)線程,它會(huì)執(zhí)行這一行代碼摧茴。
eurekaServerBootstrap.contextInitialized(EurekaServerInitializerConfiguration.this.servletContext);
eurekaServerBootstrap是EurekaServerInitializerConfiguration類的成員變量绵载,對(duì)應(yīng)的類是EurekaServerBootstrap。
來看看這個(gè)類的contextInitialized方法
public void contextInitialized(ServletContext context) {
try {
initEurekaEnvironment();//初始化Eureka運(yùn)行環(huán)境
initEurekaServerContext();//初始化Eureka運(yùn)行上下文
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);
}
}
這個(gè)方法調(diào)用了initEurekaEnvironment()苛白,初始化Eureka運(yùn)行環(huán)境娃豹;調(diào)用了initEurekaServerContext(),初始化Eureka運(yùn)行上下文购裙。關(guān)于這兩個(gè)方法的細(xì)節(jié)懂版,我們?cè)诤竺娴奈恼略偌?xì)說。
至此Eureka Server就隨著Spring容器的一起啟起了躏率。
相關(guān)流程圖如下: