在Springcloud中,注册中心是一个不可缺少的组件,eureka便是一个比较经典的注册组件。虽然现在eureka已经停止了维护,在实际项目中仍然会有不少应用,对其源码进行了解,能够更好的理解整个注册中心的功能。
eureka根据功能的不同,分为客户端和服务端。本文主要探究的是客户端。
对于客户端来说,想要把微服务注册到注册中心,一般来说都要引入如下pom文件:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
ctlr+鼠标左键点击,可以看到其是一个组合依赖,其依赖主体为:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-netflix-eureka-client</artifactId> <version>2.2.6.RELEASE</version> <scope>compile</scope> </dependency> <dependency> <groupId>com.netflix.eureka</groupId> <artifactId>eureka-client</artifactId> <version>1.10.7</version> ......
找到相关依赖jar包,在META-INF下面的spring.factories文件,可以看到其自动装配的配置:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaClientConfigServerAutoConfiguration,\
org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,\
org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration,\
org.springframework.cloud.netflix.eureka.reactive.EurekaReactiveDiscoveryClientConfiguration,\
org.springframework.cloud.netflix.eureka.loadbalancer.LoadBalancerEurekaAutoConfiguration
可以看到,红色标记的全类名便是eureka客户端自动装配的启动类。点击进去,我们可以看到其对eureka客户端的配置:
@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 = (ApplicationInfoManager)ProxyUtils.getTargetObject(manager); } else { appManager = manager; } CloudEurekaClient cloudEurekaClient = new CloudEurekaClient(appManager, config, this.optionalArgs, this.context); //客户端向服务端注册 cloudEurekaClient.registerHealthCheck(healthCheckHandler); return cloudEurekaClient; }
通过红色代码可以看出,这是实现eureka客户端向服务端注册中心注册的源码实现。
一路追踪,再结合上文引入的eureka-client的jar包,可以看到最终的注册实现是由
com.netflix.discovery.DiscoveryClient这个类的register方法实现,其过程为:
public boolean onDemandUpdate() { if (this.rateLimiter.acquire(this.burstSize, (long)this.allowedRatePerMinute)) { if (!this.scheduler.isShutdown()) { this.scheduler.submit(new Runnable() { public void run() { InstanceInfoReplicator.logger.debug("Executing on-demand update of local InstanceInfo"); Future latestPeriodic = (Future)InstanceInfoReplicator.this.scheduledPeriodicRef.get(); if (latestPeriodic != null && !latestPeriodic.isDone()) { InstanceInfoReplicator.logger.debug("Canceling the latest scheduled update, it will be rescheduled at the end of on demand update"); latestPeriodic.cancel(false); } InstanceInfoReplicator.this.run(); } ...... } public void run() { boolean var6 = false; ScheduledFuture next; label53: { try { var6 = true; this.discoveryClient.refreshInstanceInfo(); Long dirtyTimestamp = this.instanceInfo.isDirtyWithTime(); if (dirtyTimestamp != null) { this.discoveryClient.register();
最后进入具体执行的方法:
boolean register() throws Throwable {
logger.info("DiscoveryClient_{}: registering service...", this.appPathIdentifier);
EurekaHttpResponse httpResponse;
try {
httpResponse = this.eurekaTransport.registrationClient.register(this.instanceInfo);
} catch (Exception var3) {
logger.warn("DiscoveryClient_{} - registration failed {}", new Object[]{this.appPathIdentifier, var3.getMessage(), var3});
throw var3;
}
if (logger.isInfoEnabled()) {
logger.info("DiscoveryClient_{} - registration status: {}", this.appPathIdentifier, httpResponse.getStatusCode());
}
return httpResponse.getStatusCode() == Status.NO_CONTENT.getStatusCode();
}
通过源码的字面意思,可以看到这就是一个http请求,给eureka服务端发送http请求来实现对其注册,并通过状态码来判断是否注册成功。
其核心方法为抽象类EurekaHttpClientDecorator及其四个继承类及其作用如下:
RetryableEurekaHttpClient(Http请求失败进行重试),
RedirectingEurekaHttpClient(重定向到不同的EurekaServer)
MetricsCollectingEurekaHttpClient(统计执行指标)
AbstractJerseyEurekaHttpClient(使用jersey发起注册)
最后,会调用AbstractJerseyEurekaHttpClient的register方法注册:
public abstract class EurekaHttpClientDecorator implements EurekaHttpClient { public EurekaHttpClientDecorator() {} protected abstract <R> EurekaHttpResponse<R> execute(EurekaHttpClientDecorator.RequestExecutor<R> var1); public EurekaHttpResponse<Void> register(final InstanceInfo info) { return this.execute(new EurekaHttpClientDecorator.RequestExecutor<Void>() { public EurekaHttpResponse<Void> execute(EurekaHttpClient delegate) { return delegate.register(info); } public EurekaHttpClientDecorator.RequestType getRequestType() { return EurekaHttpClientDecorator.RequestType.Register; } }); }....
public EurekaHttpResponse<Void> register(InstanceInfo info) { String urlPath = "apps/" + info.getAppName(); ClientResponse response = null; EurekaHttpResponse var5; try { Builder resourceBuilder = this.jerseyClient.resource(this.serviceUrl).path(urlPath).getRequestBuilder(); this.addExtraHeaders(resourceBuilder); response = (ClientResponse)((Builder)((Builder)((Builder)resourceBuilder.header("Accept-Encoding", "gzip")).type(MediaType.APPLICATION_JSON_TYPE)).accept(new String[]{"application/json"})).post(ClientResponse.class, info); var5 = EurekaHttpResponse.anEurekaHttpResponse(response.getStatus()).headers(headersOf(response)).build(); } finally { ...... return var5; }
可以看到,其最终就是一个http请求,根据返回状态来判断是否注册成功。