服务自动注册的自动装配
服务自动注册的自动装配由类 ConsulAutoServiceRegistrationAutoConfiguration 完成。
类 ConsulAutoServiceRegistrationAutoConfiguration 上有一堆注解:
@Configuration
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
@ConditionalOnMissingBean(type = "org.springframework.cloud.consul.discovery.ConsulLifecycle")
@ConditionalOnConsulEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
@AutoConfigureAfter(ConsulServiceRegistryAutoConfiguration.class)
public class ConsulAutoServiceRegistrationAutoConfiguration {}
逐个看:
@Configuration
表明是Configuration,后面会有对应的方法和 @bean 注解来提供bean.
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
表明需要在类 AutoServiceRegistrationProperties 的bean存在时才生效。
@ConditionalOnMissingBean(type = "org.springframework.cloud.consul.discovery.ConsulLifecycle")
表明只有有类 ConsulLifecycle 的bean不存在时才生效。
@ConditionalOnConsulEnabled
Consul的开关配置,见下面。
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
表明只有配置项
spring.cloud.service-registry.auto-registration.enabled
设置为开启才有效,当然如果没有设置则视为true。同样注意这个配置项是 spring cloud 的统一配置,不是 consul 特有的。@AutoConfigureAfter(ConsulServiceRegistryAutoConfiguration.class)
表明在 ConsulServiceRegistryAutoConfiguration 配置完成之后再配置。
细看一下 @ConditionalOnConsulEnabled的内容:
@Conditional(ConditionalOnConsulEnabled.OnConsulEnabledCondition.class)
public @interface ConditionalOnConsulEnabled {
class OnConsulEnabledCondition extends AllNestedConditions {
public OnConsulEnabledCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}
// 可以通过 spring.cloud.consul.enabled 做设置
@ConditionalOnProperty(value = "spring.cloud.consul.enabled", matchIfMissing = true)
static class FoundProperty {}
// 要有类 ConsulClient
@ConditionalOnClass(ConsulClient.class)
static class FoundClass {}
}
}
总结,ConsulAutoServiceRegistrationAutoConfiguration 要生效,条件如下:
- 类 AutoServiceRegistrationProperties 的bean存在
- 类 ConsulLifecycle 的bean不存在
- 配置项
spring.cloud.service-registry.auto-registration.enabled
设置为开启 - 配置项 spring.cloud.consul.enabled 设置为开启
- 要有类 ConsulClient 存在
自动装配的Bean
bean ConsulAutoServiceRegistration
@Bean
@ConditionalOnMissingBean
public ConsulAutoServiceRegistration consulAutoServiceRegistration(ConsulServiceRegistry registry, ConsulDiscoveryProperties properties, ConsulAutoRegistration consulRegistration) {
return new ConsulAutoServiceRegistration(registry, properties, consulRegistration);
}
这个方法在参数中传进来的 ConsulServiceRegistry 和 ConsulDiscoveryProperties 这两个bean都是在 ConsulServiceRegistryAutoConfiguration 里面创建的。所以要通过 @AutoConfigureAfter(ConsulServiceRegistryAutoConfiguration.class)
来设置初始化顺序。
bean ConsulAutoRegistration
@Bean
@ConditionalOnMissingBean
public ConsulAutoRegistration consulRegistration(ConsulDiscoveryProperties properties, ApplicationContext applicationContext, ServletContext servletContext, HeartbeatProperties heartbeatProperties) {
return ConsulAutoRegistration.registration(properties, applicationContext, servletContext, heartbeatProperties);
}
HeartbeatProperties 同样来自 ConsulServiceRegistryAutoConfiguration。
这里比较闹心的时引入了 ServletContext,总不至于用consul做客户端服务发现也需要servlet 环境吧?
检查了一下代码,还好,只是在 ConsulAutoRegistration 的 createTags()方法中使用,取了一下ContextPath。重要的是,有 servletContext != null
的判断。
public static List<String> createTags(ConsulDiscoveryProperties properties, ServletContext servletContext) {
List<String> tags = new LinkedList<>(properties.getTags());
if(servletContext != null
&& StringUtils.hasText(servletContext.getContextPath())
&& StringUtils.hasText(servletContext.getContextPath().replaceAll("/", ""))) {
tags.add("contextPath=" + servletContext.getContextPath());
}
......
return tags;
}