package org.springframework.cloud.netflix;
import com.netflix.appinfo.ApplicationInfoManager;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.AbstractDiscoveryClientOptionalArgs;
import com.netflix.discovery.EurekaClient;
import com.netflix.discovery.EurekaClientConfig;
import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration.;
import org.springframework.cloud.netflix.eureka.CloudEurekaClient;
import org.springframework.context.ApplicationEventPublisher;
import com.netflix.discovery.;
import com.netflix.discovery.DiscoveryClient.;
import com.netflix.discovery.shared.transport.jersey.;
import com.netflix.discovery.shared.transport.decorator.*;
import javax.inject.Provider;
public class Doc {
/**
*
* 启动
* {@link EurekaClientConfiguration#eurekaClient -> {@link CloudEurekaClient#CloudEurekaClient(
* ApplicationInfoManager,
* EurekaClientConfig,
* ApplicationEventPublisher)->
*
* {@link CloudEurekaClient#CloudEurekaClient(
* ApplicationInfoManager,
* EurekaClientConfig,
* AbstractDiscoveryClientOptionalArgs,
* ApplicationEventPublisher
* ) ->
* super(applicationInfoManager, config, args) ->this():{@link DiscoveryClient#DiscoveryClient(
* ApplicationInfoManager,
* EurekaClientConfig,
* AbstractDiscoveryClientOptionalArgs){
* this(applicationInfoManager, config, args, new Provider<BackupRegistry>() {
* private volatile BackupRegistry backupRegistryInstance;
* @Override
* public synchronized BackupRegistry get() {...}初始化备用服务器
*
* });
* }
* }->
* {@link DiscoveryClient#DiscoveryClient(
* ApplicationInfoManager applicationInfoManager,
* EurekaClientConfig config,
* AbstractDiscoveryClientOptionalArgs args,
* Provider<BackupRegistry> backupRegistryProvider)
* .......
*
* if (config.shouldFetchRegistry()) {
* this.registryStalenessMonitor = new ThresholdLevelsMetric(this, METRIC_REGISTRY_PREFIX + "lastUpdateSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L});
* } else {
* this.registryStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC; 关闭服务发现(只做被调用)
* }
*
* if (config.shouldRegisterWithEureka()) { 关闭服务注册
* this.heartbeatStalenessMonitor = new ThresholdLevelsMetric(this, METRIC_REGISTRATION_PREFIX + "lastHeartbeatSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L});
* } else {
* this.heartbeatStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC;
* }
* ......
*
* if (!config.shouldRegisterWithEureka() && !config.shouldFetchRegistry()) { 都关闭表示单机运行
* ......
* return; // no need to setup up an network tasks and we are done
* }
*
* try {
* // default size of 2 - 1 each for heartbeat and cacheRefresh 定义三个线程池
* scheduler = Executors.newScheduledThreadPool(......); 用于调度下面两个线程池
*
* heartbeatExecutor = new ThreadPoolExecutor(......); // use direct handoff 心跳
*
* cacheRefreshExecutor = new ThreadPoolExecutor(......); // use direct handoff 服务发现
*
* ......
*
* } catch (Throwable e) {
* throw new RuntimeException("Failed to initialize DiscoveryClient!", e);
* }
*
* 如果开启了服务发现fetchRegistry(false)这个方法里去请求server {@link DiscoveryClient#fetchRegistry(boolean false)}
* if (clientConfig.shouldFetchRegistry() && !fetchRegistry(false)) {
* fetchRegistryFromBackup(); 去备用服务器放同步服务
* }
*
* ......
*
* if (clientConfig.shouldRegisterWithEureka() && clientConfig.shouldEnforceRegistrationAtInit()) {
* try {
* 服务注册 {
* @link DiscoveryClient#register() ->
* @link EurekaHttpClientDecorator#register(InstanceInfo) ->
* @link AbstractJerseyEurekaHttpClient#register(InstanceInfo) 线程池异步调用这里->
* }
* 编织一个http://ip:port/eureka/apps/clinet-name的url,client-id等信息会封装在body里面
* if (!register() ) {
* throw new IllegalStateException("Registration error at startup. Invalid server response.");
* }
* } catch (Throwable th) {
* logger.error("Registration error at startup: {}", th.getMessage());
* throw new IllegalStateException(th);
* }
*
* initScheduledTasks(); {
*
* @link DiscoveryClient#initScheduledTasks()->
* @link CacheRefreshThread
* @link HeartbeatThread
*
* 初始化本地缓存刷新线程和心跳连接发送线程
* }
* }
*
*
* {心跳续约 心跳线程池调用run
* @link HeartbeatThread#run ->
* @link HeartbeatThread#renew() ->
* @link AbstractJerseyEurekaHttpClient#sendHeartBeat url String urlPath = "apps/" + appName + '/' + id;
* 如果放回是404 则去在发起服务注册
* @link HeartbeatThread#register()->
* @link AbstractJerseyEurekaHttpClient#register(InstanceInfo)}
* 只要心跳和注册其中一个返回true 就更新lastSuccessfulHeartbeatTimestamp心跳续约时间为当前时间
* 如果都失败了就根据设定或者缺省30s后重新发送心跳续约注册重试
*
*
*
* 服务发现 服务调用线程池
* @link CacheRefreshThread#run() ->
* @link CacheRefreshThread#refreshRegistry() ->
* @link CacheRefreshThread#fetchRegistry
* if (clientConfig.shouldDisableDelta() 未配置 禁用增量更新
* || (!Strings.isNullOrEmpty(clientConfig.getRegistryRefreshSingleVipAddress())) vip:当前客户端是否对某个服务地址感兴趣
* || forceFullRegistryFetch
* || (applications == null) 本地eureka缓存为null
* || (applications.getRegisteredApplications().size() == 0)
* || (applications.getVersion() == -1))
* @link CacheRefreshThread#getAndStoreFullRegistry(); 全量
* else
* @link CacheRefreshThread#getAndUpdateDelta;增量 注:服务端接收到请求后会对需要返回的全量信息的HASHCODE,
* 客户端在接收到response后对 本地实例信息 + 增量信息 进行hash然后比对服务端放回的hash,不一致的情况下会进行全量拉取
* 服务端会有一个3分钟缓存队列,增量拉取以这个队列的数据为准 @link AbstractInstanceRegistry#recentlyChangedQueue 在服务注册,下架,状态修改,状态删除、定时器每三分钟一次更新
*
*
* 服务下架 {@link EurekaClientConfiguration#eurekaClient 注解@Bean(destroyMethod = "shutdown") 在Bean销毁时会调用
* @link DiscoveryClient#shutdown() @PreDestroy注解在spring容器销毁前回调 ,或者写个方法调用DiscoveryClient#shutdown()方法
*
*
*
*
*
* }
*
*
*
*
*
*
*
*
*/
}