六、eureka客户端自动注册服务

所有文章

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秒会执行一次。

 

 

 

 

posted @ 2019-11-24 15:42  __lay  阅读(1408)  评论(0编辑  收藏  举报