咱们从下面的图能够看出,做为一个client端,他有如下功能:spring
springboot的自动装配读取Eureka Client的spring.factories文件,咱们看到他里面有多个EnableAutoConfiguration,主要的类是EurekaClientAutoConfiguration。EurekaClientAutoConfiguration类中有多个bean的加载,咱们先看看EurekaInstanceConfigBean的加载。缓存
EurekaInstanceConfigBean有个@ConfigurationProperties("eureka.instance")注解,因此咱们在配置文件里写的eureka.instance.instanceId这类的信息最终都在赋值给这个类。还有比较重要的leaseRenewalIntervalInSeconds续约频率(默认每30秒)、leaseExpirationDurationInSeconds续约过时时间(默认90秒)都是在这个类配置的。springboot
@Bean @ConditionalOnMissingBean(value = EurekaInstanceConfig.class, search = SearchStrategy.CURRENT) public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils, ManagementMetadataProvider managementMetadataProvider) { // 省略部分代码 EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils); // 省略部分代码 return instance; }
ApplicationInfoManager也是在EurekaClientAutoConfiguration类中。
建立eurekaApplicationInfoManager对象的时候,会先建立InstanceInfo对象,InstanceInfo对象的值大部分是从EurekaInstanceConfig复制过来的,另外租约信息是存放在InstanceInfo的leaseInfo中。
因此初始化ApplicationInfoManager的时候,就是赋值EurekaInstanceConfig和InstanceInfo。网络
@Bean @ConditionalOnMissingBean(value = ApplicationInfoManager.class, search = SearchStrategy.CURRENT) @org.springframework.cloud.context.config.annotation.RefreshScope @Lazy public ApplicationInfoManager eurekaApplicationInfoManager( EurekaInstanceConfig config) { InstanceInfo instanceInfo = new InstanceInfoFactory().create(config); return new ApplicationInfoManager(config, instanceInfo); }
EurekaClientConfigBean也是一个配置信息的bean,他主要是EurekaClient和EurekaServer相关的信息,好比EurekaServer的地址defaultZone、是否从注册中心拉取注册信息fetchRegistry(默认true),拉取的频率registryFetchIntervalSeconds(默认每30秒)、是否向注册中心注册registerWithEureka(默认true)等。app
@Bean @ConditionalOnMissingBean(value = EurekaClientConfig.class, search = SearchStrategy.CURRENT) public EurekaClientConfigBean eurekaClientConfigBean(ConfigurableEnvironment env) { return new EurekaClientConfigBean(); }
建立一个EurekaClient类,这个类就是负责服务的注册、续约、取消、获取注册列表。dom
@Bean(destroyMethod = "shutdown") @ConditionalOnMissingBean(value = EurekaClient.class, search = SearchStrategy.CURRENT) @org.springframework.cloud.context.config.annotation.RefreshScope @Lazy public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config, EurekaInstanceConfig instance, @Autowired(required = false) HealthCheckHandler healthCheckHandler) { ApplicationInfoManager appManager; if (AopUtils.isAopProxy(manager)) { appManager = ProxyUtils.getTargetObject(manager); } else { appManager = manager; } CloudEurekaClient cloudEurekaClient = new CloudEurekaClient(appManager, config, this.optionalArgs, this.context); cloudEurekaClient.registerHealthCheck(healthCheckHandler); return cloudEurekaClient; }
结合上面几个类的加载以及EurekaClient的加载,咱们能够知道这几个类的关系以下:
在DiscoveryClient的构造函数里,主要是初始化一些配置参数,以及为拉取注册表信息、初始化定时任务。ide
@Inject DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args, Provider<BackupRegistry> backupRegistryProvider, EndpointRandomizer endpointRandomizer) { // 初始化applicationInfoManager、config等略 try { // 建立核心数为2的线程池,一个用于heartbeat,一个用于cacheRefresh // default size of 2 - 1 each for heartbeat and cacheRefresh scheduler = Executors.newScheduledThreadPool(2, new ThreadFactoryBuilder() .setNameFormat("DiscoveryClient-%d") .setDaemon(true) .build()); heartbeatExecutor = new ThreadPoolExecutor( 1, clientConfig.getHeartbeatExecutorThreadPoolSize(), 0, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadFactoryBuilder() .setNameFormat("DiscoveryClient-HeartbeatExecutor-%d") .setDaemon(true) .build() ); // use direct handoff cacheRefreshExecutor = new ThreadPoolExecutor( 1, clientConfig.getCacheRefreshExecutorThreadPoolSize(), 0, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadFactoryBuilder() .setNameFormat("DiscoveryClient-CacheRefreshExecutor-%d") .setDaemon(true) .build() ); // use direct handoff // 与EurekaServer网络通讯用的 eurekaTransport = new EurekaTransport(); scheduleServerEndpointTask(eurekaTransport, args); //其余的略 } catch (Throwable e) { throw new RuntimeException("Failed to initialize DiscoveryClient!", e); } if (clientConfig.shouldFetchRegistry()) { try { // 拉取注册表信息 boolean primaryFetchRegistryResult = fetchRegistry(false); //其余的略,没有拉取成功从备份注册中心获取 } } //其余的略 // 初始化定时任务 initScheduledTasks(); //其余的略 }
initScheduledTasks,用来开启更新服务注册列表和续租的定时任务,以及对EurekaServer的注册。函数
private void initScheduledTasks() { if (clientConfig.shouldFetchRegistry()) { // registry cache refresh timer // 这个定时任务是更新服务注册列表 // 更新频率 int registryFetchIntervalSeconds = clientConfig.getRegistryFetchIntervalSeconds(); // 延迟最大乘数,好比更新频率是5s,那最大延迟时间就是50s,这个后面讲线程的时候会具体说 int expBackOffBound = clientConfig.getCacheRefreshExecutorExponentialBackOffBound(); cacheRefreshTask = new TimedSupervisorTask( "cacheRefresh", scheduler, cacheRefreshExecutor, registryFetchIntervalSeconds, TimeUnit.SECONDS, expBackOffBound, new CacheRefreshThread() ); scheduler.schedule( cacheRefreshTask, registryFetchIntervalSeconds, TimeUnit.SECONDS); } instanceInfoReplicator = new InstanceInfoReplicator( this, instanceInfo, clientConfig.getInstanceInfoReplicationIntervalSeconds(), 2); if (clientConfig.shouldRegisterWithEureka()) { // 这个定时任务是续租 // 续约频率 int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs(); int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound(); logger.info("Starting heartbeat executor: " + "renew interval is: {}", renewalIntervalInSecs); // Heartbeat timer heartbeatTask = new TimedSupervisorTask( "heartbeat", scheduler, heartbeatExecutor, renewalIntervalInSecs, TimeUnit.SECONDS, expBackOffBound, new HeartbeatThread() ); scheduler.schedule( heartbeatTask, renewalIntervalInSecs, TimeUnit.SECONDS); // 其余的略 // 注册到注册中心 instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds()); } else { logger.info("Not registering with Eureka server per configuration"); } }
好了,以上对EurekaServer的注册、续租、注册表获取都说起到了,后面再详细的讲解这些内容。fetch