eureka客户端源码解析
原文:https://blog.tookbra.com/2017/08/25/Spring-Cloud-Eureka-Client-Source/源码目录结构.├── pom.xml└── src├── main│├── java││└── org││└── springframework││
·
原文:https://blog.tookbra.com/2017/08/25/Spring-Cloud-Eureka-Client-Source/
源码目录结构
.
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── org
│ │ └── springframework
│ │ └── cloud
│ │ └── netflix
│ │ ├── eureka
│ │ │ ├── CloudEurekaClient.java
│ │ │ ├── CloudEurekaInstanceConfig.java
│ │ │ ├── CloudEurekaTransportConfig.java
│ │ │ ├── EnableEurekaClient.java
│ │ │ ├── EurekaClientAutoConfiguration.java
│ │ │ ├── EurekaClientConfigBean.java
│ │ │ ├── EurekaConstants.java
│ │ │ ├── EurekaDiscoveryClient.java
│ │ │ ├── EurekaDiscoveryClientConfiguration.java
│ │ │ ├── EurekaHealthCheckHandler.java
│ │ │ ├── EurekaHealthIndicator.java
│ │ │ ├── EurekaInstanceConfigBean.java
│ │ │ ├── InstanceInfoFactory.java
│ │ │ ├── MutableDiscoveryClientOptionalArgs.java
│ │ │ ├── config
│ │ │ │ ├── DiscoveryClientOptionalArgsConfiguration.java
│ │ │ │ ├── EurekaClientConfigServerAutoConfiguration.java
│ │ │ │ ├── EurekaDiscoveryClientConfigServiceAutoConfiguration.java
│ │ │ │ └── EurekaDiscoveryClientConfigServiceBootstrapConfiguration.java
│ │ │ ├── http
│ │ │ │ ├── EurekaApplications.java
│ │ │ │ ├── RestTemplateDiscoveryClientOptionalArgs.java
│ │ │ │ ├── RestTemplateEurekaHttpClient.java
│ │ │ │ ├── RestTemplateTransportClientFactories.java
│ │ │ │ └── RestTemplateTransportClientFactory.java
│ │ │ └── serviceregistry
│ │ │ ├── EurekaAutoServiceRegistration.java
│ │ │ ├── EurekaRegistration.java
│ │ │ └── EurekaServiceRegistry.java
│ │ └── ribbon
│ │ └── eureka
│ │ ├── DomainExtractingServerList.java
│ │ ├── EurekaRibbonClientConfiguration.java
│ │ ├── EurekaServerIntrospector.java
│ │ ├── RibbonEurekaAutoConfiguration.java
│ │ └── ZoneUtils.java
│ └── resources
│ └── META-INF
│ └── spring.factories
└── test
├── java
│ └── org
│ └── springframework
│ └── cloud
│ └── netflix
│ ├── eureka
│ │ ├── ConditionalOnRefreshScopeTests.java
│ │ ├── EurekaClientAutoConfigurationTests.java
│ │ ├── EurekaClientConfigBeanTests.java
│ │ ├── EurekaHealthCheckHandlerTests.java
│ │ ├── EurekaInstanceConfigBeanTests.java
│ │ ├── InstanceInfoFactoryTests.java
│ │ ├── config
│ │ │ ├── ConfigRefreshTests.java
│ │ │ ├── DiscoveryClientConfigServiceAutoConfigurationTests.java
│ │ │ ├── EurekaClientConfigServerAutoConfigurationTests.java
│ │ │ ├── JerseyOptionalArgsConfigurationTest.java
│ │ │ └── RestTemplateOptionalArgsConfigurationTest.java
│ │ ├── healthcheck
│ │ │ └── EurekaHealthCheckTests.java
│ │ ├── http
│ │ │ ├── EurekaServerMockApplication.java
│ │ │ ├── RestTemplateEurekaHttpClientTest.java
│ │ │ ├── RestTemplateTransportClientFactoriesTest.java
│ │ │ └── RestTemplateTransportClientFactoryTest.java
│ │ ├── sample
│ │ │ ├── ApplicationTests.java
│ │ │ ├── EurekaSampleApplication.java
│ │ │ └── RefreshEurekaSampleApplication.java
│ │ └── serviceregistry
│ │ └── EurekaServiceRegistryTests.java
│ └── ribbon
│ └── eureka
│ ├── DomainExtractingServerListTests.java
│ ├── EurekaDisabledRibbonClientIntegrationTests.java
│ ├── EurekaRibbonClientConfigurationTests.java
│ ├── EurekaRibbonClientPreprocessorIntegrationTests.java
│ ├── EurekaRibbonClientPropertyOverrideIntegrationTests.java
│ ├── RibbonClientPreprocessorIntegrationTests.java
│ ├── RibbonEurekaAutoConfigurationTests.java
│ └── ZoneUtilsTests.java
└── resources
└── application.yml
客户端启动分析
@SpringBootApplication
@EnableDiscoveryClient
public class ClientApplication {
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({EnableDiscoveryClientImportSelector.class})
public @interface EnableDiscoveryClient {
boolean autoRegister() default true;
}
@Order(Ordered.LOWEST_PRECEDENCE - 100)
public class EnableDiscoveryClientImportSelector
extends SpringFactoryImportSelector<EnableDiscoveryClient> {
@Override
public String[] selectImports(AnnotationMetadata metadata) {
String[] imports = super.selectImports(metadata);
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
metadata.getAnnotationAttributes(getAnnotationClass().getName(), true));
boolean autoRegister = attributes.getBoolean("autoRegister");
if (autoRegister) {
List<String> importsList = new ArrayList<>(Arrays.asList(imports));
importsList.add("org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
imports = importsList.toArray(new String[0]);
}
return imports;
}
...
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaClientConfigServerAutoConfiguration,\
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceAutoConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,\
org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceBootstrapConfiguration
org.springframework.cloud.client.discovery.EnableDiscoveryClient=\
org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration
@Order(2147483547)
public class EnableDiscoveryClientImportSelector extends SpringFactoryImportSelector<EnableDiscoveryClient> {
public EnableDiscoveryClientImportSelector() {
}
//返回需要加载的EurekaDiscoveryClientConfiguration bean
public String[] selectImports(AnnotationMetadata metadata) {
//org.springframework.cloud.client.discovery.EnableDiscoveryClient=\org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration
String[] imports = super.selectImports(metadata);
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(this.getAnnotationClass().getName(), true));
boolean autoRegister = attributes.getBoolean("autoRegister");
if(autoRegister) {
List<String> importsList = new ArrayList(Arrays.asList(imports));
importsList.add("org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
imports = (String[])importsList.toArray(new String[0]);
}
return imports;
}
protected boolean isEnabled() {
return ((Boolean)(new RelaxedPropertyResolver(this.getEnvironment())).getProperty("spring.cloud.discovery.enabled", Boolean.class, Boolean.TRUE)).booleanValue();
}
protected boolean hasDefaultFactory() {
return true;
}
}
@Configuration
@EnableConfigurationProperties
@ConditionalOnClass(EurekaClientConfig.class)
@ConditionalOnBean(EurekaDiscoveryClientConfiguration.Marker.class)
@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
@AutoConfigureBefore({ NoopDiscoveryClientAutoConfiguration.class,
CommonsClientAutoConfiguration.class, ServiceRegistryAutoConfiguration.class })
@AutoConfigureAfter(name = "org.springframework.cloud.autoconfigure.RefreshAutoConfiguration")
public class EurekaClientAutoConfiguration {
...
@Bean
public DiscoveryClient discoveryClient(EurekaInstanceConfig config,
EurekaClient client) {
return new EurekaDiscoveryClient(config, client);
}
@Configuration
@ConditionalOnRefreshScope
protected static class RefreshableEurekaClientConfiguration {
@Autowired
private ApplicationContext context;
@Autowired(required = false)
private DiscoveryClientOptionalArgs optionalArgs;
@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) {
manager.getInfo(); // force initialization
return new CloudEurekaClient(manager, config, this.optionalArgs,
this.context);
}
@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);
}
}
@Bean
public DiscoveryClient discoveryClient(EurekaInstanceConfig config,
EurekaClient client) {
return new EurekaDiscoveryClient(config, client);
}
...
}
public class EurekaAutoServiceRegistration implements AutoServiceRegistration, SmartLifecycle, Ordered {
...
@Override
public void start() {
// only set the port if the nonSecurePort is 0 and this.port != 0
if (this.port.get() != 0 && this.registration.getNonSecurePort() == 0) {
this.registration.setNonSecurePort(this.port.get());
}
// only initialize if nonSecurePort is greater than 0 and it isn't already running
// because of containerPortInitializer below
if (!this.running.get() && this.registration.getNonSecurePort() > 0) {
// 设置 eureka 初始化状态 eureka.instance.initial-status
this.serviceRegistry.register(this.registration);
// 传递eureka注册事件
// DiscoveryClientHealthIndicator类监听
this.context.publishEvent(
new InstanceRegisteredEvent<>(this, this.registration.getInstanceConfig()));
// 设置在spring容器关闭的时候执行stop方法
this.running.set(true);
}
}
....
}
public class EurekaServiceRegistry implements ServiceRegistry<EurekaRegistration> {
public void register(EurekaRegistration reg) {
maybeInitializeClient(reg);
if (log.isInfoEnabled()) {
log.info("Registering application " + reg.getInstanceConfig().getAppname()
+ " with eureka with status "
+ reg.getInstanceConfig().getInitialStatus());
}
reg.getApplicationInfoManager()
.setInstanceStatus(reg.getInstanceConfig().getInitialStatus());
if (reg.getHealthCheckHandler() != null) {
reg.getEurekaClient().registerHealthCheck(reg.getHealthCheckHandler());
}
}
}
@Singleton
public class DiscoveryClient implements EurekaClient {
@Inject
DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args,
Provider<BackupRegistry> backupRegistryProvider) {
if (args != null) {
this.healthCheckHandlerProvider = args.healthCheckHandlerProvider;
this.healthCheckCallbackProvider = args.healthCheckCallbackProvider;
this.eventListeners.addAll(args.getEventListeners());
} else {
this.healthCheckCallbackProvider = null;
this.healthCheckHandlerProvider = null;
}
this.applicationInfoManager = applicationInfoManager;
//获取 instance
InstanceInfo myInfo = applicationInfoManager.getInfo();
//客户端配置
clientConfig = config;
staticClientConfig = clientConfig;
//传输配置,心跳时间等
transportConfig = config.getTransportConfig();
instanceInfo = myInfo;
if (myInfo != null) {
appPathIdentifier = instanceInfo.getAppName() + "/" + instanceInfo.getId();
} else {
logger.warn("Setting instanceInfo to a passed in null value");
}
this.backupRegistryProvider = backupRegistryProvider;
this.urlRandomizer = new EndpointUtils.InstanceInfoBasedUrlRandomizer(instanceInfo);
localRegionApps.set(new Applications());
fetchRegistryGeneration = new AtomicLong(0);
remoteRegionsToFetch = new AtomicReference<String>(clientConfig.fetchRegistryForRemoteRegions());
remoteRegionsRef = new AtomicReference<>(remoteRegionsToFetch.get() == null ? null : remoteRegionsToFetch.get().split(","));
//是否需要信息检索 eureka.client.fetchRegistry=true
//
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;
}
//是否注册到eureka eureka.client.registerWithEureka=true
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;
}
logger.info("Initializing Eureka in region {}", clientConfig.getRegion());
//如果不开启注册到eureka和从eureka检索服务
//把定时任务、心跳设置为null
if (!config.shouldRegisterWithEureka() && !config.shouldFetchRegistry()) {
logger.info("Client configured to neither register nor query for data.");
scheduler = null;
heartbeatExecutor = null;
cacheRefreshExecutor = null;
eurekaTransport = null;
instanceRegionChecker = new InstanceRegionChecker(new PropertyBasedAzToRegionMapper(config), clientConfig.getRegion());
// This is a bit of hack to allow for existing code using DiscoveryManager.getInstance()
// to work with DI'd DiscoveryClient
DiscoveryManager.getInstance().setDiscoveryClient(this);
DiscoveryManager.getInstance().setEurekaClientConfig(config);
initTimestampMs = System.currentTimeMillis();
logger.info("Discovery Client initialized at timestamp {} with initial instances count: {}",
initTimestampMs, this.getApplications().size());
return; // no need to setup up an network tasks and we are done
}
// 配置作业
try {
scheduler = Executors.newScheduledThreadPool(3,
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
eurekaTransport = new EurekaTransport();
scheduleServerEndpointTask(eurekaTransport, args);
AzToRegionMapper azToRegionMapper;
// eureka.client.use-dns-for-fetching-service-urls
if (clientConfig.shouldUseDnsForFetchingServiceUrls()) {
azToRegionMapper = new DNSBasedAzToRegionMapper(clientConfig);
} else {
azToRegionMapper = new PropertyBasedAzToRegionMapper(clientConfig);
}
if (null != remoteRegionsToFetch.get()) {
azToRegionMapper.setRegionsToFetch(remoteRegionsToFetch.get().split(","));
}
instanceRegionChecker = new InstanceRegionChecker(azToRegionMapper, clientConfig.getRegion());
} catch (Throwable e) {
throw new RuntimeException("Failed to initialize DiscoveryClient!", e);
}
//刷新服务注册地址
if (clientConfig.shouldFetchRegistry() && !fetchRegistry(false)) {
fetchRegistryFromBackup();
}
//初始化作业,心跳,状态、缓存
initScheduledTasks();
try {
Monitors.registerObject(this);
} catch (Throwable e) {
logger.warn("Cannot register timers", e);
}
// This is a bit of hack to allow for existing code using DiscoveryManager.getInstance()
// to work with DI'd DiscoveryClient
DiscoveryManager.getInstance().setDiscoveryClient(this);
DiscoveryManager.getInstance().setEurekaClientConfig(config);
initTimestampMs = System.currentTimeMillis();
logger.info("Discovery Client initialized at timestamp {} with initial instances count: {}",
initTimestampMs, this.getApplications().size());
}
/**
* Register with the eureka service by making the appropriate REST call.
*/
boolean register() throws Throwable {
logger.info(PREFIX + appPathIdentifier + ": registering service...");
EurekaHttpResponse<Void> httpResponse;
try {
httpResponse = eurekaTransport.registrationClient.register(instanceInfo);
} catch (Exception e) {
logger.warn("{} - registration failed {}", PREFIX + appPathIdentifier, e.getMessage(), e);
throw e;
}
if (logger.isInfoEnabled()) {
logger.info("{} - registration status: {}", PREFIX + appPathIdentifier, httpResponse.getStatusCode());
}
return httpResponse.getStatusCode() == 204;
}
}
public class ApplicationInfoManager {
public synchronized void setInstanceStatus(InstanceStatus status) {
InstanceStatus next = instanceStatusMapper.map(status);
if (next == null) {
return;
}
InstanceStatus prev = instanceInfo.setStatus(next);
if (prev != null) {
for (StatusChangeListener listener : listeners.values()) {
try {
//状态改变
listener.notify(new StatusChangeEvent(prev, next));
} catch (Exception e) {
logger.warn("failed to notify listener: {}", listener.getId(), e);
}
}
}
}
}
private void initScheduledTasks() {
if (clientConfig.shouldFetchRegistry()) {
// registry cache refresh timer
int registryFetchIntervalSeconds = clientConfig.getRegistryFetchIntervalSeconds();
int expBackOffBound = clientConfig.getCacheRefreshExecutorExponentialBackOffBound();
scheduler.schedule(
new TimedSupervisorTask(
"cacheRefresh",
scheduler,
cacheRefreshExecutor,
registryFetchIntervalSeconds,
TimeUnit.SECONDS,
expBackOffBound,
new CacheRefreshThread()
),
registryFetchIntervalSeconds, TimeUnit.SECONDS);
}
if (clientConfig.shouldRegisterWithEureka()) {
int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound();
logger.info("Starting heartbeat executor: " + "renew interval is: " + renewalIntervalInSecs);
// Heartbeat timer
scheduler.schedule(
new TimedSupervisorTask(
"heartbeat",
scheduler,
heartbeatExecutor,
renewalIntervalInSecs,
TimeUnit.SECONDS,
expBackOffBound,
new HeartbeatThread()
),
renewalIntervalInSecs, TimeUnit.SECONDS);
// InstanceInfo replicator
instanceInfoReplicator = new InstanceInfoReplicator(
this,
instanceInfo,
clientConfig.getInstanceInfoReplicationIntervalSeconds(),
2); // burstSize
//这里实现了状态改变更新服务
statusChangeListener = new ApplicationInfoManager.StatusChangeListener() {
@Override
public String getId() {
return "statusChangeListener";
}
@Override
public void notify(StatusChangeEvent statusChangeEvent) {
if (InstanceStatus.DOWN == statusChangeEvent.getStatus() ||
InstanceStatus.DOWN == statusChangeEvent.getPreviousStatus()) {
// log at warn level if DOWN was involved
logger.warn("Saw local status change event {}", statusChangeEvent);
} else {
logger.info("Saw local status change event {}", statusChangeEvent);
}
instanceInfoReplicator.onDemandUpdate();
}
};
//eureka.client.on-demand-update-status-change
//默认为true,一般不设置成false
if (clientConfig.shouldOnDemandUpdateStatusChange()) {
//状态改变监听
applicationInfoManager.registerStatusChangeListener(statusChangeListener);
}
//开启
//初始化实例信息到Eureka服务端的间隔时间 eureka.client.initialInstanceInfoReplicationIntervalSeconds 默认40s
instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
} else {
logger.info("Not registering with Eureka server per configuration");
}
}
更多推荐
已为社区贡献28条内容
所有评论(0)