Consul初始化过程中涉及三个核心包,分别为spring-cloud-consul-core、spring-cloud-consul-config、spring-cloud-consul-discovery。
spring-cloud-consul-core包涉及核心类ConsulAutoConfiguration。
spring-cloud-consul-discovery包涉及核心类如下:ConsulServiceRegistryAutoConfiguration、ConsulAutoServiceRegistrationAutoConfiguration等。
1.核心包core涉及的核心类ConsulAutoConfiguration
public class ConsulAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public ConsulProperties consulProperties() {
return new ConsulProperties();
}
@Bean
@ConditionalOnMissingBean
public ConsulClient consulClient(ConsulProperties consulProperties) {
final int agentPort = consulProperties.getPort();
final String agentHost = !StringUtils.isEmpty(consulProperties.getScheme())
? consulProperties.getScheme() + "://" + consulProperties.getHost()
: consulProperties.getHost();
...
return new ConsulClient(agentHost, agentPort);
}
}
ConsulProperties:控制服务是否接入consul集群的开关、服务注册端口8500等信息。
2.核心包discovery的核心类
2.1.ConsulServiceRegistryAutoConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnConsulEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.enabled",matchIfMissing = true)
@AutoConfigureBefore(ServiceRegistryAutoConfiguration.class)
public class ConsulServiceRegistryAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public ConsulServiceRegistry consulServiceRegistry(ConsulClient consulClient,
ConsulDiscoveryProperties properties, HeartbeatProperties heartbeatProperties,
@Autowired(required = false) TtlScheduler ttlScheduler) {
return new ConsulServiceRegistry(consulClient, properties, ttlScheduler,
heartbeatProperties);
}
@Bean
@ConditionalOnMissingBean
public HeartbeatProperties heartbeatProperties() {
return new HeartbeatProperties();//服务与consul服务端之间心跳检测相关配置
}
@Bean
@ConditionalOnMissingBean
public ConsulDiscoveryProperties consulDiscoveryProperties(InetUtils inetUtils) {
return new ConsulDiscoveryProperties(inetUtils);
}
}
ConsulDiscoveryProperties:服务注册相关属性配置。包括健康检查地址。
2.2.ConsulAutoServiceRegistrationAutoConfiguration
服务注册的核心类。该类的核心目的是初始化事件监听器ConsulAutoServiceRegistrationListener。#5
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
@ConditionalOnMissingBean(type = "org.springframework.cloud.consul.discovery.ConsulLifecycle")
@ConditionalOnConsulEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",matchIfMissing = true)
@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,ConsulServiceRegistryAutoConfiguration.class })
public class ConsulAutoServiceRegistrationAutoConfiguration {
@Autowired
AutoServiceRegistrationProperties autoServiceRegistrationProperties;
@Bean
@ConditionalOnMissingBean
public ConsulAutoServiceRegistration consulAutoServiceRegistration(
ConsulServiceRegistry registry,AutoServiceRegistrationProperties asrp,
ConsulDiscoveryProperties properties,ConsulAutoRegistration consulRegistration) {
return new ConsulAutoServiceRegistration(registry,asrp, properties, consulRegistration);
}
// 真正触发注册功能。
//监听器构造器构造参数:ConsulAutoServiceRegistration
//ConsulAutoServiceRegistration构造器构造参数包含ConsulAutoRegistration实例化
@Bean
public ConsulAutoServiceRegistrationListener consulAutoServiceRegistrationListener(
ConsulAutoServiceRegistration registration) {
return new ConsulAutoServiceRegistrationListener(registration);
}
@Bean
@ConditionalOnMissingBean
public ConsulAutoRegistration consulRegistration(
AutoServiceRegistrationProperties autoServiceRegistrationProperties,
ConsulDiscoveryProperties properties, ApplicationContext applicationContext,
ObjectProvider<List<ConsulRegistrationCustomizer>> registrationCustomizers,
ObjectProvider<List<ConsulManagementRegistrationCustomizer>> managementRegistrationCustomizers,
HeartbeatProperties heartbeatProperties) {
return ConsulAutoRegistration.registration(autoServiceRegistrationProperties,
properties, applicationContext, registrationCustomizers.getIfAvailable(),
managementRegistrationCustomizers.getIfAvailable(), heartbeatProperties);
}
...
}
3.2.1、ConsulAutoRegistration
如果NewService其port属性为null,并且并没有Management相关属性的显式配置,则健康检查地址为:
http://IP:server.port/actuator/health
public class ConsulAutoRegistration extends ConsulRegistration {
public static ConsulAutoRegistration registration(
AutoServiceRegistrationProperties autoServiceRegistrationProperties,
ConsulDiscoveryProperties properties, ApplicationContext context,
List<ConsulRegistrationCustomizer> registrationCustomizers,
List<ConsulManagementRegistrationCustomizer> managementRegistrationCustomizers,
HeartbeatProperties heartbeatProperties) {
// NewService是consul对应用服务实例的抽象
NewService service = new NewService();
//优先获取properties中serviceName,其次spring.application.name,再次application。目的就是定义注册中心中服务名
String appName = getAppName(properties, context.getEnvironment());
service.setId(getInstanceId(properties, context));
if (!properties.isPreferAgentAddress()) {
service.setAddress(properties.getHostname());
}
service.setName(normalizeForDns(appName));
service.setTags(createTags(properties));
if (properties.getPort() != null) {
service.setPort(properties.getPort());
setCheck(service, autoServiceRegistrationProperties, properties, context,
heartbeatProperties);
}
ConsulAutoRegistration registration = new ConsulAutoRegistration(service,
autoServiceRegistrationProperties, properties, context,
heartbeatProperties, managementRegistrationCustomizers);
customize(registrationCustomizers, registration);
return registration;
}
...
}
NewService中静态类check表示consul健康检查相关设置。除非的前提是配置类ConsulDiscoveryProperties中端口号不能为空。
注意:配置类ConsulDiscoveryProperties中端口号为server.port。
check的相关属性赋值存在两种情况,要不是采取默认值,要不使用Management配置相关属性。
如果选择Management配置相关属性存在三个条件,如下:
- AutoServiceRegistrationProperties配置类其属性registerManagement为true【默认值】。
- ManagementServerProperties配置类的端口号不能为空。
- 并且不能和server.port一致。
再者,就是自定义健康检查接口api:优先选择配置类ConsulDiscoveryProperties中healthCheckUrl配置的值,否则选择默认值healthCheckPath = “/actuator/health”。
4、服务注册监听器之ConsulAutoServiceRegistrationListener
public class ConsulAutoServiceRegistrationListener implements SmartApplicationListener {
// ConsulAutoServiceRegistration
private final ConsulAutoServiceRegistration autoServiceRegistration;
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return WebServerInitializedEvent.class.isAssignableFrom(eventType);
}
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
if (applicationEvent instanceof WebServerInitializedEvent) {
WebServerInitializedEvent event = (WebServerInitializedEvent) applicationEvent;
ApplicationContext context = event.getApplicationContext();
//autoServiceRegistration:ConsulAutoServiceRegistration
this.autoServiceRegistration.setPortIfNeeded(event.getWebServer().getPort());//设置端口
this.autoServiceRegistration.start();// 开始注册
}
}
}
- ConsulAutoServiceRegistrationListener是监听WebServerInitializedEvent事件的监听器。
- 服务注册是通过
事件发布机制
触发的。其原理参考WebServerInitializedEvent事件
。 - 设置AbstractAutoServiceRegistration中属性port值为当前应用服务的端口。
4.1、AbstractAutoServiceRegistration
public void start() {
if (!this.running.get()) {
this.context.publishEvent(
new InstancePreRegisteredEvent(this, getRegistration()));
register();//继续注册,调用当前抽象类的子类ConsulAutoServiceRegistration
if (shouldRegisterManagement()) {
registerManagement();
}
this.context.publishEvent(
new InstanceRegisteredEvent<>(this, getConfiguration()));
this.running.compareAndSet(false, true);
}
}
针对InstancePreRegisteredEvent、InstanceRegisteredEvent事件,应用服务可以实现对应的监听器,在服务注册前后获取相关的注册信息。
4.1.1、尝试设置NewService相关属性
protected ConsulAutoRegistration getRegistration() {
//registration:ConsulAutoRegistration
if (this.registration.getService().getPort() == null
&& this.getPort().get() > 0) {
this.registration.initializePort(this.getPort().get());
}
return this.registration;
}
- this.registration.getService():指的是NewService,应用服务实例的抽象。
- 如果NewService中端口号没有设置,则初始化为应用服务的端口号。
- 如果NewService中端口号没有设置,则初始化用于对应用服务健康检查的相关check信息。
4.1.2、ConsulServiceRegistry
// ConsulAutoServiceRegistration#register
protected void register() {
if (!this.properties.isRegister()) {//ConsulDiscoveryProperties
return;
}
super.register();//AbstractAutoServiceRegistration#register
}
spring.cloud.consul.discovery.register = false
,该配置控制当前应用服务是否在consul UI界面展示,其应用服务正常加入consul集群提供服务。spring.cloud.consul.enabled = false
,该配置当前应用服务是否加入consul集群。
protected void register() {
// 3.1 #ConsulServiceRegistry
this.serviceRegistry.register(getRegistration());
}
4.2、ConsulServiceRegistry
public void register(ConsulRegistration reg) {
this.client.agentServiceRegister(reg.getService(),this.properties.getAclToken());//
NewService service = reg.getService();
if (this.heartbeatProperties.isEnabled() && this.ttlScheduler != null
&& service.getCheck() != null
&& service.getCheck().getTtl() != null) {
this.ttlScheduler.add(reg.getInstanceId());
}
}
- client为ConsulClient。
- 注册地址:http://localhost:8500/v1/agent/service/register。
6、Management
如果配置类ConsulDiscoveryProperties的属性healthCheckUrl显式设置,则该种方式获取的端口没有任何意义。
public static boolean shouldRegisterManagement(
AutoServiceRegistrationProperties autoServiceRegistrationProperties,
ConsulDiscoveryProperties properties, ApplicationContext context) {
// registerManagement默认为TRUE
return autoServiceRegistrationProperties.isRegisterManagement()
&& getManagementPort(properties, context) != null
&& ManagementServerPortUtils.isDifferent(context);
}
6.1、getManagementPort
AutoServiceRegistrationProperties:spring.cloud.service-registry.auto-registration
通过Management获取端口号方式:
- AutoServiceRegistrationProperties配置类属性registerManagement为TRUE。
- ConsulDiscoveryProperties配置类属性managementPort是否存在。
- ManagementServerProperties配置类属性port是否存在。
public static Integer getManagementPort(ConsulDiscoveryProperties properties,
ApplicationContext context) {
// If an alternate external port is specified, use it instead
if (properties.getManagementPort() != null) {
return properties.getManagementPort();
}
return ManagementServerPortUtils.getPort(context);
}
public static Integer getPort(BeanFactory beanFactory) {
ManagementServerProperties properties = beanFactory.getBean(ManagementServerProperties.class);
return properties.getPort();
}
6.2、ManagementServerPortUtils.isDifferent
public static boolean isDifferent(BeanFactory beanFactory) {
return get(beanFactory) == ManagementServerPort.DIFFERENT;
}
public static ManagementServerPort get(BeanFactory beanFactory) {
serverProperties = beanFactory.getBean(ServerProperties.class);//为了获取应用服务的端口
ManagementServerProperties managementServerProperties = beanFactory.getBean(ManagementServerProperties.class);
Integer port = managementServerProperties.getPort();
if (port != null && port < 0) {
return DISABLE;
}
if (!(beanFactory instanceof WebApplicationContext)) {
// Current context is not a webapp
return DIFFERENT;
}
return ((port == null)
|| (serverProperties.getPort() == null && port.equals(8080))
|| (port != 0 && port.equals(serverProperties.getPort())) ? SAME
: DIFFERENT);
}
7、RibbonConsulAutoConfiguration
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConditionalOnConsulEnabled
@ConditionalOnBean(SpringClientFactory.class)
@ConditionalOnProperty(value = "spring.cloud.consul.ribbon.enabled",
matchIfMissing = true)
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@RibbonClients(defaultConfiguration = ConsulRibbonClientConfiguration.class)
public class RibbonConsulAutoConfiguration {}
ConsulRibbonClientConfiguration其实重写了RibbonClientConfiguration中部分默认的负载策略。
public class ConsulRibbonClientConfiguration {
...
@Bean
@ConditionalOnMissingBean
public ServerList<?> ribbonServerList(IClientConfig config,
ConsulDiscoveryProperties properties) {
ConsulServerList serverList = new ConsulServerList(this.client, properties);
serverList.initWithNiwsConfig(config);
return serverList;
}
@Bean
@ConditionalOnMissingBean
public ServerListFilter<Server> ribbonServerListFilter() {
return new HealthServiceServerListFilter();
}
@Bean
@ConditionalOnMissingBean
public IPing ribbonPing() {
return new ConsulPing();
}
@Bean
@ConditionalOnMissingBean
public ConsulServerIntrospector serverIntrospector() {
return new ConsulServerIntrospector();
}
}
分别重写了ribbonServerList、ribbonServerListFilter、ribbonPing等。发现机制利用ribbon的功能实现的。