0. 前言
- springboot版本:2.1.9.RELEASE
- springcloud版本:Greenwich.SR4
1. 服务实例注册
客户端触发注册的时机:
- 客户端启动时发起注册,当配置文件配置了
eureka.client.should-enforce-registration-at-init = true
,不配置默认为 false - 客户端定期心跳续租时,向服务端发起心跳续租,服务端返回404,客户端立即发起注册
- 客户端定期检查自身数据状态,当相关信息(数据中心、实例信息、健康状态)变更时,发起注册
2. register()
上面所有触发注册的情况,调用的都是 DiscoveryClient 类中的 register() 方法
// DiscoveryClient.class
boolean register() throws Throwable {
logger.info(PREFIX + "{}: registering service...", appPathIdentifier);
EurekaHttpResponse<Void> httpResponse;
try {
// 2.1 发起 Jersey 注册请求
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());
}
// 服务端返回204,表示注册成功但没有返回数据
return httpResponse.getStatusCode() == Status.NO_CONTENT.getStatusCode();
}
2.1 发起 Jersey 注册请求
Jersey 是一个 REST 框架,提供 JAX-RS 参考实现等。 Jersey 提供了自己的 API,这些 API 扩展了 JAX-RS 工具箱,并具有其他功能和实用程序,以进一步简化 RESTful 服务和客户端开发。 Jersey 还公开了许多扩展 SPI ,以便开发人员根据自身需求进行扩展。
// AbstractJerseyEurekaHttpClient.class
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);
// 通过 Jersey 提交 post 请求
response = resourceBuilder
.header("Accept-Encoding", "gzip")
.type(MediaType.APPLICATION_JSON_TYPE)
.accept(MediaType.APPLICATION_JSON)
.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();
}
}
}
3. 服务实例下架
// DiscoveryClient.class
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);
// 3.1 向服务端注销当前服务实例,发起下架
unregister();
}
if (eurekaTransport != null) {
eurekaTransport.shutdown();
}
// 注销相关监控
heartbeatStalenessMonitor.shutdown();
registryStalenessMonitor.shutdown();
logger.info("Completed shut down of DiscoveryClient");
}
}
3.1 从服务端注销当前服务实例
// DiscoveryClient.class
void unregister() {
// It can be null if shouldRegisterWithEureka == false
if(eurekaTransport != null && eurekaTransport.registrationClient != null) {
try {
logger.info("Unregistering ...");
// 发起 Jersey 下架请求,与上面注册类似
EurekaHttpResponse<Void> httpResponse = eurekaTransport.registrationClient.cancel(instanceInfo.getAppName(), instanceInfo.getId());
logger.info(PREFIX + "{} - deregister status: {}", appPathIdentifier, httpResponse.getStatusCode());
} catch (Exception e) {
logger.error(PREFIX + "{} - de-registration failed{}", appPathIdentifier, e.getMessage(), e);
}
}
}