2.1.4 InstanceInfoReplicator.run()
public void run() { try { //1.刷新DataCenterInfo //2.刷新LeaseInfo 租约信息 //3.从HealthCheckHandler中获取InstanceStatus discoveryClient.refreshInstanceInfo(); //如果isInstanceInfoDirty=true表明需要更新,返回dirtyTimestamp。 Long dirtyTimestamp = instanceInfo.isDirtyWithTime(); if (dirtyTimestamp != null) { discoveryClient.register();//注册。 instanceInfo.unsetIsDirty(dirtyTimestamp);//注册完成,设置没有更新。 } } catch (Throwable t) { logger.warn("There was a problem with the instance info replicator", t); } finally { Future next = scheduler.schedule(this, replicationIntervalSeconds, TimeUnit.SECONDS); scheduledPeriodicRef.set(next); } }
可以看出实例注册就在discoveryClient.register()
。
那么第一次注册发生在什么时候呢?
initScheduledTasks方法中,执行instanceInfoReplicator.start时,会首先调用instanceInfo.setIsDirty(),初始化是否更新标志位为ture ,开启线程,40秒后发起第一次注册。(当然如果在这40秒内,如果有状态变化,会立即发起注册。)
2.1.4 discoveryClient.register()
boolean register() throws Throwable { logger.info(PREFIX + "{}: registering service...", appPathIdentifier); EurekaHttpResponse<Void> httpResponse; try { //发起注册 httpResponse = eurekaTransport.registrationClient.register(instanceInfo); } catch (Exception e) { logger.warn(PREFIX + "{} - registration failed {}", appPathIdentifier, e.getMessage(), e); throw e; } if (logger.isInfoEnabled()) { logger.info(PREFIX + "{} - registration status: {}", appPathIdentifier, httpResponse.getStatusCode()); } return httpResponse.getStatusCode() == 204; }
可以看出,register方法本质也是通过eurekaTransport 来发起与server的通信的。
2.2EurekaClient卸载方法
2.2.1shutdown()
注解@PreDestroy修饰的shutdown()会在Servlet被彻底卸载之前执行。
public synchronized void shutdown() { if (isShutdown.compareAndSet(false, true)) { logger.info("Shutting down DiscoveryClient ..."); //移除监听 if (statusChangeListener != null && applicationInfoManager != null) { applicationInfoManager.unregisterStatusChangeListener(statusChangeListener.getId()); } //取消任务 cancelScheduledTasks(); // If APPINFO was registered if (applicationInfoManager != null && clientConfig.shouldRegisterWithEureka() && clientConfig.shouldUnregisterOnShutdown()) { applicationInfoManager.setInstanceStatus(InstanceStatus.DOWN); //下线 unregister(); } //通信中断 if (eurekaTransport != null) { eurekaTransport.shutdown(); } heartbeatStalenessMonitor.shutdown(); registryStalenessMonitor.shutdown(); logger.info("Completed shut down of DiscoveryClient"); } }
3.EurekaAutoServiceRegistration回调
EurekaAutoServiceRegistration实现了SmartLifecycle,会在spring启动完毕后,调用其start()方法。
@Override public void start() { // 设置端口 if (this.port.get() != 0) { if (this.registration.getNonSecurePort() == 0) { this.registration.setNonSecurePort(this.port.get()); } if (this.registration.getSecurePort() == 0 && this.registration.isSecure()) { this.registration.setSecurePort(this.port.get()); } } 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);// } }
this.serviceRegistry.register(this.registration);
@Override public void register(EurekaRegistration reg) { maybeInitializeClient(reg); // 更改状态,会触发监听器的执行 reg.getApplicationInfoManager() .setInstanceStatus(reg.getInstanceConfig().getInitialStatus()); reg.getHealthCheckHandler().ifAvailable(healthCheckHandler -> reg.getEurekaClient().registerHealthCheck(healthCheckHandler)); }
4.总结
1.注册流程:
EurekaAutoServiceRegistration.start()
-->EurekaServiceRegistry.register(EurekaRegistration)
-->ApplicationInfoManager.setInstanceStatus 状态改变,
-->StatusChangeListener 监听器监听到状态改变
-->InstanceInfoReplicator.onDemandUpdate() 更新状态到server
-->InstanceInfoReplicator.run()
-->DiscoveryClient.register()
-->eurekaTransport.registrationClient.register(instanceInfo);
-->jerseyClient
2.客户端初始化的几个定时任务:
- 缓存刷新任务,默认30秒
- 心跳任务,默认30秒
- 信息更新任务,默认40秒
3.客户端的几个主要操作:
- 服务注册(register)
- 服务续约(renew)
- 服务下线(unregister)
- 服务获取(fetchRegistry)
- 缓存刷新(refreshRegistry)
由于篇幅原因,很多细节不能一一展示。本文志在说说一些原理,具体细节可以研读源码,会发现框架真优秀啊。