Eureka Server服务端源码解析

本文详细解析了 Spring Cloud Netflix Eureka 的服务注册与发现流程。从启动入口 @EnableEurekaServer 到核心组件 PeerAwareInstanceRegistryImpl 的工作原理,深入介绍了服务注册、同步及定时任务处理等关键环节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

概况

@EnableEurekaServer-启动入口

EurekaServerMarkerConfiguration类

spring.factories

EurekaServerAutoConfiguration类-所有bean实例化

EurekaServerInitializerConfiguration类-eureka初始化&事件publish

EurekaServerBootstrap类-eureka env & context 初始化

PeerAwareInstanceRegistryImpl类-服务注册&同步

AbstractInstanceRegistry类-定时任务处理

RemoteRegionRegistry类-提供实例操作


概况

源码版本:

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);
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值