咱們從下面的圖能夠看出,做爲一個client端,他有如下功能:spring
springboot的自動裝配讀取Eureka Client的spring.factories文件,咱們看到他裏面有多個EnableAutoConfiguration,主要的類是EurekaClientAutoConfiguration。EurekaClientAutoConfiguration類中有多個bean的加載,咱們先看看EurekaInstanceConfigBean的加載。緩存
EurekaInstanceConfigBean有個@ConfigurationProperties("eureka.instance")註解,因此咱們在配置文件裏寫的eureka.instance.instanceId這類的信息最終都在賦值給這個類。還有比較重要的leaseRenewalIntervalInSeconds續約頻率(默認每30秒)、leaseExpirationDurationInSeconds續約過時時間(默認90秒)都是在這個類配置的。springboot
@Bean @ConditionalOnMissingBean(value = EurekaInstanceConfig.class, search = SearchStrategy.CURRENT) public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils, ManagementMetadataProvider managementMetadataProvider) { // 省略部分代碼 EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils); // 省略部分代碼 return instance; }
ApplicationInfoManager也是在EurekaClientAutoConfiguration類中。
建立eurekaApplicationInfoManager對象的時候,會先建立InstanceInfo對象,InstanceInfo對象的值大部分是從EurekaInstanceConfig複製過來的,另外租約信息是存放在InstanceInfo的leaseInfo中。
因此初始化ApplicationInfoManager的時候,就是賦值EurekaInstanceConfig和InstanceInfo。網絡
@Bean @ConditionalOnMissingBean(value = ApplicationInfoManager.class, search = SearchStrategy.CURRENT) @org.springframework.cloud.context.config.annotation.RefreshScope @Lazy public ApplicationInfoManager eurekaApplicationInfoManager( EurekaInstanceConfig config) { InstanceInfo instanceInfo = new InstanceInfoFactory().create(config); return new ApplicationInfoManager(config, instanceInfo); }
EurekaClientConfigBean也是一個配置信息的bean,他主要是EurekaClient和EurekaServer相關的信息,好比EurekaServer的地址defaultZone、是否從註冊中心拉取註冊信息fetchRegistry(默認true),拉取的頻率registryFetchIntervalSeconds(默認每30秒)、是否向註冊中心註冊registerWithEureka(默認true)等。app
@Bean @ConditionalOnMissingBean(value = EurekaClientConfig.class, search = SearchStrategy.CURRENT) public EurekaClientConfigBean eurekaClientConfigBean(ConfigurableEnvironment env) { return new EurekaClientConfigBean(); }
建立一個EurekaClient類,這個類就是負責服務的註冊、續約、取消、獲取註冊列表。dom
@Bean(destroyMethod = "shutdown") @ConditionalOnMissingBean(value = EurekaClient.class, search = SearchStrategy.CURRENT) @org.springframework.cloud.context.config.annotation.RefreshScope @Lazy public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config, EurekaInstanceConfig instance, @Autowired(required = false) HealthCheckHandler healthCheckHandler) { ApplicationInfoManager appManager; if (AopUtils.isAopProxy(manager)) { appManager = ProxyUtils.getTargetObject(manager); } else { appManager = manager; } CloudEurekaClient cloudEurekaClient = new CloudEurekaClient(appManager, config, this.optionalArgs, this.context); cloudEurekaClient.registerHealthCheck(healthCheckHandler); return cloudEurekaClient; }
結合上面幾個類的加載以及EurekaClient的加載,咱們能夠知道這幾個類的關係以下:
在DiscoveryClient的構造函數裏,主要是初始化一些配置參數,以及爲拉取註冊表信息、初始化定時任務。ide
@Inject DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args, Provider<BackupRegistry> backupRegistryProvider, EndpointRandomizer endpointRandomizer) { // 初始化applicationInfoManager、config等略 try { // 建立核心數爲2的線程池,一個用於heartbeat,一個用於cacheRefresh // default size of 2 - 1 each for heartbeat and cacheRefresh scheduler = Executors.newScheduledThreadPool(2, new ThreadFactoryBuilder() .setNameFormat("DiscoveryClient-%d") .setDaemon(true) .build()); heartbeatExecutor = new ThreadPoolExecutor( 1, clientConfig.getHeartbeatExecutorThreadPoolSize(), 0, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadFactoryBuilder() .setNameFormat("DiscoveryClient-HeartbeatExecutor-%d") .setDaemon(true) .build() ); // use direct handoff cacheRefreshExecutor = new ThreadPoolExecutor( 1, clientConfig.getCacheRefreshExecutorThreadPoolSize(), 0, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadFactoryBuilder() .setNameFormat("DiscoveryClient-CacheRefreshExecutor-%d") .setDaemon(true) .build() ); // use direct handoff // 與EurekaServer網絡通訊用的 eurekaTransport = new EurekaTransport(); scheduleServerEndpointTask(eurekaTransport, args); //其餘的略 } catch (Throwable e) { throw new RuntimeException("Failed to initialize DiscoveryClient!", e); } if (clientConfig.shouldFetchRegistry()) { try { // 拉取註冊表信息 boolean primaryFetchRegistryResult = fetchRegistry(false); //其餘的略,沒有拉取成功從備份註冊中心獲取 } } //其餘的略 // 初始化定時任務 initScheduledTasks(); //其餘的略 }
initScheduledTasks,用來開啓更新服務註冊列表和續租的定時任務,以及對EurekaServer的註冊。函數
private void initScheduledTasks() { if (clientConfig.shouldFetchRegistry()) { // registry cache refresh timer // 這個定時任務是更新服務註冊列表 // 更新頻率 int registryFetchIntervalSeconds = clientConfig.getRegistryFetchIntervalSeconds(); // 延遲最大乘數,好比更新頻率是5s,那最大延遲時間就是50s,這個後面講線程的時候會具體說 int expBackOffBound = clientConfig.getCacheRefreshExecutorExponentialBackOffBound(); cacheRefreshTask = new TimedSupervisorTask( "cacheRefresh", scheduler, cacheRefreshExecutor, registryFetchIntervalSeconds, TimeUnit.SECONDS, expBackOffBound, new CacheRefreshThread() ); scheduler.schedule( cacheRefreshTask, registryFetchIntervalSeconds, TimeUnit.SECONDS); } instanceInfoReplicator = new InstanceInfoReplicator( this, instanceInfo, clientConfig.getInstanceInfoReplicationIntervalSeconds(), 2); if (clientConfig.shouldRegisterWithEureka()) { // 這個定時任務是續租 // 續約頻率 int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs(); int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound(); logger.info("Starting heartbeat executor: " + "renew interval is: {}", renewalIntervalInSecs); // Heartbeat timer heartbeatTask = new TimedSupervisorTask( "heartbeat", scheduler, heartbeatExecutor, renewalIntervalInSecs, TimeUnit.SECONDS, expBackOffBound, new HeartbeatThread() ); scheduler.schedule( heartbeatTask, renewalIntervalInSecs, TimeUnit.SECONDS); // 其餘的略 // 註冊到註冊中心 instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds()); } else { logger.info("Not registering with Eureka server per configuration"); } }
好了,以上對EurekaServer的註冊、續租、註冊表獲取都說起到了,後面再詳細的講解這些內容。fetch