前言
上兩篇文章我分析了在SpringBoot啟動時候會註冊該服務到Nacos,那我們考慮過服務發現時候為什麼會從Nacos獲取服務實例嗎?服務發現的底層是Ribbon,默認不是從Nacos獲取服務實例列表的,可以從RibbonClientConfiguration的自動配置類得到答案,代碼截圖如下:
![](https://news.xinpengboligang.com/upload/keji/1baeca2281fa72d108b32159829a1e12.jpeg)
RibbonClientConfiguration自動配置類部分截圖
可以看到默認的服務是ConfigurationBasedServerList,那麼為什麼引入Nacos會從Nacos服務器獲取到服務列表嗎?下面我就揭開它的神秘面紗。
源碼分析
上文說過,引入Nacos服務發現與註冊的jar包以後,會在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
org.springframework.context.ApplicationListener=\
com.alibaba.cloud.nacos.discovery.logging.NacosLoggingListener
這裡面引入了一個自動配置類RibbonNacosAutoConfiguration,可以從名字看出來時Nacos與Ribbon的整合配置類,該類的定義截圖如下:
![](https://news.xinpengboligang.com/upload/keji/ed420766814dbe861650b7994a9728c6.jpeg)
RibbonNacosAutoConfiguration自動配置類
其中引入了一個@RibbonClients(defaultConfiguration = NacosRibbonClientConfiguration.class)註解,這個註解裡面內容如下:
package org.springframework.cloud.netflix.ribbon;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration(proxyBeanMethods = false)
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
@Documented
@Import(RibbonClientConfigurationRegistrar.class)
public @interface RibbonClients {
RibbonClient[] value() default {};
Class<?>[] defaultConfiguration() default {};
}
可以看出導入了一個RibbonClientConfigurationRegistrar類,該類實現了ImportBeanDefinitionRegistrar接口,由SpringBoot原理會調用registerBeanDefinitions方法,該方法的定義如下:
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
Map<String, Object> attrs = metadata
.getAnnotationAttributes(RibbonClients.class.getName(), true);
if (attrs != null && attrs.containsKey("value")) {
AnnotationAttributes[] clients = (AnnotationAttributes[]) attrs.get("value");
for (AnnotationAttributes client : clients) {
registerClientConfiguration(registry, getClientName(client),
client.get("configuration"));
}
}
if (attrs != null && attrs.containsKey("defaultConfiguration")) {
String name;
if (metadata.hasEnclosingClass()) {
name = "default." metadata.getEnclosingClassName();
}
else {
name = "default." metadata.getClassName();
}
registerClientConfiguration(registry, name,
attrs.get("defaultConfiguration"));
}
Map<String, Object> client = metadata
.getAnnotationAttributes(RibbonClient.class.getName(), true);
String name = getClientName(client);
if (name != null) {
registerClientConfiguration(registry, name, client.get("configuration"));
}
在@RibbonClient註解上配置了一個defaultConfiguration的屬性是NacosRibbonClientConfiguration,那麼會調用到registerClientConfiguration方法,該方法如下:
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
Object configuration) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(RibbonClientSpecification.class);
builder.addConstructorArgValue(name);
builder.addConstructorArgValue(configuration);
registry.registerBeanDefinition(name ".RibbonClientSpecification",
builder.getBeanDefinition());
}
往容器中自動註入了一個Bean類型是RibbonClientSpecification, 名稱是default.com.alibaba.cloud.nacos.ribbon.RibbonNacosAutoConfiguration.RibbonClientSpecification的Bean,構造了RibbonClientSpecification的構造函數的兩個參數,分別為name,configuration,由Ribbon的原理可知會加載RibbonClientSpecification類的configuration屬性,會把configuration對應類裡面的對象全部加載到容器中,那麼我們就關註這個configuration的類型是NacosRibbonClientConfiguration,這裡面都有什麼內容:
package com.alibaba.cloud.nacos.ribbon;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ServerList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.netflix.ribbon.PropertiesFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
@ConditionalOnRibbonNacos
public class NacosRibbonClientConfiguration {
@Autowired
private PropertiesFactory propertiesFactory;
@Bean
@ConditionalOnMissingBean
public ServerList<?> ribbonServerList(IClientConfig config,
NacosDiscoveryProperties nacosDiscoveryProperties) {
if (this.propertiesFactory.isSet(ServerList.class, config.getClientName())) {
ServerList serverList = this.propertiesFactory.get(ServerList.class, config,
config.getClientName());
return serverList;
}
NacosServerList serverList = new NacosServerList(nacosDiscoveryProperties);
serverList.initWithNiwsConfig(config);
return serverList;
}
@Bean
@ConditionalOnMissingBean
public NacosServerIntrospector nacosServerIntrospector() {
return new NacosServerIntrospector();
}
}
可以看出新創建出一個NacosServerList對象,裡面包含了NacosServer對象,NacosServer對象會連接服務器獲取到所有已經註冊的對象,這樣就能解釋了為什麼引入Nacos以後會從Nacos服務器獲取已註冊的實例。
好了,至此SpringBoot整合Nacos服務註冊原理和配置中心的原理已經分析完了,如果喜歡我的文章請點贊關註,我會持續更新源碼解析的文章,請大傢持續關註哦。