在服务的启动类上添加@EnableEurekaServer 注解后,这个服务就是一个注册中心。下面分析下为何加了@EnableEurekaServer 注解后为何就成为了服务的注册中心。
@SpringBootApplication@EnableEurekaServerpublic class EurekaApplication {public static void main(String[] args) {SpringApplication.run(EurekaApplication.class, args);}}
下面分析下@EnableEurekaServer 注解
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Import(EurekaServerMarkerConfiguration.class)public @interface EnableEurekaServer {}@Configurationpublic class EurekaServerMarkerConfiguration {@Beanpublic Marker eurekaServerMarkerBean() {return new Marker();}class Marker {}}
看上面的代码可以得知通过@Import 注解将EurekaServerMarkerConfiguration这个类导入到spring容器中,
然后EurekaServerMarkerConfiguration类中声明了Marker类的bean对象。这个bean对象下面会用到。
当注册中心启动时,了解springboot自动装配我们知道,系统会加载META-INF/spring.factories下的配置
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.springframework.cloud.netflix.eureka.server.EurekaServerAutoConfiguration
根据spring.factories配置文件会加载EurekaServerAutoConfiguration这个类
@Configuration@Import(EurekaServerInitializerConfiguration.class)// 有Marker的这个bean才会将EurekaServerAutoConfiguration注入到spring容器中@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)@EnableConfigurationProperties({ EurekaDashboardProperties.class,InstanceRegistryProperties.class })@PropertySource("classpath:/eureka/server.properties")public class EurekaServerAutoConfiguration extends WebMvcConfigurerAdapter {
通过代码可以得知,spring会判断是否存在Marker的bean对象,存在则将EurekaServerAutoConfiguration这个类注入到spring容器中。在EurekaServerAutoConfiguration类中我们并没有发现启动Eureka祥光的代码,下面我们看下EurekaServerInitializerConfiguration这个类
@Configurationpublic class EurekaServerInitializerConfigurationimplements ServletContextAware, SmartLifecycle, Ordered
通过上面代码可以看出EurekaServerInitializerConfiguration也是一个配置类,同时它实现了ServletContextAware接口,可以在Servlet容器启动后得到ServletContext容器上下文;它还实现了SmartLifecycle,这样在spring 生命周期中会调用这个类相关的方法。比如在spring初始化时,会调用它start方法。
@Overridepublic void start() {new Thread(new Runnable() {@Overridepublic 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);
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容器的一起启起了。
