https://blog.csdn.net/yaomingyang/article/details/110879101
https://www.cnblogs.com/crazymakercircle/p/14231815.html
https://www.cnblogs.com/llysc/p/14982849.html
https://blog.csdn.net/qq_40125268/article/details/131478039
### ----------------------------------------------------------------------------------------------nacos服务注册与发现
nacos实现动态发现和注册的原理,nacos 1.x之间的数据同步靠http协议同步,2.x版本后改成distro协议来同步数据。
注册与发现是通过订阅机制来实现的。客户端通过订阅注册中心,注册中心则会返回当前注册在注册中心的所有的实例,
返回的数据就包含了其他客户端的ip和端口,则可以通过ip和端口对其他客户端服务进行访问和调用。
### nacos服务注册
理解@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...)
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", 属性为true时,此配置类会被加载
matchIfMissing = true)
public class AutoServiceRegistrationConfiguration {
配置类有两个作用,
第一将AutoServiceRegistrationProperties属性配置类注入IOC容器,
其二只有在spring.cloud.service-registry.auto-registration.enabled为true时才将配置类注入IOC容器,
默认就为true;
}
当**.registration.enabled=spring-cloud-commons.jar包内的spring-configuration-metadata.json定义了此属性默认为true
即: 不配置@EnableDiscoveryClient或者配置@EnableDiscoveryClient设置autoRegister为true时AutoServiceRegistrationConfiguration会被加载,
当@EnableDiscoveryClient设置autoRegister属性为false时,此配置类AutoServiceRegistrationConfiguration不会被加载
既然@EnableDiscoveryClient注解不配置AutoServiceRegistrationConfiguration一样可以注入到IOC容器,那么说明肯定是有其他的地方有注入,
看下spring.factories配置文件中的自动化配置有一个 AutoServiceRegistrationAutoConfiguration 自动化配置类,再看下其源码:
@Configuration(proxyBeanMethods = false)
@Import(AutoServiceRegistrationConfiguration.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public class AutoServiceRegistrationAutoConfiguration implements InitializingBean {
}
看到上面有一个@Import将AutoServiceRegistrationConfiguration配置类注入IOC容器,
这里就说明了如果EnableDiscoveryClientImportSelector类没有将配置类注入IOC容器,那么此处就会将其注入。
由于spring boot默认启用了@EnableAutoConfiguration,所以nacos-discovery包的spring.factories文件中会加载;
找到nacos的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,\ nacos服务注册自动配置类。主要注册NacosAutoServiceRegistration类的bean实例
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
那服务注册功能呢? NacosServiceRegistryAutoConfiguration
服务自动注册逻辑:
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled 确保spring.cloud.nacos.discovery.enabled为true
(开启nacos的服务注册与发现功能)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
matchIfMissing = true) 默认为true,使用@EnableDiscoveryClient注解配置autoRegister为false时,
此属性值为false即: 此类不被加载,即: 服务不具备自动注册功能
@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);
}
}
-> new NacosAutoServiceRegistration() 该类的构造方法,其实例化通过其父类AbstractAutoServiceRegistration的构造方法实现
-> new AbstractAutoServiceRegistration() 该类实现了ApplicationListener接口,这个接口可以监听容器中发布WebServerInitializedEvent事件,
这个事件会在应用上下文刷新后和WebServer已经准备好之后被发布,
然后触发onApplicationEvent,执行bind()方法。
...
-> AbstractAutoServiceRegistration.onApplicationEvent()
register()
-> AbstractAutoServiceRegistration.register()
this.serviceRegistry.register(getRegistration())
-> NacosServiceRegistry.register()
namingService.registerInstance(serviceId, group, instance);
-> NacosNamingService.registerInstance()
clientProxy.registerService(serviceName, groupName, instance);
-> NamingClientProxy.registerService() 有三种实现:NamingGrpcClientProxy NamingClientProxyDelegate NamingHttpClientProxy
注册服务的逻辑中包含如下几个步骤:
1.redoService是去添加redo日志,实际上通过registeredInstances 的map结构来存储redo日志
2.doRegisterService是真正发起注册的逻辑,其中requestToServer 方法就是发送gRpc协议请求,
去完成注册,然后instanceRegistered方法主要是标记当前服务已经完成注册逻辑。
-> NamingGrpcClientProxy.registerService()
redoService.cacheInstanceForRedo(serviceName, groupName, instance);
doRegisterService(serviceName, groupName, instance);
-> NamingGrpcClientProxy.doRegisterService()
public void doRegisterService(String serviceName, String groupName, Instance instance) throws NacosException {
InstanceRequest request = new InstanceRequest(namespaceId, serviceName, groupName,
NamingRemoteConstants.REGISTER_INSTANCE, instance);
requestToServer(request, Response.class); 实例注册
redoService.instanceRegistered(serviceName, groupName); 实例注册成功后,会把redo日志中实例标记成注册成功
}
注入NacosDiscoveryAutoConfiguration
新建NacosDiscoveryProperties服务发现属性和命名服务
新建NacosServiceDiscovery通过NacosDiscoveryProperties的NamingService获取信息,将Instance封装成ServiceInstance。
注入NacosDiscoveryClientConfiguration获取服务信息用
新建NacosDiscoveryClient
新建GatewayLocatorHeartBeatPublisher
新建NacosWatch
NacosDiscoveryEndpointAutoConfiguration监控相关
新建NacosDiscoveryEndpoint
新建NacosDiscoveryHealthIndicator健康检查
### 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,服务就具有拉取注册中心信息的功能