所有文章
https://www.cnblogs.com/lay2017/p/11908715.html
正文
上一篇文章,我們稍微了解了一下eureka客戶端是如何自動配置的,配置了哪些東西。在自動配置的時候會產生一個負責自動注冊的Bean,也就是
@Bean @ConditionalOnBean(AutoServiceRegistrationProperties.class) @ConditionalOnProperty( value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) public EurekaAutoServiceRegistration eurekaAutoServiceRegistration( ApplicationContext context, EurekaServiceRegistry registry, EurekaRegistration registration) { return new EurekaAutoServiceRegistration(context, registry, registration); }
所以,我們打開EurekaAutoServiceRegistration看看
public class EurekaAutoServiceRegistration implements AutoServiceRegistration, SmartLifecycle, Ordered, SmartApplicationListener { private ApplicationContext context; private EurekaServiceRegistry serviceRegistry; private EurekaRegistration registration; public EurekaAutoServiceRegistration(ApplicationContext context, EurekaServiceRegistry serviceRegistry, EurekaRegistration registration) { this.context = context; this.serviceRegistry = serviceRegistry; this.registration = registration; } @Override public void start() { // ... 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); } } }
注冊任務被委托給了serviceRegistry來做,跟進register方法
@Override public void register(EurekaRegistration reg) { maybeInitializeClient(reg); // ... reg.getApplicationInfoManager().setInstanceStatus(reg.getInstanceConfig().getInitialStatus()); reg.getHealthCheckHandler().ifAvailable(healthCheckHandler -> reg.getEurekaClient().registerHealthCheck(healthCheckHandler)); }
調用了eurekaClient原始的registerhealthCheck方法,跟進它
@Override public void registerHealthCheck(HealthCheckHandler healthCheckHandler) { if (instanceInfo == null) { logger.error("Cannot register a healthcheck handler when instance info is null!"); } if (healthCheckHandler != null) { // 注冊心跳檢查處理器 this.healthCheckHandlerRef.set(healthCheckHandler); // schedule an onDemand update of the instanceInfo when a new healthcheck handler is registered if (instanceInfoReplicator != null) { instanceInfoReplicator.onDemandUpdate(); } } }
心跳檢查處理器被設置為了成員變量,執行的核心邏輯被托付給了onDemandUpdate方法,跟進它
public boolean onDemandUpdate() { if (rateLimiter.acquire(burstSize, allowedRatePerMinute)) { if (!scheduler.isShutdown()) { scheduler.submit(new Runnable() { @Override public void run() { // ... InstanceInfoReplicator.this.run(); } }); return true; } else { // ... } } else { // ... } }
單線程異步執行了當前類的run方法,進入run方法
public void run() { try { // 刷新實例信息 discoveryClient.refreshInstanceInfo(); Long dirtyTimestamp = instanceInfo.isDirtyWithTime(); if (dirtyTimestamp != null) { // 注冊 discoveryClient.register(); instanceInfo.unsetIsDirty(dirtyTimestamp); } } catch (Throwable t) { // ... } finally { // 下一次延遲執行 Future next = scheduler.schedule(this, replicationIntervalSeconds, TimeUnit.SECONDS); scheduledPeriodicRef.set(next); } }
run方法每次執行都會刷新實例信息,然后調用register注冊新的實例信息,最后發出下一次執行的延遲任務
跟進register方法
boolean register() throws Throwable { logger.info(PREFIX + "{}: registering service...", appPathIdentifier); EurekaHttpResponse<Void> httpResponse; try { // 發出遠程請求 httpResponse = eurekaTransport.registrationClient.register(instanceInfo); } catch (Exception e) { } return httpResponse.getStatusCode() == Status.NO_CONTENT.getStatusCode(); }
繼續跟進register方法,發出了http請求,這里以jersey為例
@Override public EurekaHttpResponse<Void> register(InstanceInfo info) { String urlPath = "apps/" + info.getAppName(); ClientResponse response = null; try { Builder resourceBuilder = jerseyClient.resource(serviceUrl).path(urlPath).getRequestBuilder(); addExtraHeaders(resourceBuilder); response = resourceBuilder .header("Accept-Encoding", "gzip") .type(MediaType.APPLICATION_JSON_TYPE) .accept(MediaType.APPLICATION_JSON) // 發出http請求 .post(ClientResponse.class, info); return anEurekaHttpResponse(response.getStatus()).headers(headersOf(response)).build(); } finally { if (logger.isDebugEnabled()) { logger.debug("Jersey HTTP POST {}/{} with instance {}; statusCode={}", serviceUrl, urlPath, info.getId(), response == null ? "N/A" : response.getStatus()); } if (response != null) { response.close(); } } }
http請求將進入eureka服務端,注冊實例信息有興趣可以看看eureka服務端注冊服務這篇。
總結
eureka客戶端自動注冊服務主要是將自動配置的時候拿到的實例信息通過http請求發送給eureka服務端,默認30秒會執行一次。