通过在Aplication 处添加该注解, 启用服务发现:
@SpringBootApplication
@EnableDiscoveryClient // 启用服务发现
public class MsGatewayApplication {
这个注解 @EnableDiscoveryClient 是在Spring-Cloud-Commons里定义的
查看该注解定义, 可以看到 @Import({EnableDiscoveryClientImportSelector.class}) ,这个注解会在启动时, 自动注入 EnableDiscoveryClientImportSelector
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({EnableDiscoveryClientImportSelector.class}) // 通过注解导入 EnableDiscoveryClientImportSelector
public @interface EnableDiscoveryClient {
boolean autoRegister() default true;
}
EnableDiscoveryClientImportSelector 的主要功能是导入需要的 AutoServiceRegistrationConfiguration (自动服务注册配置类) 或者 修改环境变量,这取决于 @EnableDiscoveryClient 里的 autoRegister 参数
根据 autoRegister(默认为true)判断:
如果为 true : importsList.add(“org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration”) 是在引用列表里添加 org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration , 这个类是在 spring-coud-commons 项目里定义的
如果为 false :
map.put(“spring.cloud.service-registry.auto-registration.enabled”, false) 在环境变量中将 自动注册 设为 false
@Order(2147483547)
public class EnableDiscoveryClientImportSelector extends SpringFactoryImportSelector<EnableDiscoveryClient> {
public EnableDiscoveryClientImportSelector() {
}
public String[] selectImports(AnnotationMetadata metadata) {
String[] imports = super.selectImports(metadata);
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(this.getAnnotationClass().getName(), true));
boolean autoRegister = attributes.getBoolean("autoRegister");
// 是否自动注册服务 EnableDiscoveryClient.autoRegister default true
if (autoRegister) {
// 引用列表
List<String> importsList = new ArrayList(Arrays.asList(imports));
// 调用 spring-cloud-commons 里的 AutoServiceRegistrationConfiguration (自动服务注册配置)
importsList.add("org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
imports = (String[])importsList.toArray(new String[0]);
} else {
Environment env = this.getEnvironment();
if (ConfigurableEnvironment.class.isInstance(env)) {
ConfigurableEnvironment configEnv = (ConfigurableEnvironment)env;
LinkedHashMap<String, Object> map = new LinkedHashMap();
// 配置 spring.cloud.service-registry.auto-registration.enabled 为false,不启用自动注册服务
map.put("spring.cloud.service-registry.auto-registration.enabled", false);
MapPropertySource propertySource = new MapPropertySource("springCloudDiscoveryClient", map);
// 添加到环境变量
configEnv.getPropertySources().addLast(propertySource);
}
}
return imports;
}
// 根据 配置项 spring.cloud.discovery.enabled 判断是否启用服务发现,该配置项默认为true
protected boolean isEnabled() {
// 从环境变量中获取 spring.cloud.discovery.enabled 的布尔值,并且默认返回TRUE
return (Boolean)this.getEnvironment().getProperty("spring.cloud.discovery.enabled", Boolean.class, Boolean.TRUE);
}
protected boolean hasDefaultFactory() {
return true;
}
}
@EnableConfigurationProperties(AutoServiceRegistrationProperties.class) :
该注解的意思是启用配置类 AutoServiceRegistrationProperties
@ConditionalOnProperty(value = “spring.cloud.service-registry.auto-registration.enabled”, matchIfMissing = true):
在 spring.cloud.service-registry.auto-registration.enabled 的配置项为 true 的时候该类才会启用, 属性 matchIfMissing = true 的意思是假如没有对该项进行配置, 则默认情况下相当于 true,也会启用该类
/**
* @author Spencer Gibb
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(AutoServiceRegistrationProperties.class) // 启用配置 AutoServiceRegistrationProperties
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) // spring.cloud.service-registry.auto-registration.enabled 的配置项为true的时候,才会启用, matchIfMissing = true 为该配置项如果未配置,也会启用该类
public class AutoServiceRegistrationConfiguration {
}
在 AutoServiceRegistrationConfiguration @Import(EnableConfigurationPropertiesRegistrar.class):
导入了 EnableConfigurationPropertiesRegistrar (一个关于启用属性配置的注册器),该注册器会将 @EnableConfigurationProperties 里的 Class>[] value() 进行bean注册 (即对 AutoServiceRegistrationProperties 进行bean注册)
/**
* Enable support for {@link ConfigurationProperties @ConfigurationProperties} annotated
* beans. {@code @ConfigurationProperties} beans can be registered in the standard way
* (for example using {@link Bean @Bean} methods) or, for convenience, can be specified
* directly on this annotation.
*
* @author Dave Syer
* @since 1.0.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EnableConfigurationPropertiesRegistrar.class)
public @interface EnableConfigurationProperties {
// 验证器 BEAN 名称
/**
* The bean name of the configuration properties validator.
* @since 2.2.0
*/
String VALIDATOR_BEAN_NAME = "configurationPropertiesValidator";
// 接收一个数组,数组类型为ClassType
/**
* Convenient way to quickly register
* {@link ConfigurationProperties @ConfigurationProperties} annotated beans with
* Spring. Standard Spring Beans will also be scanned regardless of this value.
* @return {@code @ConfigurationProperties} annotated beans to register
*/
Class<?>[] value() default {};
}
AutoServiceRegistrationProperties 是怎么被引入呢
这类实现了接口 ImportBeanDefinitionRegistrar , 重写了registerBeanDefinitions 方法,它在这里将之前的 AutoServiceRegistrationProperties 通过 ConfigurationPropertiesBeanRegistrar 注册到容器
/**
* {@link ImportBeanDefinitionRegistrar} for
* {@link EnableConfigurationProperties @EnableConfigurationProperties}.
*
* @author Phillip Webb
* @author Andy Wilkinson
*/
class EnableConfigurationPropertiesRegistrar implements ImportBeanDefinitionRegistrar {
private static final String METHOD_VALIDATION_EXCLUDE_FILTER_BEAN_NAME = Conventions
.getQualifiedAttributeName(EnableConfigurationPropertiesRegistrar.class, "methodValidationExcludeFilter");
// 注册
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
registerInfrastructureBeans(registry);
registerMethodValidationExcludeFilter(registry);
// new 一个ConfigurationPropertiesBean注册器
ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);
getTypes(metadata).forEach(beanRegistrar::register);
/* 类似:依次注册 getTypes 返回的Class集
getTypes(metadata).forEach( (item) -> {
beanRegistrar.register(item)
} )
*/
}
// 获取EnableConfigurationProperties集
private Set<Class<?>> getTypes(AnnotationMetadata metadata) {
return metadata.getAnnotations().stream(EnableConfigurationProperties.class)
// 合并
.flatMap((annotation) -> Arrays.stream(annotation.getClassArray(MergedAnnotation.VALUE)))
// 过滤空的class
.filter((type) -> void.class != type)
// 返回set
.collect(Collectors.toSet());
}
static void registerInfrastructureBeans(BeanDefinitionRegistry registry) {
ConfigurationPropertiesBindingPostProcessor.register(registry);
BoundConfigurationProperties.register(registry);
}
// 注册方法验证排除过滤器
static void registerMethodValidationExcludeFilter(BeanDefinitionRegistry registry) {
// 如果注册器不包含 METHOD_VALIDATION_EXCLUDE_FILTER_BEAN_NAME 的BeanDefinition
if (!registry.containsBeanDefinition(METHOD_VALIDATION_EXCLUDE_FILTER_BEAN_NAME)) {
BeanDefinition definition = BeanDefinitionBuilder
// 生成一个BeanDefinition, 过滤 @ConfigurationProperties 的注解
.genericBeanDefinition(MethodValidationExcludeFilter.class,
() -> MethodValidationExcludeFilter.byAnnotation(ConfigurationProperties.class))
// 设置BeanDefinition的角色
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE).getBeanDefinition();
// 注册过滤器
registry.registerBeanDefinition(METHOD_VALIDATION_EXCLUDE_FILTER_BEAN_NAME, definition);
}
}
}
该类是一个Bean注册器,在 void register 方法里:
void register(Class<?> type) {
MergedAnnotation<ConfigurationProperties> annotation = MergedAnnotations
.from(type, SearchStrategy.TYPE_HIERARCHY).get(ConfigurationProperties.class);
register(type, annotation);
}
// 注册
void register(Class<?> type, MergedAnnotation<ConfigurationProperties> annotation) {
String name = getName(type, annotation);
// 如果没有该BeanDefinition,则进行注册
if (!containsBeanDefinition(name)) {
registerBeanDefinition(name, type, annotation);
}
}
通过下面这行代码从 Class> type 里 拿到 MergedAnnotation< ConfigurationProperties > annotation
MergedAnnotation<ConfigurationProperties> annotation = MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY).get(ConfigurationProperties.class)
然后通过下面的断言:
Assert.state(annotation.isPresent(), () -> {
return "No " + ConfigurationProperties.class.getSimpleName() + " annotation found on '" + type.getName() + "'.";
});
来判断是否带有 ConfigurationProperties.class 类型的注解,接下来通过构造函数里传入的 BeanDefinitionRegistry registry ,把它注册到容器里:
private void registerBeanDefinition(String beanName, Class<?> type,
MergedAnnotation<ConfigurationProperties> annotation) {
Assert.state(annotation.isPresent(), () -> "No " + ConfigurationProperties.class.getSimpleName()
+ " annotation found on '" + type.getName() + "'.");
this.registry.registerBeanDefinition(beanName, createBeanDefinition(beanName, type));
}
它的属性 BeanDefinitionRegistry registry 是一个接口,具体传进来的实现类由容器进行管理, 这里只需要知道它实现了这组接口,调用它的 registerBeanDefinition() 方法进行bean注册就可以, ConfigurationPropertiesBeanRegistrar 的意义是它做了一个 过滤 和 去重 ,过滤出 ConfigurationProperties 类型的注解, 通过 containsBeanDefinition() 方法判断之前是否已经注册过相同的Bean,在注册时对不同的 BindMethod( JAVA_BEAN, VALUE_OBJECT) 和 Bean名称 进行了统一的处理。
它的构造函数这里做了一个强制转换, 把 BeanDefinitionRegistry 转换成 BeanFactory, 但是 BeanDefinitionRegistry 里并没有没有 BeanFactory 的约束,这应该是作者自己知道具体的实现类,然后做的转换。
ConfigurationPropertiesBeanRegistrar 的构造函数:
private final BeanDefinitionRegistry registry;
private final BeanDefinitionRegistry registry;
private final BeanFactory beanFactory;
ConfigurationPropertiesBeanRegistrar(BeanDefinitionRegistry registry) {
this.registry = registry;
this.beanFactory = (BeanFactory)this.registry;
}
统一获取Bean名称的方法:
private String getName(Class<?> type, MergedAnnotation<ConfigurationProperties> annotation) {
String prefix = annotation.isPresent() ? annotation.getString("prefix") : "";
return (StringUtils.hasText(prefix) ? prefix + "-" + type.getName() : type.getName());
}
对不同类型的 BindMethod 处理:
private BeanDefinition createBeanDefinition(String beanName, Class<?> type) {
BindMethod bindMethod = BindMethod.forType(type);
RootBeanDefinition definition = new RootBeanDefinition(type);
definition.setAttribute(BindMethod.class.getName(), bindMethod);
if (bindMethod == BindMethod.VALUE_OBJECT) {
definition.setInstanceSupplier(() -> {
return this.createValueObject(beanName, type);
});
}
return definition;
}
完整 ConfigurationPropertiesBeanRegistrar 的类代码:
final class ConfigurationPropertiesBeanRegistrar {
private final BeanDefinitionRegistry registry;
private final BeanFactory beanFactory;
ConfigurationPropertiesBeanRegistrar(BeanDefinitionRegistry registry) {
// 注入 bean注册器
this.registry = registry;
this.beanFactory = (BeanFactory) this.registry;
}
void register(Class<?> type) {
MergedAnnotation<ConfigurationProperties> annotation = MergedAnnotations
.from(type, SearchStrategy.TYPE_HIERARCHY).get(ConfigurationProperties.class);
register(type, annotation);
}
// 注册
void register(Class<?> type, MergedAnnotation<ConfigurationProperties> annotation) {
String name = getName(type, annotation);
// 如果没有该BeanDefinition,则进行注册
if (!containsBeanDefinition(name)) {
registerBeanDefinition(name, type, annotation);
}
}
// 获取名称:"prefix-typeName" , 或 "typeName"
private String getName(Class<?> type, MergedAnnotation<ConfigurationProperties> annotation) {
String prefix = annotation.isPresent() ? annotation.getString("prefix") : "";
return (StringUtils.hasText(prefix) ? prefix + "-" + type.getName() : type.getName());
}
private boolean containsBeanDefinition(String name) {
return containsBeanDefinition(this.beanFactory, name);
}
// 判断是否包含BeanDefinition
private boolean containsBeanDefinition(BeanFactory beanFactory, String name) {
if (beanFactory instanceof ListableBeanFactory
&& ((ListableBeanFactory) beanFactory).containsBeanDefinition(name)) {
return true;
}
if (beanFactory instanceof HierarchicalBeanFactory) {
return containsBeanDefinition(((HierarchicalBeanFactory) beanFactory).getParentBeanFactory(), name);
}
return false;
}
// 注册BeanDefinition
private void registerBeanDefinition(String beanName, Class<?> type,
MergedAnnotation<ConfigurationProperties> annotation) {
Assert.state(annotation.isPresent(), () -> "No " + ConfigurationProperties.class.getSimpleName()
+ " annotation found on '" + type.getName() + "'.");
this.registry.registerBeanDefinition(beanName, createBeanDefinition(beanName, type));
}
// 根据bean名称,类型,创建一个 BeanDefinition
private BeanDefinition createBeanDefinition(String beanName, Class<?> type) {
if (BindMethod.forType(type) == BindMethod.VALUE_OBJECT) {
// 返回一个 ConfigurationProperties 值对象的BeanDefinition
return new ConfigurationPropertiesValueObjectBeanDefinition(this.beanFactory, beanName, type);
}
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(type);
return definition;
}
}
这个类主要是加载一些配置,映射配置文件配置:
ConfigurationProperties("spring.cloud.service-registry.auto-registration")
public class AutoServiceRegistrationProperties {
private boolean enabled = true;
private boolean registerManagement = true;
private boolean failFast = false;
public AutoServiceRegistrationProperties() {
}
public boolean isEnabled() {
return this.enabled;
}
...
..
在 SpringBootApplication 添加了 @EnabledDiscoveryClient 注解之后,什么时候启动服务呢
在 spring-cloud-starter-alibaba-nacos-discovery 的项目里的 spring.factories 中,定义了该启动配置NacosDiscoveryClientConfigServiceBootstrapConfiguration ,因此会在启动的时候加载该类。
查看 NacosDiscoveryClientConfigServiceBootstrapConfiguration 的定义,它是一个空的 class,主要是通过 @ImportAutoConfiguration 这个注解,在启动时导入了以下几个类 :
它们的后缀都是 Configuration,它还有一些其他的注解:
@ConditionalOnClass({ConfigServicePropertySourceLocator.class})
上面这个注解是判断 ConfigServicePropertySourceLocator 这个class是否在classpath中, 在的话才会构建这个Bean
@ConditionalOnProperty(
value = {"spring.cloud.config.discovery.enabled"},
matchIfMissing = false
)
上面这个注解判断 spring.cloud.config.discovery.enabled 的配置是否为 true ,是的话才会构建这个Bean
它们都带有 ConditionalOn 的 前缀,都是起到 构建Bean条件判断的作用。
完整的类代码:
@ConditionalOnClass({ConfigServicePropertySourceLocator.class})
@ConditionalOnProperty(
value = {"spring.cloud.config.discovery.enabled"},
matchIfMissing = false
)
@Configuration(
proxyBeanMethods = false
)
@ImportAutoConfiguration({NacosDiscoveryAutoConfiguration.class, NacosServiceAutoConfiguration.class, NacosDiscoveryClientConfiguration.class, NacosReactiveDiscoveryClientConfiguration.class})
public class NacosDiscoveryClientConfigServiceBootstrapConfiguration {
public NacosDiscoveryClientConfigServiceBootstrapConfiguration() {
}
}
@ConditionalOnDiscoveryEnabled 和 @ConditionalOnNacosDiscoveryEnabled 同样是构建Bean条件判断的注解 。
在类 NacosDiscoveryAutoConfiguration 里定义了 NacosDiscoveryProperties nacosProperties() 和 cosServiceDiscovery nacosServiceDiscovery 两个方法, 通过@Bean 注解,定义 NacosDiscoveryProperties 和 NacosServiceDiscovery 这两个Bean,在启动时,Spring容器会将这两个Bean注册到容器中。
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnDiscoveryEnabled
@ConditionalOnNacosDiscoveryEnabled
public class NacosDiscoveryAutoConfiguration {
public NacosDiscoveryAutoConfiguration() {
}
@Bean
@ConditionalOnMissingBean
public NacosDiscoveryProperties nacosProperties() {
return new NacosDiscoveryProperties();
}
@Bean
@ConditionalOnMissingBean
public NacosServiceDiscovery nacosServiceDiscovery(NacosDiscoveryProperties discoveryProperties, NacosServiceManager nacosServiceManager) {
return new NacosServiceDiscovery(discoveryProperties, nacosServiceManager);
}
}
@ConfigurationProperties(“spring.cloud.nacos.discovery”) 会将这个前缀的配置映射到配置类的属性中。
它有一个带有 @PostConstruct 注解的 void init() 方法。
@PostConstruct 注解的方法会执行在构造函数之后,init() 函数之前
这里的方法同时命名为 init(),并且带有 @PostConstruct 注解, 因此在该类实例化后,会执行该方法。
它的 init() 方法里主要是初始化相关的配置,比如: serverAddr(服务地址),namespace(命名控件),username(用户名),password(密码)等。
通过 if (this.nacosServiceManager.isNacosDiscoveryInfoChanged(this)) 判断这一行代码判断配置是否修改了。如果修改了,则通过 this.applicationEventPublisher.publishEvent(new NacosDiscoveryInfoChangedEvent(this)) 发布 一个NacosDiscoveryInfoChangedEvent 类型的事件。
可以在 SringApplication.run() 执行之前, 通过
System.setProperty(“spring.cloud.nacos.config.server-addr”, “127.0.0.1:port”)
System.setProperty(“spring.cloud.nacos.discovery.server-addr”, “127.0.0.1:port”)
修改配置,它会在 this.overrideFromEnv(this.environment) 这里读取并覆盖。
// 映射配置
@ConfigurationProperties("spring.cloud.nacos.discovery")
public class NacosDiscoveryProperties {
private static final Logger log = LoggerFactory.getLogger(NacosDiscoveryProperties.class);
public static final String PREFIX = "spring.cloud.nacos.discovery";
private static final Pattern PATTERN = Pattern.compile("-(\\w)");
private String serverAddr;
private String username;
private String password;
private String endpoint;
private String namespace;
private long watchDelay = 30000L;
// 在构造函数之后,执行该方法
@PostConstruct
public void init() throws Exception {
this.metadata.put("preserved.register.source", "SPRING_CLOUD");
if (this.secure) {
this.metadata.put("secure", "true");
}
// 获取配置的 nacos 服务地址
this.serverAddr = Objects.toString(this.serverAddr, "");
if (this.serverAddr.endsWith("/")) {
this.serverAddr = this.serverAddr.substring(0, this.serverAddr.length() - 1);
}
this.endpoint = Objects.toString(this.endpoint, "");
this.namespace = Objects.toString(this.namespace, "");
this.logName = Objects.toString(this.logName, "");
if (StringUtils.isEmpty(this.ip)) {
if (StringUtils.isEmpty(this.networkInterface)) {
this.ip = this.inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
} else {
NetworkInterface netInterface = NetworkInterface.getByName(this.networkInterface);
if (null == netInterface) {
throw new IllegalArgumentException("no such interface " + this.networkInterface);
}
Enumeration inetAddress = netInterface.getInetAddresses();
while(inetAddress.hasMoreElements()) {
InetAddress currentAddress = (InetAddress)inetAddress.nextElement();
if (currentAddress instanceof Inet4Address && !currentAddress.isLoopbackAddress()) {
this.ip = currentAddress.getHostAddress();
break;
}
}
if (StringUtils.isEmpty(this.ip)) {
throw new RuntimeException("cannot find available ip from network interface " + this.networkInterface);
}
}
}
// 重写配置
this.overrideFromEnv(this.environment);
// 如果配置修改了,发布一个 NacosDiscoveryInfoChangedEvent 事件
if (this.nacosServiceManager.isNacosDiscoveryInfoChanged(this)) {
this.applicationEventPublisher.publishEvent(new NacosDiscoveryInfoChangedEvent(this));
}
}
在 NacosDiscoveryProperties 初始化之后,执行 @PostConstruct 注解的 init() 方法, 发布了一个 NacosDiscoveryInfoChangedEvent 类型的事件。
这个事件是在哪里被监听和处理的呢?
通过全局搜索,找到了 NacosAutoServiceRegistration 这个类,它有一个 void onNacosDiscoveryInfoChangedEvent 的方法,这个方法用一个
@EventListener 的注解修饰, 并且接收了一个 NacosDiscoveryInfoChangedEvent 类型的参数,这个刚好和之前发布的事件的类型是一样的:
/**
* @author xiaojing
* @author Mercy
*/
public class NacosAutoServiceRegistration
extends AbstractAutoServiceRegistration<Registration> {
...
...
// 事件监听:NacosDiscoveryInfoChangedEvent
@EventListener
public void onNacosDiscoveryInfoChangedEvent(NacosDiscoveryInfoChangedEvent event) {
// 重启
restart();
}
private void restart() {
this.stop();
this.start();
}
...
它起到监听 NacosDiscoveryInfoChangedEvent 事件并且对事件进行处理的这样一个作用。通过 @EventListener 注解, SpringBoot初始化时会注册一个监听和处理该事件的 Listener, 通过 applicationEventPublisher.publishEvent() 发布一个事件的时候, 会根据事件的类型,在已经注册的 Listener 里找到对应的处理者,可能一个事件同时会有多个Listener,它会把发布的事件广播给所有的 Listener, 每个 Listener 对事件进行各自的处理。
onNacosDiscoveryInfoChangedEvent() 这里执行的是 restart() 重启,其实是执行了继承的 stop() 和 start() 方法
该类继承自在SpringCloud中定义的泛型抽象类
AbstractAutoServiceRegistration < T extends Registration >
实现了 AutoServiceRegistration, ApplicationContextAware , ApplicationListener < WebServerInitializedEvent > 三个接口
在 ApplicationContextAware 接口中定义了 void setApplicationContext(ApplicationContext applicationContext)
在 ApplicationListener < WebServerInitializedEvent > 定义了 void onApplicationEvent(WebServerInitializedEvent event)
NacosAutoServiceRegistration 的类关系简图
在 ApplicationContextAware 接口中定义了 void setApplicationContext(ApplicationContext applicationContext) ,这里用了接口的方式,调用者知道你实现了这个接口规范 。通过这个方法可以在某个时候(比如初始化时),把 ApplicationContext 传过来
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
this.environment = this.context.getEnvironment();
}
在 void onApplicationEvent 方法中,当 WebServerInitializedEvent 事件传进来后, 执行 bind() 方法。
在bind() 方法中, 主要做一些逻辑判断,判断事件里的应用程序上下文,和命名空间。
this.port.compareAndSet(0, event.getWebServer().getPort());
这里的 compareAndSet 的用法是,当 this.port 的值为0的时候,将 this.port 的值设置为 event.getWebServer().getPort() , 即事件里的端口。
然后执行 this.start()
@Override
@SuppressWarnings("deprecation")
public void onApplicationEvent(WebServerInitializedEvent event) {
bind(event);
}
@Deprecated
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();
}
在 start() 方法里主要是做一些状态判断:isEnabled() 是否启用, running 是否运行中等。
然后在执行 this.register() 之前, 发布一个 InstancePreRegisteredEvent 类型的事件, 并且在之后发布一个 InstanceRegisteredEvent 类型的事件。
这样我们只要知道一个类继承自 AbstractAutoServiceRegistration , 调用它的 start() 方法,并且成功注册的话,它就会在注册前后发布这两个事件,需要的情况下可以定义两个事件监听器,去捕获和处理这两个事件。
public void start() {
if (!this.isEnabled()) {
if (logger.isDebugEnabled()) {
logger.debug("Discovery Lifecycle disabled. Not starting");
}
} else {
if (!this.running.get()) {
this.context.publishEvent(new InstancePreRegisteredEvent(this, this.getRegistration()));
this.register();
if (this.shouldRegisterManagement()) {
this.registerManagement();
}
this.context.publishEvent(new InstanceRegisteredEvent(this, this.getConfiguration()));
this.running.compareAndSet(false, true);
}
}
}
在 register() 方法里, 调用的 this.serviceRegistry 是在构造函数里传入的一个 ServiceRegistry < R extends Registration > 类型的接口。
getRegistration() 这个方法在抽象类里并没有具体实现,只是作了定义,该方法返回泛型 R( 泛型约束:继承自 Registration ):
protected abstract R getRegistration();
protected void register() {
this.serviceRegistry.register(this.getRegistration());
}
private final ServiceRegistry<R> serviceRegistry;
@Deprecated
protected AbstractAutoServiceRegistration(ServiceRegistry<R> serviceRegistry) {
this.serviceRegistry = serviceRegistry;
}
protected AbstractAutoServiceRegistration(ServiceRegistry<R> serviceRegistry, AutoServiceRegistrationProperties properties) {
this.serviceRegistry = serviceRegistry;
this.properties = properties;
}
再看 stop() 方法这部分, 同样是对状态作判断,并且调用的是 serviceRegistry 的 deregister() 方法 和 close() 方法。
serviceRegistry 是 ServiceRegistry< R extends Registration> 类型的接口。任何具体的该接口的实现类,都可以通过在构造函数中以参数的方式注入, 被用来做服务状态具体的操作。
public void stop() {
if (this.getRunning().compareAndSet(true, false) && this.isEnabled()) {
this.deregister();
if (this.shouldRegisterManagement()) {
this.deregisterManagement();
}
this.serviceRegistry.close();
}
}
ServiceRegistry< R extends Registration> 的接口定义,该接口定义了一个服务注册类应该实现的几个方法:
public interface ServiceRegistry<R extends Registration> {
/**
* Registers the registration. A registration typically has information about an
* instance, such as its hostname and port.
* @param registration registration meta data
*/
void register(R registration);
/**
* Deregisters the registration.
* @param registration registration meta data
*/
void deregister(R registration);
/**
* Closes the ServiceRegistry. This is a lifecycle method.
*/
void close();
/**
* Sets the status of the registration. The status values are determined by the
* individual implementations.
* @param registration The registration to update.
* @param status The status to set.
* @see org.springframework.cloud.client.serviceregistry.endpoint.ServiceRegistryEndpoint
*/
void setStatus(R registration, String status);
/**
* Gets the status of a particular registration.
* @param registration The registration to query.
* @param The type of the status.
* @return The status of the registration.
* @see org.springframework.cloud.client.serviceregistry.endpoint.ServiceRegistryEndpoint
*/
<T> T getStatus(R registration);
}
在看看泛型R的约束类 Registration , 查看定义后发现它是空的,他只是对 ServiceInstance 的一层封装, 为什么这么多此一举呢,我想应该是为了在抽象概念上达到更清晰的一个目的。
ServiceInstance 同样也是在 SpringCloud 中定义的一组接口,它定义的方法:
方法 | 描述 |
---|---|
String getHost() | 获取主机名称 |
int getPort() | 获取端口 |
boolean isSecure() | 是否安全 |
URI getUri() | 获取服务的Uri地址 |
Map |
获取服务实例的元数据 |
String getInstanceId() | 获取唯一的实例Id |
String getServiceId() | 获取服务Id |
String getScheme() | 获取方案信息 |
按照SpringCloud文档里的说明,每个注册的服务实例都会有唯一的 InstanceId, 而多个实例可能有同一个 ServiceId (如 “service-order” )
public interface Registration extends ServiceInstance {
}
public interface ServiceInstance {
default String getInstanceId() {
return null;
}
String getServiceId();
String getHost();
int getPort();
boolean isSecure();
URI getUri();
Map<String, String> getMetadata();
default String getScheme() {
return null;
}
}
再回到 NacosAutoServiceRegistration , 它有个 NacosRegistration registration 的属性, 构造函数的参数个数也增加了一个 NacosRegistration registration,这个类实现了SpringCloud的 Registration 接口。
它同时 实现了 Registration, ServiceInstance , 两个接口, 不过既然 Registration 是空的,且 Registration 继承 ServiceInstance ,那这两者方法应该没有太大区别,有的只是概念上的差异,我们依然可以理解成它是一个 Registration。
public class NacosAutoServiceRegistration extends AbstractAutoServiceRegistration<Registration> {
private NacosRegistration registration;
public NacosAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry, AutoServiceRegistrationProperties autoServiceRegistrationProperties, NacosRegistration registration) {
super(serviceRegistry, autoServiceRegistrationProperties);
this.registration = registration;
}
可以看到 NacosRegistration 的构造函数有3个参数, 关于nacos的操作主要是在 NacosDiscoveryProperties 里进行的
public NacosRegistration(List<NacosRegistrationCustomizer> registrationCustomizers, NacosDiscoveryProperties nacosDiscoveryProperties, ApplicationContext context) {
this.registrationCustomizers = registrationCustomizers;
this.nacosDiscoveryProperties = nacosDiscoveryProperties;
this.context = context;
}
那这个 NacosAutoServiceRegistration 是在什么时候被实例化的呢?现在又回到之前看过的 spring.factories, 在这里了找到一个 com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration 的配置类 , 同时@Enabled,该类会在启动的时候自动加载:
找到 NacosServiceRegistryAutoConfiguration 这个类的文件,查看它的定义, 它有3个用@Bean注解的方法 :
在 @AutoConfigureAfter 注解的作用下,这个类将会在 这两个配置加载完之后再加载:
由@Bean注解的方法 NacosAutoServiceRegistration nacosAutoServiceRegistration() 方法,就是要找的 NacosAutoServiceRegistration Bean被注册的地方 , 它会在配置类加载的时候, 被注册到容器中。
nacosAutoServiceRegistration 依赖的 NacosServiceRegistry 和 NacosRegistration 在这个配置类里都有定义,它们也是通过@Bean修饰的方法,同样会被注册到容器中,通过注入的方式注入到参数里。
而另一个参数类型 AutoServiceRegistrationProperties 的命名空间是在 SpringCloud Commons 项目里,因此要到那里去找这个Bean被注册的地方。
/**
* @author xiaojing
* @author Mercy
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled
@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(
NacosServiceManager nacosServiceManager,
NacosDiscoveryProperties nacosDiscoveryProperties) {
return new NacosServiceRegistry(nacosServiceManager, 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);
}
}
可以看到是在 SpringCloud Common里被加载的,通过 AutoServiceRegistrationConfiguration 的 @EnableConfigurationProperties(AutoServiceRegistrationProperties.class) 注解:
/**
* @author Spencer Gibb
*/
@Configuration(proxyBeanMethods = false)
// 通过注解 @EnableConfigurationProperties 启用指定的 AutoServiceRegistrationProperties.class 配置
@EnableConfigurationProperties(AutoServiceRegistrationProperties.class)
// 根据 spring.cloud.service-registry.auto-registration.enabled 判断是否启用该类, matchIfMissing = true 默认为true
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public class AutoServiceRegistrationConfiguration {
}
而 AutoServiceRegistrationConfiguration 又是通过 AutoServiceRegistrationAutoConfiguration 类里的
@Import(AutoServiceRegistrationConfiguration.class) 被导入,也就是说 AutoServiceRegistrationAutoConfiguration 加载的时候,通过该注解会同时加载 AutoServiceRegistrationConfiguration 这个类, AutoServiceRegistrationAutoConfiguration 是什么时候被加载的呢?
/**
* @author Spencer Gibb
*/
@Configuration(proxyBeanMethods = false)
@Import(AutoServiceRegistrationConfiguration.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public class AutoServiceRegistrationAutoConfiguration implements InitializingBean {
@Autowired(required = false)
private AutoServiceRegistration autoServiceRegistration;
@Autowired
private AutoServiceRegistrationProperties properties;
...
AutoServiceRegistrationAutoConfiguration 是被写在 SpringCloud Commons 项目里的 spring.factories 的自动配置项里 , 同时 @EnableDiscoveryClient 注解里也把这个类加入到 ImportList 里面 。因此它会在启动时被自动加载,这样 AutoServiceRegistrationConfiguration 也会被注册到容器中。
以上是关于 Spring-Cloud-Starter-Alibaba-Nacos-Discovery 在应用启动时,自动注册服务的一些相关的源码分析。在应用程序开始运行后, 加载Bean NacosDiscoveryProperties 时,在它构造函数执行完的时候,会自动调用 init() 方法,完成服务注册的操作。