Eureka源码分析之 Client的启动流程
Eureka Client 是一个Java 客户端,用于简化与Eureka Server的交互,客户端同时也具备一个内置的、使用轮询负载算法的负载均衡器。
在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒),如果Eureka Server在多个心跳周期没有收到某个节点的心跳,Eureka Server 将会从服务注册表中把这个服务节点移除(默认90秒)。Eureka Client具有缓存的机制,即使所有的Eureka Server 都挂掉的话,客户端依然可以利用缓存中的信息消费其它服务的API。下面一起来看Client客户端相关操作的流程图。

1.从启动类入手
从启动类的@EnableDiscoveryClient注解入手看调用流程。进入 EnableDiscoveryClient 之后,通过注释知道它的作用是为了激活 DiscoveryClient:

首先是在类头使用了 import 注解引入了:EnableDiscoveryClientImportSelector。该类的主要作用是实例化:AutoServiceRegistrationConfiguration。
@Order(Ordered.LOWEST_PRECEDENCE - 100)
public class EnableDiscoveryClientImportSelector
extends SpringFactoryImportSelector<EnableDiscoveryClient> {
@Override
public String[] selectImports(AnnotationMetadata metadata) {
**//调用父类的方法,拿到通过父类方法要注入的全路径类名数组**
String[] imports = super.selectImports(metadata);
**//获得该注解(@EnableDiscoveryClient)的所有属性参数**
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
metadata.getAnnotationAttributes(getAnnotationClass().getName(), true));
**//获得属性autoRegister的值,该值默认是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]);
} else {
Environment env = getEnvironment();
if(ConfigurableEnvironment.class.isInstance(env)) {
ConfigurableEnvironment configEnv = (ConfigurableEnvironment)env;
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
map.put("spring.cloud.service-registry.auto-registration.enabled", false);
MapPropertySource propertySource = new MapPropertySource(
"springCloudDiscoveryClient", map);
configEnv.getPropertySources().addLast(propertySource);
}
}
return imports;
}
@Override
protected boolean isEnabled() {
return getEnvironment().getProperty(
"spring.cloud.discovery.enabled", Boolean.class, Boolean.TRUE);
}
@Override
protected boolean hasDefaultFactory() {
return true;
}
}
这里最终的目的是想实例化:AutoServiceRegistrationConfiguration,我们来看他做了什么:
@Configuration
@Import(AutoServiceRegistrationConfiguration.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public class AutoServiceRegistrationAutoConfiguration {
@Autowired(required = false)
private AutoServiceRegistration autoServiceRegistration;
@Autowired
private AutoServiceRegistrationProperties properties;
@PostConstruct
protected void init() {
if (autoServiceRegistration == null && this.properties.isFailFast()) {
throw new IllegalStateException("Auto Service Registration has been requested, but there is no AutoServiceRegistration bean");
}
}
}
从这里看主要目的是为了实例化:AutoServiceRegistration,AutoServiceRegistrationProperties这两个类。那么初始化这两个bean的作用是什么呢,查看调用的地方:
@Configuration
@EnableConfigurationProperties
@ConditionalOnClass(EurekaClientConfig.class)
@Import(DiscoveryClientOptionalArgsConfiguration.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",
"org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration",
"org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration"})
public class EurekaClientAutoConfiguration {
......
......
......
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient, CloudEurekaInstanceConfig instanceConfig, ApplicationInfoManager applicationInfoManager, ObjectProvider<HealthCheckHandler> healthCheckHandler) {
return EurekaRegistration.builder(instanceConfig)
.with(applicationInfoManager)
.with(eurekaClient)
.with(healthCheckHandler)
.build();
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public EurekaAutoServiceRegistration eurekaAutoServiceRegistration(ApplicationContext context, EurekaServiceRegistry registry, EurekaRegistration registration) {
return new EurekaAutoServiceRegistration(context, registry, registration);
}
......
......
......
}
原因是在这里实例化bean的时候被作为前置条件。
EurekaClientAutoConfiguration 算是到目前为止比较重要的一个类,主要做的事情包括:
-
注册 EurekaClientConfigBean ,初始化client端配置信息;
-
注册 EurekaInstanceConfigBean ,初始化客户端实例信息;
-
初始化 EurekaRegistration,EurekaServiceRegistry,EurekaAutoServiceRegistration实现Eureka服务自动注册;
-
初始化 EurekaClient ,ApplicationInfoManager。EurekaClient 的默认实现是 DiscoveryClient,是我们接下来要分析的重点;
-
初始化 EurekaHealthIndicator,为/health 端点提供Eureka相关信息,主要有Status当前实例状态和applications服务列表。
继续看 EurekaClientAutoConfiguration 又在哪里被使用:
@ConditionalOnClass(ConfigServicePropertySourceLocator.class)
@ConditionalOnProperty(value = "spring.cloud.config.discovery.enabled", matchIfMissing = false)
@Configuration
@Import({ EurekaDiscoveryClientConfiguration.class, **// this emulates @EnableDiscoveryClient, the import selector doesn't run before the bootstrap phase**
EurekaClientAutoConfiguration.class })
public class EurekaDiscoveryClientConfigServiceBootstrapConfiguration {
}
在 EurekaDiscoveryClientConfigServiceBootstrapConfiguration 类中被作为注入的对象。
而 EurekaDiscoveryClientConfigServiceBootstrapConfiguration 被引用的分地方就比较特殊,被配置在配置文件中。
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceBootstrapConfiguration
这个配置的Key部分对应着一个注解类 BootstrapConfiguration:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface BootstrapConfiguration {
**/****
\* Exclude specific auto-configuration classes such that they will never be applied.
*/
Class<?>[] exclude() default {};
}
他被使用的地方是:BootstrapApplicationListener 的 164行,在这里拿到类的全路径之后,186行进行加载类。
public class BootstrapApplicationListener
implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
......
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
......
ConfigurableApplicationContext context = null;
String configName =
Eureka Client 启动流程

本文详细解析了Eureka Client的启动流程,包括服务注册、续约、下线及服务获取等关键步骤,展示了如何通过Spring Boot注解激活DiscoveryClient,并深入分析了Eureka Discovery Client的初始化过程。
最低0.47元/天 解锁文章
721

被折叠的 条评论
为什么被折叠?



