1.Eureka Client如何实现服务注册?
基于Spring Cloud的eureka的client端在启动类上加上@EnableDiscovertClient注解,就可以用NetFilx提供Eureka Client。下面以@EnableDiscoveryClient为入口,进行源码分析。
@EnableDiscoveryClient,通过源码发现这是一个标记注解
/**
* Annotation to enable a DiscoveryClient implementation.
* @author Spencer Gibb
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {
/**
* If true, the ServiceRegistry will automatically register the local server.
* @return - {@code true} if you want to automatically register.
*/
boolean autoRegister() default true;
}
通过注释可以知道@EnableDiscoveryClient注解是用来启动DiscoveryClient的实现。DiscoveryClient接口代码如下:
public interface DiscoveryClient extends Ordered {
int DEFAULT_ORDER = 0;
String description();
List<ServiceInstance> getInstances(String serviceId);
List<String> getServices();
default int getOrder() {
return 0;
}
}
这个接口的实现类:
查看EurekaDiscoveryClient是DiscoveryClient的实现类,查看源码,真正发现服务的是EurekaClient
可以看到EurekaClient实现类是DiscoveryClient,查看类图:
DisCoveryClient实现了EurekaClient接口,并且定义了内部类。
- DiscoveryClientOptionalArgs:可选参数类,源码里面实现为空,是默认实现,具体需要查看AbstractDiscovertClientOptionalArags这个抽象类
- EurekaTransport:封装了Client请求的类
- CacheFreshThread:刷新缓存线程,提供定时拉取服务列表等
- HeartbeatThread:心跳线程,提供定时向服务端续约等。
现在查看DiscoveryClient的构造函数:
@Inject
DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args, Provider<BackupRegistry> backupRegistryProvider, EndpointRandomizer endpointRandomizer) {
this.RECONCILE_HASH_CODES_MISMATCH = Monitors.newCounter("DiscoveryClient_ReconcileHashCodeMismatch");
this.FETCH_REGISTRY_TIMER = Monitors.newTimer("DiscoveryClient_FetchRegistry");
this.REREGISTER_COUNTER = Monitors.newCounter("DiscoveryClient_Reregister");
this.localRegionApps = new AtomicReference();
this.fetchRegistryUpdateLock = new ReentrantLock();
this.healthCheckHandlerRef = new AtomicReference();
this.remoteRegionVsApps = new ConcurrentHashMap();
this.lastRemoteInstanceStatus = InstanceStatus.UNKNOWN;
this.eventListeners = new CopyOnWriteArraySet();
this.registrySize = 0;
this.lastSuccessfulRegistryFetchTimestamp = -1L;
this.lastSuccessfulHeartbeatTimestamp = -1L;
this.isShutdown = new AtomicBoolean(false);
if (args != null) {
this.healthCheckHandlerProvider = args.healthCheckHandlerProvider;
this.healthCheckCallbackProvider = args.healthCheckCallbackProvider;
this.eventListeners.addAll(args.getEventListeners());
this.preRegistrationHandler = args.preRegistrationHandler;
} else {
this.healthCheckCallbackProvider = null;
this.healthCheckHandlerProvider = null;
this.preRegistrationHandler = null;
}
this.applicationInfoManager = applicationInfoManager;
InstanceInfo myInfo = applicationInfoManager.getInfo();
this.clientConfig = config;
staticClientConfig = this.clientConfig;
this.transportConfig = config.getTransportConfig();
this.instanceInfo = myInfo;
if (myInfo != null) {
this.appPathIdentifier = this.instanceInfo.getAppName() + "/" + this.instanceInfo.getId();
} else {
logger.warn("Setting instanceInfo to a passed in null value");
}
this.backupRegistryProvider = backupRegistryProvider;
this.endpointRandomizer = endpointRandomizer;
this.urlRandomizer = new InstanceInfoBasedUrlRandomizer(this.instanceInfo);
this.localRegionApps.set(new Applications());
//拉取服务计数器:单调地增加计数器,已确保陈旧的线程不会将注册表重置为旧版本
this.fetchRegistryGeneration = new AtomicLong(0L);
this.remoteRegionsToFetch = new AtomicReference(this.clientConfig.fetchRegistryForRemoteRegions());
this.remoteRegionsRef = new AtomicReference(this.remoteRegionsToFetch.get() == null ? null : ((String)this.remoteRegionsToFetch.get()).split(","));
//过时注册统计
if (config.shouldFetchRegistry()) {
this.registryStalenessMonitor = new ThresholdLevelsMetric(this, "eurekaClient.registry.lastUpdateSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L});
} else {
this.registryStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC;
}
//过时心跳统计
if (config.shouldRegisterWithEureka()) {
this.heartbeatStalenessMonitor = new ThresholdLevelsMetric(this, "eurekaClient.registration.lastHeartbeatSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L});
} else {
this.heartbeatStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC;
}
logger.info("Initializing Eureka in region {}", this.clientConfig.getRegion());
//既不注册也不拉取
if (!config.shouldRegisterWithEureka() && !config.shouldFetchRegistry()) {
logger.info("Client configured to neither register nor query for data.");
this.scheduler = null;
this.heartbeatExecutor = null;
this.cacheRefreshExecutor = null;
this.eurekaTransport = null;
this.instanceRegionChecker = new InstanceRegionChecker(new PropertyBasedAzToRegionMapper(config), this.clientConfig.getRegion());
DiscoveryManager.getInstance().setDiscoveryClient(this);
DiscoveryManager.getInstance().setEurekaClientConfig(config);
this.initTimestampMs = System.currentTimeMillis();
logger.info("Discovery Client initialized at timestamp {} with initial instances count: {}", this.initTimestampMs, this.getApplications().size());
} else {
try {
//开启2个线程大小的定时线城池:一个是刷新缓存CacheFreshThread 一个心跳线程HeartbeatThread
this.scheduler = Executors.newScheduledThreadPool(2, (new ThreadFactoryBuilder()).setNameFormat("DiscoveryClient-%d").setDaemon(true).build());
//心跳线程池
this.heartbeatExecutor = new ThreadPoolExe