1 、cloud nacos discovery 实现原理:
1、1注入自动配置类 :
@EnableDiscoveryClient 扫描 nacos包中的spring.factories,加载NacosDiscoveryClientAutoConfiguration。
不贴代码了,springboot enable的标签都这么玩。
2、2 初始化配置和NacosAutoServiceRegistration对象。
@Configuration
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled
@ConditionalOnClass(name = "org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent")
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
@AutoConfigureBefore({ AutoServiceRegistrationAutoConfiguration.class,
NacosDiscoveryClientAutoConfiguration.class })
public class NacosDiscoveryAutoConfiguration {
//初始化核心类。
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosAutoServiceRegistration nacosAutoServiceRegistration(
NacosServiceRegistry registry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties,
NacosRegistration registration) {
return new NacosAutoServiceRegistration(registry,
autoServiceRegistrationProperties, registration);
}
NacosAutoServiceRegistration 继承AbstractAutoServiceRegistration:该类为spring cloud comoon中的基类,不管enruka 还是其他注册中心,都会继承该抽象类,AbstractAutoServiceRegistration有个bind 方法,监听了WebServerInitializedEvent事件,当webserver初始化完成后,实现注册中心注册的逻辑。
@EventListener(WebServerInitializedEvent.class)
public void bind(WebServerInitializedEvent event) {
ApplicationContext context = event.getApplicationContext();
if (context instanceof ConfigurableWebServerApplicationContext) {
if ("management".equals(
((ConfigurableWebServerApplicationContext) context).getServerNamespace())) {
return;
}
}
this.port.compareAndSet(0, event.getWebServer().getPort());
this.start();
}
bug 原因
现象:bind方法断点无法进入。事件没有监听到
分析:@EventListener 标签没有生效。
追踪:@EventListener 解析逻辑。通过注释@EventListener 标签通过EventListenerMethodProcessor来解析初始化的。
通过debug 发现spring 5.1 后新增了条件判断。导致NacosAutoServiceRegistration 无法作为事件注入到容器中。
/**
* Determine whether the given class is an {@code org.springframework}
* bean class that is not annotated as a user or test {@link Component}...
* which indicates that there is no {@link EventListener} to be found there.
* @since 5.1
*/
private static boolean isSpringContainerClass(Class<?> clazz) {
return (clazz.getName().startsWith("org.springframework.") &&
!AnnotatedElementUtils.isAnnotated(ClassUtils.getUserClass(clazz), Component.class));
}