@EnableDiscoveryClient 注解如何实现服务注册与发现
通过前面的文章,我们在每个引导类上都使用了@EnableDiscoveryClient
这个注解,这个注解的作用是让该服务放注册中心注册和从注册中心获取其他服务。今天我们就来聊聊@EnableDiscoveryClient
注解是如何进行服务注册与服务发现。
@EnableDiscoveryClient 是如何实现服务注册的?
我们首先需要了解 Spring-Cloud-Commons 这个模块,Spring-Cloud-Commons 是 Spring-Cloud 官方提供的一套抽象层,类似于 JDBC 一样,提供了一套规范,具体的实现有实现厂商去根据标准实现,在Finchley版中, Spring-Cloud-Commons 共提供了6个模块标准规范。
- actuator
- circuitbreaker
- discovery
- hypermedia
- loadbalancer
- serviceregistry
在今天的文章中,我们一起来探讨学习一下discovery
、serviceregistry
这两个模块,我们使用 alibaba 的 nacos-discovery 实现来进行学习。
@EnableDiscoveryClient 注解做了什么事?
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {
/**
* If true, the ServiceRegistry will automatically register the local server.
*/
boolean autoRegister() default true;
}
从EnableDiscoveryClient
源码可以看出该接口有一个autoRegister()
方法默认返回值是true
,它还做了一件非常重要的事,引用了EnableDiscoveryClientImportSelector
类。为什么说这个类非常重要呢?我们来看看就知道了
EnableDiscoveryClientImportSelector 类做了什么事?
@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]);
} 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;
}
}
将焦点聚集到selectImports()
方法上,该类获取了autoRegister
的值。
当autoRegister=true
时,将AutoServiceRegistrationConfiguration
类添加到自动装配中,系统就会去自动装配AutoServiceRegistrationConfiguration
类,在具体的实现中自动装配类都是在这个AutoServiceRegistrationConfiguration
类自动装配完成后才装配的,也就是说autoRegister=true
就更够实现服务注册
当autoRegister=false
时,将spring.cloud.service-registry.auto-registration.enabled
设置成了 false
,这样跟注册相关的类将不会自动装配,因为自动注册相关的类都有一个条件装配@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
,换句话说如果我们不想该服务注册到注册中心,只是想从注册中心拉取服务,我们只需要引导类上的注解改成@EnableDiscoveryClient(autoRegister = false)
nacos 是如何根据标准去实现服务注册的?
我们先看看在org.springframework.cloud.alibaba.nacos
包下的NacosDiscoveryAutoConfiguration
类
NacosDiscoveryAutoConfiguration类做了些什么?
@Configuration
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
@AutoConfigureAfter({
AutoServiceRegistrationConfiguration.class,
AutoServiceRegistrationAutoConfiguration.class })
public class NacosDiscoveryAutoConfiguration {
@Bean
public NacosServiceRegistry nacosServiceRegistry(
NacosDiscoveryProperties nacosDiscoveryProperties) {
return new NacosServiceRegistry(nacosDiscoveryProperties);
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosRegistration nacosRegistration(
NacosDiscoveryProperties nacosDiscoveryProperties,
ApplicationContext context) {
return new NacosRegistration(nacosDiscoveryProperties, context);
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosAutoServiceRegistration nacosAutoServiceRegistration(
NacosServiceRegistry registry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties,
NacosRegistration registration) {
return new NacosAutoServiceRegistration(registry,
autoServiceRegistrationProperties, registration);