@EnableDiscoveryClient与Nacos的服务注册与拉取
前一阵看到有篇博客说cloud从Edgware版本开始,可以不加@EnableDiscoveryClient注解,只要配置好注册中心的相关配置即可自动开启服务注册功能,比较好奇其中的原理,研究了一番特意记录下来
环境:
SpringBoot: 2.3.5
SpringCloud: Hoxton.SR8
SpringCloudAlibaba: 2.2.3
配置信息:
@SpringBootApplication
//autoRegiste属性值默认为true可以不配置此属性
@EnableDiscoveryClient(autoRegister = true)
public class NacosApplication {
public static void main(String[] args) {
SpringApplication.run(NacosApplication.class, args);
}
}
spring:
application:
name: nacosTest
cloud:
nacos:
discovery:
enabled: true(默认为true,可以不配置此属性)
server-addr: 192.168.1.10:8848
username: nacos
password: nacos
配置的作用:
nacos.discovery.enabled: 开启服务的注册与发现功能;
注册成功后可以在nacos的web端界面看到服务的相关信息
同时,具备拉取服务信息的功能, discoveryClient.getInstances()方法可以返回服务的详细配置信息
@Resource
private DiscoveryClient discoveryClient;
@GetMapping("/client")
public List<ServiceInstance> client() {
return discoveryClient.getInstances("服务名称");
}
@EnableDiscoveryClient(autoRegister = true); 开启服务自动注册功能,项目启动后能在nacos的web端界面看到服务的相关信息,并且具备拉取服务信息的功能(前提是nacos.discovery.enabled不为false)
@EnableDiscoveryClient(autoRegister = false); 关闭服务自动注册功能, 项目启动后nacos的web端界面没有此项目的信息,但是依然具备拉取服务信息的功能(前提是nacos.discovery.enabled不为false)
实现逻辑:
@EnableDiscoveryClient
打开@EnableDiscoveryClient注解(代码里只保留了重点)
@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {
boolean autoRegister() default true;
}
进入EnableDiscoveryClientImportSelector类
@Override
public String[] selectImports(AnnotationMetadata metadata) {
String[] imports = super.selectImports(metadata);
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
metadata.getAnnotationAttributes(getAnnotationClass().getName(), true));
//获取@EnableDiscoveryClient的autoRegister属性
boolean autoRegister = attributes.getBoolean("autoRegister");
//开启自动注册的话,将AutoServiceRegistrationConfiguration类的全限定名返回,会被spring加载到bean容器
if (autoRegister) {
List<String> importsList = new ArrayList<>(Arrays.asList(imports));
importsList.add(
"org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
imports = importsList.toArray(new String[0]);
}
//关闭自动注册的话,将***.auto-registration.enabled设置为false,放入环境属性中(其他地方会用到)
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;
}
既然开启自动注册服务会返回一个叫AutoServiceRegistrationConfiguration的类,那就打开看一下:
此类是实现自动注册的入口,具体的逻辑在由注册中心实现(如Nacos\Eureka...)
//当**.registration.enabled属性为true时,此配置类会被加载
//spring-cloud-commons.jar包内的spring-configuration-metadata.json定义了此属性默认为true
//即: 不配置@EnableDiscoveryClient或者配置@EnableDiscoveryClient设置autoRegister为true时
//AutoServiceRegistrationConfiguration会被加载,当@EnableDiscoveryClient设置autoRegister
//属性为false时,此配置类不会被加载
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
matchIfMissing = true)
public class AutoServiceRegistrationConfiguration {
}
到现在似乎还没发现太多有用的信息,那继续看Nacos的源码
Nacos:
找到nacos的spring.factories文件,这是配置自动配置类的地方,文件路径:
spring-cloud-starter-alibaba-nacos-discovery.jar/META-INF/spring.factories
文件信息:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration,\
com.alibaba.cloud.nacos.ribbon.RibbonNacosAutoConfiguration,\
com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration,\
com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration,\
com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,\
com.alibaba.cloud.nacos.discovery.reactive.NacosReactiveDiscoveryClientConfiguration,\
com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration,\
com.alibaba.cloud.nacos.NacosServiceAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration
既然有BootstrapConfiguration,那就先看最后一行的NacosDiscoveryClientConfigServiceBootstrapConfiguration
//删减了部分代码,便于阅读
@ImportAutoConfiguration({NacosDiscoveryClientConfiguration.class})
public class NacosDiscoveryClientConfigServiceBootstrapConfiguration {
}
继续进入NacosDiscoveryClientConfiguration
//删减了部分代码,便于阅读
//spring.cloud.nacos.discovery.enabled=true时,此配置类才会加载
@ConditionalOnNacosDiscoveryEnabled
@AutoConfigureAfter(NacosDiscoveryAutoConfiguration.class)
public class NacosDiscoveryClientConfiguration {
@Bean
public DiscoveryClient nacosDiscoveryClient(NacosServiceDiscovery nacosServiceDiscovery) {
return new NacosDiscoveryClient(nacosServiceDiscovery);
}
}
此配置类注入了一个bean: NacosDiscoveryClient, 这个类实现了DiscoveryClient接口, 我们上边的测试用例
discoveryClient.getInstances("服务名称"), 调用的getInstances方法,实际上就是调用了Nacos官方提供的NacosDiscoveryClient重写的getInstances方法,
至此,Nacos的的服务拉取搞明白了: 无论是否配置@EnableDiscoveryClient,只要spring.cloud.nacos.discovery.enabled不设置为false,服务就具有拉取注册中心信息的功能
那服务注册功能呢? 返回spring.factories打开第五行的类: NacosServiceRegistryAutoConfiguration
服务自动注册逻辑:
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
//确保spring.cloud.nacos.discovery.enabled为true(开启nacos的服务注册与发现功能)
@ConditionalOnNacosDiscoveryEnabled
//默认为true,使用@EnableDiscoveryClient注解配置autoRegister为false时,次属性值为false
//即: 此类不被加载,即: 服务不具备自动注册功能
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
matchIfMissing = true)
@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,
AutoServiceRegistrationAutoConfiguration.class,
NacosDiscoveryAutoConfiguration.class })
public class NacosServiceRegistryAutoConfiguration {
@Bean
public NacosServiceRegistry nacosServiceRegistry(
NacosDiscoveryProperties nacosDiscoveryProperties) {
return new NacosServiceRegistry(nacosDiscoveryProperties);
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosRegistration nacosRegistration(
ObjectProvider<List<NacosRegistrationCustomizer>> registrationCustomizers,
NacosDiscoveryProperties nacosDiscoveryProperties,
ApplicationContext context) {
return new NacosRegistration(registrationCustomizers.getIfAvailable(),
nacosDiscoveryProperties, context);
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosAutoServiceRegistration nacosAutoServiceRegistration(
NacosServiceRegistry registry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties,
NacosRegistration registration) {
return new NacosAutoServiceRegistration(registry,
autoServiceRegistrationProperties, registration);
}
}
实验结论:
配置 | 效果 |
---|---|
不配置@EnableDiscoveryClient,不配置nacos.discovery.enable | 具有服务自动注册功能,具有拉取服务信息功能 |
不配置@EnableDiscoveryClient,配置nacos.discovery.enable=false | 服务注册与拉取服务信息功能都不具备 |
配置@EnableDiscoveryClient(autoRegister=false),配置nacos.discovery.enable=true | 不具有服务注册功能,具有拉取服务信息功能 |
配置@EnableDiscoveryClient(autoRegister=false),配置nacos.discovery.enable=false | 服务注册与拉取服务信息功能都不具备 |
最后:
才疏学浅,难免有疏漏或者错误的地方,希望各位不吝指教