取消注册
取消注册(服务下线)指的是EureakClient正常关闭之前,微服务会主动向EurekaServer发送下线请求,EureakServer接收到请求从注册表中剔除下线的服务
DiscoveryClient.shutdown 方法
DiscoveryClient是服务发现最核心的实现,DiscoveryClient通过shutdown 方法取消服务注册,方法上通过@PreDestroy标记该方法是实例的销毁方法,当应用关闭,容器正常关闭,Bean的销毁方法执行,源码如下:
publicclassDiscoveryClientimplementsEurekaClient { ....省略部分代码... /**//关闭Eureak Client,从Eureak Server中取消服务的注册* Shuts down Eureka Client. Also sends a deregistration request to the* eureka server.*/publicsynchronizedvoidshutdown() { if (isShutdown.compareAndSet(false, true)) { logger.info("Shutting down DiscoveryClient ..."); //1.移除掉服务状态监听器if (statusChangeListener!=null&&applicationInfoManager!=null) { applicationInfoManager.unregisterStatusChangeListener(statusChangeListener.getId()); } //2.注销定时任务cancelScheduledTasks(); // If APPINFO was registered//如果开启了shouldUnregisterOnShutdown 取消注册(默认true),if (applicationInfoManager!=null&&clientConfig.shouldRegisterWithEureka() &&clientConfig.shouldUnregisterOnShutdown()) { //3.修改实例的注册状态为 DOWNapplicationInfoManager.setInstanceStatus(InstanceStatus.DOWN); //4.取消注册unregister(); } //5.注销eurekaTransportif (eurekaTransport!=null) { eurekaTransport.shutdown(); } //6.注销心跳状态监视器heartbeatStalenessMonitor.shutdown(); //7.注销注册表状态监视器registryStalenessMonitor.shutdown(); logger.info("Completed shut down of DiscoveryClient"); } } //注销定时任务privatevoidcancelScheduledTasks() { if (instanceInfoReplicator!=null) { instanceInfoReplicator.stop(); } if (heartbeatExecutor!=null) { heartbeatExecutor.shutdownNow(); } if (cacheRefreshExecutor!=null) { cacheRefreshExecutor.shutdownNow(); } if (scheduler!=null) { scheduler.shutdownNow(); } } //注销EurekaTransport ,privatestaticfinalclassEurekaTransport { privateClosableResolverbootstrapResolver; privateTransportClientFactorytransportClientFactory; privateEurekaHttpClientregistrationClient; privateEurekaHttpClientFactoryregistrationClientFactory; privateEurekaHttpClientqueryClient; privateEurekaHttpClientFactoryqueryClientFactory; voidshutdown() { if (registrationClientFactory!=null) { registrationClientFactory.shutdown(); } if (queryClientFactory!=null) { queryClientFactory.shutdown(); } if (registrationClient!=null) { registrationClient.shutdown(); } if (queryClient!=null) { queryClient.shutdown(); } if (transportClientFactory!=null) { transportClientFactory.shutdown(); } if (bootstrapResolver!=null) { bootstrapResolver.shutdown(); } } }
总结一下,在shutdown方法中做了如下事情
- 通过
applicationInfoManager.unregisterStatusChangeListener
移除服务实例状态监听器StatusChangeListener
- 调用
DiscoveryClient.cancelScheduledTasks();
取消定时任务 - 修改
applicationInfoManager.setInstanceStatus(InstanceStatus.DOWN);
状态为DOWN,调用unregister
方法取消注册 eurekaTransport.shutdown();
注销和EurekaServer交互的Http客户端- 注销心跳状态监视器,注册表状态监视器
我们重点跟踪一下 unregister方法源码
/**向eureka发送取消注册请求* unregister w/ the eureka service.*/voidunregister() { // It can be null if shouldRegisterWithEureka == falseif(eurekaTransport!=null&&eurekaTransport.registrationClient!=null) { try { logger.info("Unregistering ..."); //向eureka发送取消注册的http请求EurekaHttpResponse<Void>httpResponse=eurekaTransport.registrationClient.cancel(instanceInfo.getAppName(), instanceInfo.getId()); logger.info(PREFIX+"{} - deregister status: {}", appPathIdentifier, httpResponse.getStatusCode()); } catch (Exceptione) { logger.error(PREFIX+"{} - de-registration failed{}", appPathIdentifier, e.getMessage(), e); } } }
这里依然通过eurekaTransport.registrationClient得到EureakHttpClient客户端发请求,最终会调用AbstractJerseyEurekaHttpClient.cancel方法发送Delete取消注册请求
publicEurekaHttpResponse<Void>cancel(StringappName, Stringid) { StringurlPath="apps/"+appName+'/'+id; ClientResponseresponse=null; try { BuilderresourceBuilder=jerseyClient.resource(serviceUrl).path(urlPath).getRequestBuilder(); addExtraHeaders(resourceBuilder); //发送Delete请求response=resourceBuilder.delete(ClientResponse.class); returnanEurekaHttpResponse(response.getStatus()).headers(headersOf(response)).build(); } finally { if (logger.isDebugEnabled()) { logger.debug("Jersey HTTP DELETE {}/{}; statusCode={}", serviceUrl, urlPath, response==null?"N/A" : response.getStatus()); } if (response!=null) { response.close(); } } }
总结
- Eureak服务取消注册,通过 @PreDestroy标记DiscoveyClient.shutdown销毁方法,当容器正常关闭,Bean的销毁执行
- 在shutdown方法中注销了服务注册状态监听器,注销定时任务执行器,修改服务注册状态为下线,调用unregister方法取消注册等等
- unregister方法中通过eurekaTransport 得到HttpClient,使用AbstractJerseyEurekaHttpClient发送delete请求到Eureak Server取消服务注册