SpringCloud部分源碼:Eureka Client註冊

1:使用SpringCloud框架的程序,除了Eureka服務以外,其他的服務都是Eureka Client。默認的狀況,會向Eureka註冊本身的服務實例,並從Eureka服務器週期性的獲取註冊信息。
在應用程序 引入 spring-cloud-starter-eureka 依賴包,便可引入 Eureka Clinet:spring-cloud-netflix-eureka-client。(可能不一樣的版本,依賴的包名稱不同)。以下:
<dependency>
 <groupId>org.springframework.cloud</groupId>
 <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

2:在spring-cloud-netflix-eureka-client包的 spring.factories裏,代碼以下。在這裏裏面,會執行自動配置加載類:EurekaClientAutoConfiguration。這裏主要就是註冊Eureka客戶端須要的對象。spring

org.springframework.boot.autoconfigure.EnableAutoConfiguration=
org.springframework.cloud.netflix.eureka.config.EurekaClientConfigServerAutoConfiguration,
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceAutoConfiguration,
org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,
org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceBootstrapConfiguration
org.springframework.cloud.client.discovery.EnableDiscoveryClient=
org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration

3:默認狀況,配置 eureka.client.enabled 的值是true。在yml文件以 eureka.client 開頭的配置,解析的對象是EurekaClientConfigBean。
其默認配置以下:
registryFetchIntervalSeconds:從erureka服務端獲取服務實例的頻率。默認狀況下。每一個30秒一次
eurekaServerReadTimeoutSeconds:從eureka服務端讀取獲取信息的超時時間,默認:8秒
eurekaServerConnectTimeoutSeconds:鏈接eureka服務器的超時時間,默認:5秒
serviceUrl:eureka服務註冊的URL:默認地址是:http://localhost:8761/eureka。這裏是個MAP,能夠配置多個地址
eurekaServerTotalConnections:鏈接到eureka的總鏈接數,默認:200個
eurekaServerTotalConnectionsPerHost:鏈接單個eureka的鏈接數,默認:50個
registerWithEureka:是否註冊到eureka,默認值:true
fetchRegistry:是否從eureka服務端獲取註冊信息,默認值:true.bootstrap

@ConfigurationProperties(EurekaClientConfigBean.PREFIX)
public class EurekaClientConfigBean implements EurekaClientConfig, EurekaConstants {
   public static final String PREFIX = "eureka.client";
 @Autowired(required = false)
   PropertyResolver propertyResolver;
 public static final String DEFAULT_URL = "http://localhost:8761" + DEFAULT_PREFIX
 + "/";
 public static final String DEFAULT_ZONE = "defaultZone";
 
 @Bean
@ConditionalOnMissingBean(value = EurekaClientConfig.class, search = SearchStrategy.CURRENT)
public EurekaClientConfigBean eurekaClientConfigBean() {
   EurekaClientConfigBean client = new EurekaClientConfigBean();
 if ("bootstrap".equals(propertyResolver.getProperty("spring.config.name"))) {
      // We don't register during bootstrap by default, but there will be another
 // chance later. client.setRegisterWithEureka(false);
 }
   return client;
}

4:註冊DiscoveryClient實例,能夠經過該實例對象,從緩存中獲取在eureka上註冊的服務信息。~~~~緩存

@Bean
public DiscoveryClient discoveryClient(EurekaInstanceConfig config, EurekaClient client) {
   return new EurekaDiscoveryClient(config, client);
}

5:註冊EurekaClient實例,類型是CloudEurekaClient。其父類是 DiscoveryClient。在該類的構造函數裏,會創建註冊到eureka和從eureka獲取服務服務的定時任務。服務器

@Bean(destroyMethod = "shutdown")
@ConditionalOnMissingBean(value = EurekaClient.class, search = SearchStrategy.CURRENT)
public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config) {
   return new CloudEurekaClient(manager, config, this.optionalArgs,
 this.context);
}

6:在 DiscoveryClient 的構造函數裏,除了各類屬性賦值外,還調用了一個很是重要的方法initScheduledTasks()來初始化定時任務,固然,若是該應用的registerWithEureka和fetchRegistry都是false,則不不會執行該方法。app

