目录
EurekaServerMarkerConfiguration类
EurekaServerAutoConfiguration类-所有bean实例化
EurekaServerInitializerConfiguration类-eureka初始化&事件publish
EurekaServerBootstrap类-eureka env & context 初始化
PeerAwareInstanceRegistryImpl类-服务注册&同步
AbstractInstanceRegistry类-定时任务处理
概况
源码版本:
spring-cloud-neflix-eureka-client:2.1.2.RELEASE
eureka-core:1.9.12
@EnableEurekaServer-启动入口
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({EurekaServerMarkerConfiguration.class}) //引入EurekaServerMarkerConfiguration.class
public @interface EnableEurekaServer {
}
EurekaServerMarkerConfiguration类
/**
* Annotation to activate Eureka Server related configuration.
* {@link EurekaServerAutoConfiguration} //有时候注释也会有idea
*
* @author Dave Syer
* @author Biju Kunjummen
*
*/
@Configuration
public class EurekaServerMarkerConfiguration {
public EurekaServerMarkerConfiguration() {
}
//突然发现只实例一个MarKer,其它好象没什么了?
//是的,就是这一个Marker起了作用,请看注释:@link EurekaServerAutoConfiguration(当然jar包没有注释,要java源码中才有)
@Bean
public EurekaServerMarkerConfiguration.Marker eurekaServerMarkerBean() {
return new EurekaServerMarkerConfiguration.Marker();
}
class Marker {
Marker() {
}
}
}
spring.factories
结合spring.factories也可知目标就是为了EurekaServerAutoConfiguration类
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.eureka.server.EurekaServerAutoConfiguration
EurekaServerAutoConfiguration类-所有bean实例化
@Configuration
@Import({EurekaServerInitializerConfiguration.class}) //引入EurekaServerInitializerConfiguration
@ConditionalOnBean({Marker.class}) //原因在这里:它要依赖EurekaServerMarkerConfiguration中的Marker类
@EnableConfigurationProperties({EurekaDashboardProperties.class, InstanceRegistryProperties.class})
@PropertySource({"classpath:/eureka/server.properties"}) //配置信息文件
public class EurekaServerAutoConfiguration extends WebMvcConfigurerAdapter {
...
public EurekaServerAutoConfiguration() {
}
@Bean
public HasFeatures eurekaServerFeature() {
return HasFeatures.namedFeature("Eureka Server", EurekaServerAutoConfiguration.class);
}
//ui的接口实例化 EurekaController
@Bean
@ConditionalOnProperty(
prefix = "eureka.dashboard",
name = {"enabled"},
matchIfMissing = true
)
public EurekaController eurekaController() {
return new EurekaController(this.applicationInfoManager);
}
...
//实例化接收客户端注册请求&各类定时任务对象
@Bean
public PeerAwareInstanceRegistry peerAwareInstanceRegistry(ServerCodecs serverCodecs) {
this.eurekaClient.getApplications();
return new InstanceRegistry(this.eurekaServerConfig, this.eurekaClientConfig, serverCodecs, this.eurekaClient, this.instanceRegistryProperties.getExpectedNumberOfClientsSendingRenews(), this.instanceRegistryProperties.getDefaultOpenForTrafficCount());
}
//配置服务peer节点信息,节点之间信息同步刷新定时任务 实例化
@Bean
@ConditionalOnMissingBean
public PeerEurekaNodes peerEurekaNodes(PeerAwareInstanceRegistry registry, ServerCodecs serverCodecs) {
return new EurekaServerAutoConfiguration.RefreshablePeerEurekaNodes(registry, this.eurekaServerConfig, this.eurekaClientConfig, serverCodecs, this.applicationInfoManager);
}
//init上下文初始化,其中启动了peerEurekaNodes定时任务
@Bean
public EurekaServerContext eurekaServerContext(ServerCodecs serverCodecs, PeerAwareInstanceRegistry registry, PeerEurekaNodes peerEurekaNodes) {
return new DefaultEurekaServerContext(this.eurekaServerConfig, serverCodecs, registry, peerEurekaNodes, this.applicationInfoManager);
}
//实例Eureka-server配置,同步其他注册中心的数据到当前注册中心
@Bean
public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry registry, EurekaServerContext serverContext) {
return new EurekaServerBootstrap(this.applicationInfoManager, this.eurekaClientConfig, this.eurekaServerConfig, registry, serverContext);
}
//实例拦截器,ServletContainer里面实现了jersey框架,来实现eurekaServer对外的restful接口
@Bean
public FilterRegistrationBean jerseyFilterRegistration(Application eurekaJerseyApp) {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new ServletContainer(eurekaJerseyApp));
bean.setOrder(2147483647);
bean.setUrlPatterns(Collections.singletonList("/eureka/*"));
return bean;
}
@Bean
public Application jerseyApplication(Environment environment, ResourceLoader resourceLoader) {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false, environment);
provider.addIncludeFilter(new AnnotationTypeFilter(Path.class));
provider.addIncludeFilter(new AnnotationTypeFilter(Provider.class));
Set<Class<?>> classes = new HashSet();
String[] var5 = EUREKA_PACKAGES;
int var6 = var5.length;
for(int var7 = 0; var7 < var6; ++var7) {
String basePackage = var5[var7];
Set<BeanDefinition> beans = provider.findCandidateComponents(basePackage);
Iterator var10 = beans.iterator();
while(var10.hasNext()) {
BeanDefinition bd = (BeanDefinition)var10.next();
Class<?> cls = ClassUtils.resolveClassName(bd.getBeanClassName(), resourceLoader.getClassLoader());
classes.add(cls);
}
}
Map<String, Object> propsAndFeatures = new HashMap();
propsAndFeatures.put("com.sun.jersey.config.property.WebPageContentRegex", "/eureka/(fonts|images|css|js)/.*");
DefaultResourceConfig rc = new DefaultResourceConfig(classes);
rc.setPropertiesAndFeatures(propsAndFeatures);
return rc;
}
@Bean
public FilterRegistrationBean traceFilterRegistration(@Qualifier("httpTraceFilter") Filter filter) {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(filter);
bean.setOrder(2147483637);
return bean;
}
...
@Configuration
protected static class EurekaServerConfigBeanConfiguration {
protected EurekaServerConfigBeanConfiguration() {
}
@Bean
@ConditionalOnMissingBean
public EurekaServerConfig eurekaServerConfig(EurekaClientConfig clientConfig) {
EurekaServerConfigBean server = new EurekaServerConfigBean();
if (clientConfig.shouldRegisterWithEureka()) {
server.setRegistrySyncRetries(5);
}
return server;
}
}
}
EurekaServerInitializerConfiguration类-eureka初始化&事件publish
由EurekaServerAutoConfiguration import 交由spring 控制回调启动
@Configuration
public class EurekaServerInitializerConfiguration implements ServletContextAware, SmartLifecycle, Ordered {
private static final Log log = LogFactory.getLog(EurekaServerInitializerConfiguration.class);
@Autowired
private EurekaServerConfig eurekaServerConfig;
private ServletContext servletContext;
@Autowired
private ApplicationContext applicationContext;
@Autowired
private EurekaServerBootstrap eurekaServerBootstrap;
private boolean running;
private int order = 1;
public EurekaServerInitializerConfiguration() {
}
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
//启动线程
public void start() {
(new Thread(new Runnable() {
public void run() {
try {
//initEurekaEnvironment initEurekaServerContext 下面分析
EurekaServerInitializerConfiguration.this.eurekaServerBootstrap.contextInitialized(EurekaServerInitializerConfiguration.this.servletContext);
EurekaServerInitializerConfiguration.log.info("Started Eureka Server");
//发布EurekaServer的注册事件
EurekaServerInitializerConfiguration.this.publish(new EurekaRegistryAvailableEvent(EurekaServerInitializerConfiguration.this.getEurekaServerConfig()));
EurekaServerInitializerConfiguration.this.running = true;
//发布EurekaServer的启动事件
EurekaServerInitializerConfiguration.this.publish(new EurekaServerStartedEvent(EurekaServerInitializerConfiguration.this.getEurekaServerConfig()));
} catch (Exception var2) {
EurekaServerInitializerConfiguration.log.error("Could not initialize Eureka servlet context", var2);
}
}
})).start();
}
...
}
EurekaServerBootstrap类-eureka env & context 初始化
EurekaServerInitializerConfiguration类启动时调用了eurekaServerBootstrap.contextInitialized
public class EurekaServerBootstrap {
...
public EurekaServerBootstrap(ApplicationInfoManager applicationInfoManager, EurekaClientConfig eurekaClientConfig, EurekaServerConfig eurekaServerConfig, PeerAwareInstanceRegistry registry, EurekaServerContext serverContext) {
this.applicationInfoManager = applicationInfoManager;
this.eurekaClientConfig = eurekaClientConfig;
this.eurekaServerConfig = eurekaServerConfig;
this.registry = registry;
this.serverContext = serverContext;
}
public void contextInitialized(ServletContext context) {
try {
//初始化环境变量
this.initEurekaEnvironment();
//初始化上下文
this.initEurekaServerContext();
context.setAttribute(EurekaServerContext.class.getName(), this.serverContext);
} catch (Throwable var3) {
log.error("Cannot bootstrap eureka server :", var3);
throw new RuntimeException("Cannot bootstrap eureka server :", var3);
}
}
public void contextDestroyed(ServletContext context) {
try {
log.info("Shutting down Eureka Server..");
context.removeAttribute(EurekaServerContext.class.getName());
this.destroyEurekaServerContext();
this.destroyEurekaEnvironment();
} catch (Throwable var3) {
log.error("Error shutting down eureka", var3);
}
log.info("Eureka Service is now shutdown...");
}
protected void initEurekaEnvironment() throws Exception {
log.info("Setting the eureka configuration..");
String dataCenter = ConfigurationManager.getConfigInstance().getString("eureka.datacenter");
if (dataCenter == null) {
log.info("Eureka data center value eureka.datacenter is not set, defaulting to default");
ConfigurationManager.getConfigInstance().setProperty("archaius.deployment.datacenter", "default");
} else {
ConfigurationManager.getConfigInstance().setProperty("archaius.deployment.datacenter", dataCenter);
}
String environment = ConfigurationManager.getConfigInstance().getString("eureka.environment");
if (environment == null) {
ConfigurationManager.getConfigInstance().setProperty("archaius.deployment.environment", "test");
log.info("Eureka environment value eureka.environment is not set, defaulting to test");
} else {
ConfigurationManager.getConfigInstance().setProperty("archaius.deployment.environment", environment);
}
}
protected void initEurekaServerContext() throws Exception {
JsonXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), 10000);
XmlXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), 10000);
if (this.isAws(this.applicationInfoManager.getInfo())) {
this.awsBinder = new AwsBinderDelegate(this.eurekaServerConfig, this.eurekaClientConfig, this.registry, this.applicationInfoManager);
this.awsBinder.start();
}
EurekaServerContextHolder.initialize(this.serverContext);
log.info("Initialized server context");
//从相邻的eureka节点复制注册表,并注册
//详情可查看PeerAwareInstanceRegistryImpl中syncUp()方法
int registryCount = this.registry.syncUp();
// 修改eureka状态为up,默认每30秒发送心跳,1分钟就是2次
// 同时,这里面会开启一个定时任务,用于清理 60秒没有心跳的客户端。自动下线
//详情看PeerAwareInstanceRegistryImpl中openForTraffic方法
this.registry.openForTraffic(this.applicationInfoManager, registryCount);
EurekaMonitors.registerAllStats();
}
protected void destroyEurekaServerContext() throws Exception {
EurekaMonitors.shutdown();
if (this.awsBinder != null) {
this.awsBinder.shutdown();
}
if (this.serverContext != null) {
this.serverContext.shutdown();
}
}
...
}
PeerAwareInstanceRegistryImpl类-服务注册&同步
syncUp() :拉取其它节点注册信息并进行注册
openForTraffic():设置期望每分钟接收到的心跳次数,将服务实例的状态设置为UP,通过方法postInit来开启一个定时任务,用于每隔一段时间(默认60秒)将没有续约的服务实例(默认90秒没有续约)清理掉
@Singleton
public class PeerAwareInstanceRegistryImpl extends AbstractInstanceRegistry implements PeerAwareInstanceRegistry {
public int syncUp() {
int count = 0;
//获取节点配置
for(int i = 0; i < this.serverConfig.getRegistrySyncRetries() && count == 0; ++i) {
if (i > 0) {
try {
Thread.sleep(this.serverConfig.getRegistrySyncRetryWaitMs());
} catch (InterruptedException var10) {
logger.warn("Interrupted during registry transfer..");
break;
}
}
Applications apps = this.eurekaClient.getApplications();
Iterator var4 = apps.getRegisteredApplications().iterator();
while(var4.hasNext()) {
Application app = (Application)var4.next();
Iterator var6 = app.getInstances().iterator();
while(var6.hasNext()) {
InstanceInfo instance = (InstanceInfo)var6.next();
try {
if (this.isRegisterable(instance)) {
//进行注册
this.register(instance, instance.getLeaseInfo().getDurationInSecs(), true);
++count;
}
} catch (Throwable var9) {
logger.error("During DS init copy", var9);
}
}
}
}
return count;
}
...
public void openForTraffic(ApplicationInfoManager applicationInfoManager, int count) {
//最大续约数量
this.expectedNumberOfClientsSendingRenews = count;
//计算最小续约数
this.updateRenewsPerMinThreshold();
logger.info("Got {} instances from neighboring DS node", count);
logger.info("Renew threshold is: {}", this.numberOfRenewsPerMinThreshold);
this.startupTime = System.currentTimeMillis();
if (count > 0) {
this.peerInstancesTransferEmptyOnStartup = false;
}
//获取自身节点
Name selfName = applicationInfoManager.getInfo().getDataCenterInfo().getName();
boolean isAws = Name.Amazon == selfName;
if (isAws && this.serverConfig.shouldPrimeAwsReplicaConnections()) {
logger.info("Priming AWS connections for all replicas..");
//见下
this.primeAwsReplicas(applicationInfoManager);
}
logger.info("Changing status to UP");
// 设置服务实例的状态为UP
applicationInfoManager.setInstanceStatus(InstanceStatus.UP);
// 调用父类启动定时任务
super.postInit();
}
...
//接上
private void primeAwsReplicas(ApplicationInfoManager applicationInfoManager) {
boolean areAllPeerNodesPrimed = false;
while(!areAllPeerNodesPrimed) {
String peerHostName = null;
try {
//检查自身服务是否存在
Application eurekaApps = this.getApplication(applicationInfoManager.getInfo().getAppName(), false);
if (eurekaApps == null) {
areAllPeerNodesPrimed = true;
logger.info("No peers needed to prime.");
return;
}
Iterator var5 = this.peerEurekaNodes.getPeerEurekaNodes().iterator();
while(var5.hasNext()) {
PeerEurekaNode node = (PeerEurekaNode)var5.next();
Iterator var7 = eurekaApps.getInstances().iterator();
while(var7.hasNext()) {
InstanceInfo peerInstanceInfo = (InstanceInfo)var7.next();
LeaseInfo leaseInfo = peerInstanceInfo.getLeaseInfo();
if (System.currentTimeMillis() <= leaseInfo.getRenewalTimestamp() + (long)(leaseInfo.getDurationInSecs() * 1000) + 120000L) {
peerHostName = peerInstanceInfo.getHostName();
logger.info("Trying to send heartbeat for the eureka server at {} to make sure the network channels are open", peerHostName);
if (peerHostName.equalsIgnoreCase((new URI(node.getServiceUrl())).getHost())) {
node.heartbeat(peerInstanceInfo.getAppName(), peerInstanceInfo.getId(), peerInstanceInfo, (InstanceStatus)null, true);
}
}
}
}
areAllPeerNodesPrimed = true;
} catch (Throwable var11) {
logger.error("Could not contact {}", peerHostName, var11);
try {
Thread.sleep(30000L);
} catch (InterruptedException var10) {
logger.warn("Interrupted while priming : ", var10);
areAllPeerNodesPrimed = true;
}
}
}
}
//获取eurekaApps,先从this.registry获取,如没有则考虑从远端获取
public Application getApplication(String appName, boolean includeRemoteRegion) {
Application app = null;
Map<String, Lease<InstanceInfo>> leaseMap = (Map)this.registry.get(appName);
Iterator var5;
Entry entry;
if (leaseMap != null && leaseMap.size() > 0) {
for(var5 = leaseMap.entrySet().iterator(); var5.hasNext(); app.addInstance(this.decorateInstanceInfo((Lease)entry.getValue()))) {
entry = (Entry)var5.next();
if (app == null) {
app = new Application(appName);
}
}
} else if (includeRemoteRegion) {
var5 = this.regionNameVSRemoteRegistry.values().iterator();
while(var5.hasNext()) {
RemoteRegionRegistry remoteRegistry = (RemoteRegionRegistry)var5.next();
Application application = remoteRegistry.getApplication(appName);
if (application != null) {
return application;
}
}
}
return app;
}
}
AbstractInstanceRegistry类-定时任务处理
updateRenewsPerMinThreshold方法:计算最小续约数
postInit方法:启动定时任务,包含两个
renewsLastMin.start():更新Renews最小时间
evictionTimer.schedule:清理任务(如有保护机制,会根据阀值因子清除)
protected void updateRenewsPerMinThreshold() {
this.numberOfRenewsPerMinThreshold = (int)((double)this.expectedNumberOfClientsSendingRenews * (60.0D / (double)this.serverConfig.getExpectedClientRenewalIntervalSeconds()) * this.serverConfig.getRenewalPercentThreshold());
}
protected void postInit() {
//最小
this.renewsLastMin.start();
if (this.evictionTaskRef.get() != null) {
((AbstractInstanceRegistry.EvictionTask)this.evictionTaskRef.get()).cancel();
}
this.evictionTaskRef.set(new AbstractInstanceRegistry.EvictionTask());
//启动定时任务
this.evictionTimer.schedule((TimerTask)this.evictionTaskRef.get(), this.serverConfig.getEvictionIntervalTimerInMs(), this.serverConfig.getEvictionIntervalTimerInMs());
}
...
//每隔一段时间(默认60秒)将没有续约的服务实例(默认90秒没有续约)清理掉
public void evict(long additionalLeaseMs) {
logger.debug("Running the evict task");
//判断是否开启自我保护机制
if (!this.isLeaseExpirationEnabled()) {
logger.debug("DS: lease expiration is currently disabled.");
} else {
List<Lease<InstanceInfo>> expiredLeases = new ArrayList();
Iterator var4 = this.registry.entrySet().iterator();
while(true) {
Map leaseMap;
do {
if (!var4.hasNext()) {
//此时要结合阀值因子计算
int registrySize = (int)this.getLocalRegistrySize();
int registrySizeThreshold = (int)((double)registrySize * this.serverConfig.getRenewalPercentThreshold());
int evictionLimit = registrySize - registrySizeThreshold;
int toEvict = Math.min(expiredLeases.size(), evictionLimit);
if (toEvict > 0) {
logger.info("Evicting {} items (expired={}, evictionLimit={})", new Object[]{toEvict, expiredLeases.size(), evictionLimit});
Random random = new Random(System.currentTimeMillis());
for(int i = 0; i < toEvict; ++i) {
int next = i + random.nextInt(expiredLeases.size() - i);
Collections.swap(expiredLeases, i, next);
Lease<InstanceInfo> lease = (Lease)expiredLeases.get(i);
String appName = ((InstanceInfo)lease.getHolder()).getAppName();
String id = ((InstanceInfo)lease.getHolder()).getId();
EurekaMonitors.EXPIRED.increment();
logger.warn("DS: Registry: expired lease for {}/{}", appName, id);
this.internalCancel(appName, id, false);
}
}
return;
}
Entry<String, Map<String, Lease<InstanceInfo>>> groupEntry = (Entry)var4.next();
leaseMap = (Map)groupEntry.getValue();
} while(leaseMap == null);
Iterator var7 = leaseMap.entrySet().iterator();
while(var7.hasNext()) {
Entry<String, Lease<InstanceInfo>> leaseEntry = (Entry)var7.next();
Lease<InstanceInfo> lease = (Lease)leaseEntry.getValue();
if (lease.isExpired(additionalLeaseMs) && lease.getHolder() != null) {
expiredLeases.add(lease);
}
}
}
}
}
RemoteRegionRegistry类-提供实例操作
public class RemoteRegionRegistry implements LookupService<String> {
private static final Logger logger = LoggerFactory.getLogger(RemoteRegionRegistry.class);
private final ApacheHttpClient4 discoveryApacheClient;
private final EurekaJerseyClient discoveryJerseyClient;
private final Timer fetchRegistryTimer;
private final URL remoteRegionURL;
private final ScheduledExecutorService scheduler;
private final AtomicLong fetchRegistryGeneration = new AtomicLong(0L);
private final Lock fetchRegistryUpdateLock = new ReentrantLock();
private final AtomicReference<Applications> applications = new AtomicReference(new Applications());
private final AtomicReference<Applications> applicationsDelta = new AtomicReference(new Applications());
private final EurekaServerConfig serverConfig;
private volatile boolean readyForServingData;
private final EurekaHttpClient eurekaHttpClient;
@Inject
public RemoteRegionRegistry(EurekaServerConfig serverConfig, EurekaClientConfig clientConfig, ServerCodecs serverCodecs, String regionName, URL remoteRegionURL) {
this.serverConfig = serverConfig;
this.remoteRegionURL = remoteRegionURL;
this.fetchRegistryTimer = Monitors.newTimer(this.remoteRegionURL.toString() + "_FetchRegistry");
EurekaJerseyClientBuilder clientBuilder = (new EurekaJerseyClientBuilder()).withUserAgent("Java-EurekaClient-RemoteRegion").withEncoderWrapper(serverCodecs.getFullJsonCodec()).withDecoderWrapper(serverCodecs.getFullJsonCodec()).withConnectionTimeout(serverConfig.getRemoteRegionConnectTimeoutMs()).withReadTimeout(serverConfig.getRemoteRegionReadTimeoutMs()).withMaxConnectionsPerHost(serverConfig.getRemoteRegionTotalConnectionsPerHost()).withMaxTotalConnections(serverConfig.getRemoteRegionTotalConnections()).withConnectionIdleTimeout(serverConfig.getRemoteRegionConnectionIdleTimeoutSeconds());
if (remoteRegionURL.getProtocol().equals("http")) {
clientBuilder.withClientName("Discovery-RemoteRegionClient-" + regionName);
} else if ("true".equals(System.getProperty("com.netflix.eureka.shouldSSLConnectionsUseSystemSocketFactory"))) {
clientBuilder.withClientName("Discovery-RemoteRegionSystemSecureClient-" + regionName).withSystemSSLConfiguration();
} else {
clientBuilder.withClientName("Discovery-RemoteRegionSecureClient-" + regionName).withTrustStoreFile(serverConfig.getRemoteRegionTrustStore(), serverConfig.getRemoteRegionTrustStorePassword());
}
this.discoveryJerseyClient = clientBuilder.build();
this.discoveryApacheClient = this.discoveryJerseyClient.getClient();
if (serverConfig.shouldGZipContentFromRemoteRegion()) {
this.discoveryApacheClient.addFilter(new GZIPContentEncodingFilter(false));
}
String ip = null;
try {
ip = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException var14) {
logger.warn("Cannot find localhost ip", var14);
}
EurekaServerIdentity identity = new EurekaServerIdentity(ip);
this.discoveryApacheClient.addFilter(new EurekaIdentityHeaderFilter(identity));
EurekaHttpClient newEurekaHttpClient = null;
try {
ClusterResolver clusterResolver = StaticClusterResolver.fromURL(regionName, remoteRegionURL);
newEurekaHttpClient = EurekaServerHttpClients.createRemoteRegionClient(serverConfig, clientConfig.getTransportConfig(), serverCodecs, clusterResolver);
} catch (Exception var13) {
logger.warn("Transport initialization failure", var13);
}
this.eurekaHttpClient = newEurekaHttpClient;
try {
if (this.fetchRegistry()) {
this.readyForServingData = true;
} else {
logger.warn("Failed to fetch remote registry. This means this eureka server is not ready for serving traffic.");
}
} catch (Throwable var12) {
logger.error("Problem fetching registry information :", var12);
}
Runnable remoteRegionFetchTask = new Runnable() {
public void run() {
try {
//异步线程:远端注册
if (RemoteRegionRegistry.this.fetchRegistry()) {
RemoteRegionRegistry.this.readyForServingData = true;
} else {
RemoteRegionRegistry.logger.warn("Failed to fetch remote registry. This means this eureka server is not ready for serving traffic.");
}
} catch (Throwable var2) {
RemoteRegionRegistry.logger.error("Error getting from remote registry :", var2);
}
}
};
//启动定时任务 拉取远程instance到本地
ThreadPoolExecutor remoteRegionFetchExecutor = new ThreadPoolExecutor(1, serverConfig.getRemoteRegionFetchThreadPoolSize(), 0L, TimeUnit.SECONDS, new SynchronousQueue());
this.scheduler = Executors.newScheduledThreadPool(1, (new ThreadFactoryBuilder()).setNameFormat("Eureka-RemoteRegionCacheRefresher_" + regionName + "-%d").setDaemon(true).build());
this.scheduler.schedule(new TimedSupervisorTask("RemoteRegionFetch_" + regionName, this.scheduler, remoteRegionFetchExecutor, serverConfig.getRemoteRegionRegistryFetchInterval(), TimeUnit.SECONDS, 5, remoteRegionFetchTask), (long)serverConfig.getRemoteRegionRegistryFetchInterval(), TimeUnit.SECONDS);
}
public boolean isReadyForServingData() {
return this.readyForServingData;
}
//远端注册
private boolean fetchRegistry() {
Stopwatch tracer = this.fetchRegistryTimer.start();
boolean var4;
try {
boolean success;
if (!this.serverConfig.shouldDisableDeltaForRemoteRegions() && this.getApplications() != null && this.getApplications().getRegisteredApplications().size() != 0) {
success = this.fetchAndStoreDelta();
} else {
logger.info("Disable delta property : {}", this.serverConfig.shouldDisableDeltaForRemoteRegions());
logger.info("Application is null : {}", this.getApplications() == null);
logger.info("Registered Applications size is zero : {}", this.getApplications().getRegisteredApplications().isEmpty());
success = this.storeFullRegistry();
}
this.logTotalInstances();
return success;
} catch (Throwable var8) {
logger.error("Unable to fetch registry information from the remote registry {}", this.remoteRegionURL, var8);
var4 = false;
} finally {
if (tracer != null) {
tracer.stop();
}
}
return var4;
}
//
private boolean fetchAndStoreDelta() throws Throwable {
//获取本地instance
long currGeneration = this.fetchRegistryGeneration.get();
//获取远端注册instance
Applications delta = this.fetchRemoteRegistry(true);
if (delta == null) {
logger.error("The delta is null for some reason. Not storing this information");
//两者对比
} else if (this.fetchRegistryGeneration.compareAndSet(currGeneration, currGeneration + 1L)) {
this.applicationsDelta.set(delta);
} else {
delta = null;
logger.warn("Not updating delta as another thread is updating it already");
}
if (delta == null) {
logger.warn("The server does not allow the delta revision to be applied because it is not safe. Hence got the full registry.");
return this.storeFullRegistry();
} else {
String reconcileHashCode = "";
if (this.fetchRegistryUpdateLock.tryLock()) {
try {
this.updateDelta(delta);
reconcileHashCode = this.getApplications().getReconcileHashCode();
} finally {
this.fetchRegistryUpdateLock.unlock();
}
} else {
logger.warn("Cannot acquire update lock, aborting updateDelta operation of fetchAndStoreDelta");
}
if (!reconcileHashCode.equals(delta.getAppsHashCode())) {
return this.reconcileAndLogDifference(delta, reconcileHashCode);
} else {
return delta != null;
}
}
}
private void updateDelta(Applications delta) {
int deltaCount = 0;
Iterator var3 = delta.getRegisteredApplications().iterator();
while(var3.hasNext()) {
Application app = (Application)var3.next();
Iterator var5 = app.getInstances().iterator();
while(var5.hasNext()) {
InstanceInfo instance = (InstanceInfo)var5.next();
++deltaCount;
Application existingApp;
if (ActionType.ADDED.equals(instance.getActionType())) {
existingApp = this.getApplications().getRegisteredApplications(instance.getAppName());
if (existingApp == null) {
this.getApplications().addApplication(app);
}
logger.debug("Added instance {} to the existing apps ", instance.getId());
this.getApplications().getRegisteredApplications(instance.getAppName()).addInstance(instance);
} else if (ActionType.MODIFIED.equals(instance.getActionType())) {
existingApp = this.getApplications().getRegisteredApplications(instance.getAppName());
if (existingApp == null) {
this.getApplications().addApplication(app);
}
logger.debug("Modified instance {} to the existing apps ", instance.getId());
this.getApplications().getRegisteredApplications(instance.getAppName()).addInstance(instance);
} else if (ActionType.DELETED.equals(instance.getActionType())) {
existingApp = this.getApplications().getRegisteredApplications(instance.getAppName());
if (existingApp == null) {
this.getApplications().addApplication(app);
}
logger.debug("Deleted instance {} to the existing apps ", instance.getId());
this.getApplications().getRegisteredApplications(instance.getAppName()).removeInstance(instance);
}
}
}
logger.debug("The total number of instances fetched by the delta processor : {}", deltaCount);
}
private void closeResponse(ClientResponse response) {
if (response != null) {
try {
response.close();
} catch (Throwable var3) {
logger.error("Cannot release response resource :", var3);
}
}
}
public boolean storeFullRegistry() {
long currentGeneration = this.fetchRegistryGeneration.get();
Applications apps = this.fetchRemoteRegistry(false);
if (apps == null) {
logger.error("The application is null for some reason. Not storing this information");
} else {
if (this.fetchRegistryGeneration.compareAndSet(currentGeneration, currentGeneration + 1L)) {
this.applications.set(apps);
this.applicationsDelta.set(apps);
logger.info("Successfully updated registry with the latest content");
return true;
}
logger.warn("Not updating applications as another thread is updating it already");
}
return false;
}
private Applications fetchRemoteRegistry(boolean delta) {
logger.info("Getting instance registry info from the eureka server : {} , delta : {}", this.remoteRegionURL, delta);
if (this.shouldUseExperimentalTransport()) {
try {
EurekaHttpResponse<Applications> httpResponse = delta ? this.eurekaHttpClient.getDelta(new String[0]) : this.eurekaHttpClient.getApplications(new String[0]);
int httpStatus = httpResponse.getStatusCode();
if (httpStatus >= 200 && httpStatus < 300) {
logger.debug("Got the data successfully : {}", httpStatus);
return (Applications)httpResponse.getEntity();
}
logger.warn("Cannot get the data from {} : {}", this.remoteRegionURL, httpStatus);
} catch (Throwable var10) {
logger.error("Can't get a response from {}", this.remoteRegionURL, var10);
}
} else {
ClientResponse response = null;
try {
String urlPath = delta ? "apps/delta" : "apps/";
response = (ClientResponse)this.discoveryApacheClient.resource(this.remoteRegionURL + urlPath).accept(new MediaType[]{MediaType.APPLICATION_JSON_TYPE}).get(ClientResponse.class);
int httpStatus = response.getStatus();
if (httpStatus >= 200 && httpStatus < 300) {
logger.debug("Got the data successfully : {}", httpStatus);
Applications var5 = (Applications)response.getEntity(Applications.class);
return var5;
}
logger.warn("Cannot get the data from {} : {}", this.remoteRegionURL, httpStatus);
} catch (Throwable var11) {
logger.error("Can't get a response from {}", this.remoteRegionURL, var11);
} finally {
this.closeResponse(response);
}
}
return null;
}
private boolean reconcileAndLogDifference(Applications delta, String reconcileHashCode) throws Throwable {
logger.warn("The Reconcile hashcodes do not match, client : {}, server : {}. Getting the full registry", reconcileHashCode, delta.getAppsHashCode());
long currentGeneration = this.fetchRegistryGeneration.get();
Applications apps = this.fetchRemoteRegistry(false);
if (apps == null) {
logger.error("The application is null for some reason. Not storing this information");
return false;
} else if (this.fetchRegistryGeneration.compareAndSet(currentGeneration, currentGeneration + 1L)) {
this.applications.set(apps);
this.applicationsDelta.set(apps);
logger.warn("The Reconcile hashcodes after complete sync up, client : {}, server : {}.", this.getApplications().getReconcileHashCode(), delta.getAppsHashCode());
return true;
} else {
logger.warn("Not setting the applications map as another thread has advanced the update generation");
return true;
}
}
private void logTotalInstances() {
int totInstances = 0;
Application application;
for(Iterator var2 = this.getApplications().getRegisteredApplications().iterator(); var2.hasNext(); totInstances += application.getInstancesAsIsFromEureka().size()) {
application = (Application)var2.next();
}
logger.debug("The total number of all instances in the client now is {}", totInstances);
}
public Applications getApplications() {
return (Applications)this.applications.get();
}
public InstanceInfo getNextServerFromEureka(String arg0, boolean arg1) {
return null;
}
public Application getApplication(String appName) {
return ((Applications)this.applications.get()).getRegisteredApplications(appName);
}
public List<InstanceInfo> getInstancesById(String id) {
List<InstanceInfo> list = Collections.emptyList();
Iterator var3 = ((Applications)this.applications.get()).getRegisteredApplications().iterator();
InstanceInfo info;
do {
if (!var3.hasNext()) {
return list;
}
Application app = (Application)var3.next();
info = app.getByInstanceId(id);
} while(info == null);
list.add(info);
return list;
}
public Applications getApplicationDeltas() {
return (Applications)this.applicationsDelta.get();
}
private boolean shouldUseExperimentalTransport() {
if (this.eurekaHttpClient == null) {
return false;
} else {
String enabled = this.serverConfig.getExperimental("transport.enabled");
return enabled != null && "true".equalsIgnoreCase(enabled);
}
}
}