Eureka运行流程
流程描述
1,启动过程分析
1.1 @EnableEurekaServer注解,来标记启动注册中心功能
@EnableDiscoveryClient @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(EurekaServerMarkerConfiguration.class) public @interface EnableEurekaServer { }
源码中有2个重要的操作
1,使用注解@EnableDiscoveryClent,开启SpringCloud服务发现客户端的注解,由于SpringCloud在服务发现组件上不止支持Eureka,还支持例如Alibaba的Dubbo等。
2,Import(EurekaServerMarkerConfiguration.Class),导入配置类,此配置类还实例化了一个Marker的bean。
看下自动配置EurekaServerAutoConfiguration 源码
@Configuration @Import(EurekaServerInitializerConfiguration.class) @ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class) @EnableConfigurationProperties({ EurekaDashboardProperties.class, InstanceRegistryProperties.class }) @PropertySource("classpath:/eureka/server.properties") public class EurekaServerAutoConfiguration extends WebMvcConfigurerAdapter {...
1)自动配置类实例化的前提是上下文中存在EurekaServerMarkerConfiguration.Marker这个bean
2)通过@EnableConfigurationProperties({ EurekaDashboardProperties.class, InstanceRegistryProperties.class })导入了两个配置类
EurekaDashboardProperties用于控制eureka面板的启动及打开路径。
InstanceRegistryProperties 设置续约数量和通信数量
3)使用@Import导入配置类EurekaServerInitializerConfiguration.class
4)PropertySource控制字符集编码的;
1.2 配置类EurekaServerAutoConfiguration
1)实例化bean
@Bean public HasFeatures eurekaServerFeature() { return HasFeatures.namedFeature("Eureka Server", EurekaServerAutoConfiguration.class); }
2) 在静态内部类中有条件的实例化了eureka服务端配置,配置类为 EurekaServerConfig;
@Configuration protected static class EurekaServerConfigBeanConfiguration { @Bean @ConditionalOnMissingBean public EurekaServerConfig eurekaServerConfig(EurekaClientConfig clientConfig) { EurekaServerConfigBean server = new EurekaServerConfigBean(); if (clientConfig.shouldRegisterWithEureka()) { // Set a sensible default if we are supposed to replicate server.setRegistrySyncRetries(5); } return server; } }
3)实例化了进入eureka控制面板的Controller类:EurekaController:用于展示eureka面板
@Bean @ConditionalOnProperty(prefix = "eureka.dashboard", name = "enabled", matchIfMissing = true) public EurekaController eurekaController() { return new EurekaController(this.applicationInfoManager); }
4)eureka服务的Context维护
@Bean public EurekaServerContext eurekaServerContext(ServerCodecs serverCodecs, PeerAwareInstanceRegistry registry, PeerEurekaNodes peerEurekaNodes) { return new DefaultEurekaServerContext(this.eurekaServerConfig, serverCodecs, registry, peerEurekaNodes, this.applicationInfoManager); }
5)实例化了eureka多个服务维持节点同步的bean;初始化注册表
@Bean public PeerAwareInstanceRegistry peerAwareInstanceRegistry( ServerCodecs serverCodecs) { this.eurekaClient.getApplications(); // force initialization return new InstanceRegistry(this.eurekaServerConfig, this.eurekaClientConfig, serverCodecs, this.eurekaClient, this.instanceRegistryProperties.getExpectedNumberOfRenewsPerMin(), this.instanceRegistryProperties.getDefaultOpenForTrafficCount()); }
6)管理每个eureka服务节点的生命周期
@Bean @ConditionalOnMissingBean public PeerEurekaNodes peerEurekaNodes(PeerAwareInstanceRegistry registry, ServerCodecs serverCodecs) { return new PeerEurekaNodes(registry, this.eurekaServerConfig, this.eurekaClientConfig, serverCodecs, this.applicationInfoManager); }
7)通过tomcat维护管理eureka生命周期
@Bean public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry registry, EurekaServerContext serverContext) { return new EurekaServerBootstrap(this.applicationInfoManager, this.eurekaClientConfig, this.eurekaServerConfig, registry, serverContext); }
1.3 Eureka服务的启动
1)在EurekaServerBootstrap类中我们看到了初始化方法:
public void contextInitialized(ServletContext context) { try { //看源码可知这里主要初始化服务环境,配置信息; initEurekaEnvironment(); //初始化了eureka服务端的上下文 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); } }
在这个方法中我们看到了初始化eureka-server环境配置及eureka-server上下文的操作,那么这个方法应该在一个地方有调用,通过查找调用发现:
@Configuration @CommonsLog public class EurekaServerInitializerConfiguration implements ServletContextAware, SmartLifecycle, Ordered { @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(); } @Override public void stop() { this.running = false; eurekaServerBootstrap.contextDestroyed(this.servletContext); } ..... 部分代码省略..... }
EurekaServerInitializerConfiguration中操作如下:
1)start()初始化,
eurekaServerBootstrap.contextInitialized(EurekaServerInitializerConfiguration.this.servletContext); log.info("Started Eureka Server");
2)发布EurekaServer的注册事件pubilsh
publish(new EurekaRegistryAvailableEvent(getEurekaServerConfig()));
3)发布Eureka Start事件的pubilsh
publish(new EurekaServerStartedEvent(getEurekaServerConfig()));
那么在启动eureka服务有哪些操作呢?深入跟进下源码.
protected void initEurekaServerContext() throws Exception { // For backward compatibility 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"); // Copy registry from neighboring eureka node
//服务同步 int registryCount = this.registry.syncUp();
//服务剔除 this.registry.openForTraffic(this.applicationInfoManager, registryCount); // Register all monitoring statistics. EurekaMonitors.registerAllStats(); }
在初始化eureka服务端initEurekaServerContext()方法中,主要做了初始化server上下文,同步了其他节点的信息,启动了剔除不可用eureka客户端的定时任务;