private void initScheduledTasks() {
    if (clientConfig.shouldFetchRegistry()) { //fetchRegistry配置的是true,則執行
        // registry cache refresh timer
 int registryFetchIntervalSeconds = clientConfig.getRegistryFetchIntervalSeconds(); //默認30S,從eureka獲取註冊信息間隔時間
 int expBackOffBound = clientConfig.getCacheRefreshExecutorExponentialBackOffBound(); //默認值是10,
 scheduler.schedule( //創建任務,從eureka獲取註冊信息,初始延遲時間,30S。任務類:TimedSupervisorTask
                new TimedSupervisorTask(
                        "cacheRefresh",
 scheduler,
 cacheRefreshExecutor,
 registryFetchIntervalSeconds,
 TimeUnit.SECONDS,
 expBackOffBound,
 new CacheRefreshThread()
                ),
 registryFetchIntervalSeconds, TimeUnit.SECONDS);
 }
    if (clientConfig.shouldRegisterWithEureka()) { //registerWithEureka配置的值是true則執行。
        int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
 int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound(); //默認30秒
 logger.info("Starting heartbeat executor: " + "renew interval is: " + renewalIntervalInSecs);
 // Heartbeat timer
 scheduler.schedule( //註冊心跳定時任務,定時向eureka發送信息,初始延遲時間30S
                new TimedSupervisorTask(
                        "heartbeat",
 scheduler,
 heartbeatExecutor,
 renewalIntervalInSecs,
 TimeUnit.SECONDS,
 expBackOffBound,
 new HeartbeatThread()
                ),
 renewalIntervalInSecs, TimeUnit.SECONDS);
 // InstanceInfo replicator
 instanceInfoReplicator = new InstanceInfoReplicator(
                this,
 instanceInfo,
 clientConfig.getInstanceInfoReplicationIntervalSeconds(),
 2); // burstSize
 statusChangeListener = new ApplicationInfoManager.StatusChangeListener() {
            @Override
 public String getId() {
                return "statusChangeListener";
 }
            @Override
 public void notify(StatusChangeEvent statusChangeEvent) {
                if (InstanceStatus.DOWN == statusChangeEvent.getStatus() ||
                        InstanceStatus.DOWN == statusChangeEvent.getPreviousStatus()) {
                    // log at warn level if DOWN was involved
 logger.warn("Saw local status change event {}", statusChangeEvent);
 } else {
                    logger.info("Saw local status change event {}", statusChangeEvent);
 }
                instanceInfoReplicator.onDemandUpdate();
 }
        };
 if (clientConfig.shouldOnDemandUpdateStatusChange()) { //註冊事件監聽器,按照上面的代碼,若是發現狀態是DOWN,會馬上註冊到eureka
            applicationInfoManager.registerStatusChangeListener(statusChangeListener);
 }
        instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds()); //創建定時任務,初始延遲時間是40S
 } else {
        logger.info("Not registering with Eureka server per configuration");
 }
}

7:實際上上面代碼中,TimedSupervisorTask類實際執行的是類: CacheRefreshThread 和 HeartbeatThread 的run 方法。 這裏就不展開。 代碼也不難。框架

8:在自動化配置中,同時也會實例化 EurekaAutoServiceRegistration 對象。該對象監聽了Spring的事件:EmbeddedServletContainerInitializedEvent。當WEB容器初始化完成後,會發送此事件。 在該事件處理方法中,會把當前節點註冊到 eureka服務器中。ide

@EventListener(EmbeddedServletContainerInitializedEvent.class)
public void onApplicationEvent(EmbeddedServletContainerInitializedEvent event) {
   // TODO: take SSL into account when Spring Boot 1.2 is available
 int localPort = event.getEmbeddedServletContainer().getPort();
 if (this.port.get() == 0) {
      log.info("Updating port to " + localPort);
 this.port.compareAndSet(0, localPort);
 start();
 }
}

public void start() {
   // only set the port if the nonSecurePort is 0 and this.port != 0
 if (this.port.get() != 0 && this.registration.getNonSecurePort() == 0) {
      this.registration.setNonSecurePort(this.port.get());
 }
   // only initialize if nonSecurePort is greater than 0 and it isn't already running
 // because of containerPortInitializer below if (!this.running.get() && this.registration.getNonSecurePort() > 0) {
      this.serviceRegistry.register(this.registration);
 this.context.publishEvent(
            new InstanceRegisteredEvent<>(this, this.registration.getInstanceConfig()));
 this.running.set(true);
 }
}
相關文章
相關標籤/搜索