原始碼剖析 啟動Eureka Server(一)@EnableEurekaServer註解

weixin_34087301發表於2018-10-29

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容器的一起啟起了。


相關流程圖如下:

5826441-4e26306bdddbd8e3.png
Eureka原始碼剖析(一)註解方式啟動Eureka Server.png

相關文章