Nacos-spring-context.java

感觉这个后台要比之前的Nacos复杂多了,涉及到很多基础的概念,慢慢看,这个后面慢慢更新解析过程

看到他的目录结构一个是基于注解,一个是XML的解析,之前我们的值基于注解的,我们就看下这个注解的实现过程;

借助ImportBeanDefinitionRegistrar接口实现bean的动态注入

https://www.jianshu.com/p/2b993ced6a4c

NacosBeanDefinitionRegistrar.java
public class NacosBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware, BeanFactoryAware {

    private Environment environment;

    private BeanFactory beanFactory;

    @Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinition annotationProcessor = BeanDefinitionBuilder.genericBeanDefinition(
PropertySourcesPlaceholderConfigurer.class).getBeanDefinition();
registry.registerBeanDefinition(PropertySourcesPlaceholderConfigurer.class.getName(), annotationProcessor); AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableNacos.class.getName())); // Register Global Nacos Properties Bean
registerGlobalNacosProperties(attributes, registry, environment, GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
// Register Nacos Annotation Beans
registerNacosAnnotationBeans(registry);
// Invoke NacosPropertySourcePostProcessor immediately
// in order to enhance the precedence of @NacosPropertySource process
invokeNacosPropertySourcePostProcessor(beanFactory);
} @Override
public void setEnvironment(Environment environment) {
this.environment = environment;
} public void registerNacosAnnotationBeans(BeanDefinitionRegistry registry) {
registerNacosCommonBeans(registry);
registerNacosConfigBeans(registry, environment);
registerNacosDiscoveryBeans(registry);
} @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
NacosConfigBeanDefinitionRegistrar.java
下面这个操作就是将含有NacosPropertySource注解的类,注册到beanfactory
public class NacosConfigBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware,
BeanFactoryAware { private Environment environment; private BeanFactory beanFactory; @Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AnnotationAttributes attributes = fromMap(metadata.getAnnotationAttributes(EnableNacosConfig.class.getName()));
// Register Global Nacos Properties Bean
registerGlobalNacosProperties(attributes, registry, environment, CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
// Register Nacos Common Beans
registerNacosCommonBeans(registry);
// Register Nacos Config Beans
registerNacosConfigBeans(registry, environment);
// Invoke NacosPropertySourcePostProcessor immediately
// in order to enhance the precedence of @NacosPropertySource process
invokeNacosPropertySourcePostProcessor(beanFactory);
} @Override
public void setEnvironment(Environment environment) {
this.environment = environment;
} @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}

invokeNacosPropertySourcePostProcessor(beanFactory);

NacosBeanUtils.java
 /**
* Invokes {@link NacosPropertySourcePostProcessor}
*
* @param beanFactory {@link BeanFactory}
*/
public static void invokeNacosPropertySourcePostProcessor(BeanFactory beanFactory) {
NacosPropertySourcePostProcessor postProcessor =
beanFactory.getBean(NacosPropertySourcePostProcessor.BEAN_NAME, NacosPropertySourcePostProcessor.class);
postProcessor.postProcessBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}
NacosPropertySourcePostProcessor.java
 @Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] abstractNacosPropertySourceBuilderBeanNames = BeanUtils.getBeanNames(beanFactory,
AbstractNacosPropertySourceBuilder.class); this.nacosPropertySourceBuilders = new ArrayList<AbstractNacosPropertySourceBuilder>(
abstractNacosPropertySourceBuilderBeanNames.length); for (String beanName : abstractNacosPropertySourceBuilderBeanNames) {
this.nacosPropertySourceBuilders.add(
beanFactory.getBean(beanName, AbstractNacosPropertySourceBuilder.class));
} this.configServiceBeanBuilder = getConfigServiceBeanBuilder(beanFactory); String[] beanNames = beanFactory.getBeanDefinitionNames(); for (String beanName : beanNames) {
processPropertySource(beanName, beanFactory);
} }
 private void processPropertySource(String beanName, ConfigurableListableBeanFactory beanFactory) {

        if (processedBeanNames.contains(beanName)) {
return;
} BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); // Build multiple instance if possible
List<NacosPropertySource> nacosPropertySources = buildNacosPropertySources(beanName, beanDefinition); // Add Orderly
for (NacosPropertySource nacosPropertySource : nacosPropertySources) {
addNacosPropertySource(nacosPropertySource);
addListenerIfAutoRefreshed(nacosPropertySource);
} processedBeanNames.add(beanName);
}
private List<NacosPropertySource> buildNacosPropertySources(String beanName, BeanDefinition beanDefinition) {
for (AbstractNacosPropertySourceBuilder builder : nacosPropertySourceBuilders) {
if (builder.supports(beanDefinition)) {
return builder.build(beanName, beanDefinition);
}
}
return Collections.emptyList();
}
 public List<NacosPropertySource> build(String beanName, T beanDefinition) {
Map<String, Object>[] attributesArray = this.resolveRuntimeAttributesArray(beanDefinition, this.globalNacosProperties);
int size = attributesArray == null ? 0 : attributesArray.length;
if (size == 0) {
return Collections.emptyList();
} else {
List<NacosPropertySource> nacosPropertySources = new ArrayList(size); for(int i = 0; i < size; ++i) {
Map<String, Object> attributes = attributesArray[i];
if (!CollectionUtils.isEmpty(attributes)) {
NacosPropertySource nacosPropertySource = this.doBuild(beanName, beanDefinition, attributesArray[i]);
NacosConfigMetadataEvent metadataEvent = this.createMetaEvent(nacosPropertySource, beanDefinition);
this.initMetadataEvent(nacosPropertySource, beanDefinition, metadataEvent);
this.publishMetadataEvent(metadataEvent);
nacosPropertySources.    (nacosPropertySource);
}
}
return nacosPropertySources;
}
}
protected NacosPropertySource doBuild(String beanName, T beanDefinition, Map<String, Object> runtimeAttributes) {

        // Get annotation metadata
String name = (String) runtimeAttributes.get(NAME_ATTRIBUTE_NAME);
String dataId = (String) runtimeAttributes.get(DATA_ID_ATTRIBUTE_NAME);
String groupId = (String) runtimeAttributes.get(GROUP_ID_ATTRIBUTE_NAME);
Map<String, Object> nacosPropertiesAttributes = (Map<String, Object>) runtimeAttributes.get(PROPERTIES_ATTRIBUTE_NAME); Properties nacosProperties = resolveProperties(nacosPropertiesAttributes, environment, globalNacosProperties); String nacosConfig = nacosConfigLoader.load(dataId, groupId, nacosProperties); if (!StringUtils.hasText(nacosConfig)) {
if (logger.isWarnEnabled()) {
logger.warn(format("There is no content for NacosPropertySource from dataId[%s] , groupId[%s] , properties[%s].",
dataId,
groupId,
valueOf(nacosPropertiesAttributes)));
}
} if (!StringUtils.hasText(name)) {
name = buildDefaultPropertySourceName(dataId, groupId, nacosProperties);
} NacosPropertySource nacosPropertySource = new NacosPropertySource(name, nacosConfig); nacosPropertySource.setBeanName(beanName); String beanClassName = beanDefinition.getBeanClassName();
if (StringUtils.hasText(beanClassName)) {
nacosPropertySource.setBeanType(resolveClassName(beanClassName, classLoader));
}
nacosPropertySource.setGroupId(groupId);
nacosPropertySource.setDataId(dataId);
nacosPropertySource.setProperties(nacosProperties); initNacosPropertySource(nacosPropertySource, beanDefinition, runtimeAttributes); return nacosPropertySource; }

加载初始化的内容

 /**
* Load Nacos config vid dataId, groupId and {@link Properties acos Properties}
*
* @param dataId dataId
* @param groupId groupId
* @param nacosProperties {@link Properties acos Properties}
* @return Nacos config
* @throws RuntimeException If {@link ConfigService} creating is failed.
*/
public String load(String dataId, String groupId, Properties nacosProperties) throws RuntimeException {
try {
configService = nacosServiceFactory != null ?
nacosServiceFactory.createConfigService(nacosProperties) :
NacosFactory.createConfigService(nacosProperties);
} catch (NacosException e) {
throw new RuntimeException("ConfigService can't be created with dataId :"
+ dataId + " , groupId : " + groupId + " , properties : " + nacosProperties
, e);
}
return NacosUtils.getContent(configService, dataId, groupId);
}

这里我们之前应该是漏掉了,我们会过来再看下,这里根据反射的构造函数决定用哪个构造函数初始化;

CacheableEventPublishingNacosServiceFactory.java
 public ConfigService createConfigService(Properties properties) throws NacosException {
Properties copy = new Properties();
copy.putAll(properties);
String cacheKey = NacosUtils.identify(copy);
ConfigService configService = (ConfigService)this.configServicesCache.get(cacheKey);
if (configService == null) {
configService = this.doCreateConfigService(copy);
this.configServicesCache.put(cacheKey, configService);
} return configService;
}
 private ConfigService doCreateConfigService(Properties properties) throws NacosException {
ConfigService configService = NacosFactory.createConfigService(properties);
return new EventPublishingConfigService(configService, properties, this.context, this.nacosConfigListenerExecutor);
}

不管nacosServiceFactory是否为空,绕到最后都是通过下面的方式进行初始化

public class ConfigFactory {
public ConfigFactory() {
} public static ConfigService createConfigService(Properties properties) throws NacosException {
try {
Class<?> driverImplClass = Class.forName("com.alibaba.nacos.client.config.NacosConfigService");
Constructor constructor = driverImplClass.getConstructor(Properties.class);
ConfigService vendorImpl = (ConfigService)constructor.newInstance(properties);
return vendorImpl;
} catch (Throwable var4) {
throw new NacosException(-400, var4.getMessage());
}
}
NacosConfigService.java中的构造函数进行初始化,同时也初始化了我们的clientWorker;
public NacosConfigService(Properties properties) throws NacosException {
String encodeTmp = properties.getProperty("encode");
if (StringUtils.isBlank(encodeTmp)) {
this.encode = "UTF-8";
} else {
this.encode = encodeTmp.trim();
} String namespaceTmp = properties.getProperty("namespace");
if (StringUtils.isBlank(namespaceTmp)) {
this.namespace = TenantUtil.getUserTenant();
properties.put("namespace", this.namespace);
} else {
this.namespace = namespaceTmp;
properties.put("namespace", this.namespace);
} this.agent = new ServerHttpAgent(properties);
this.agent.start();
this.worker = new ClientWorker(this.agent, this.configFilterChainManager);
}

AnnotationNacosPropertySourceBuilder.java

protected Map<String, Object>[] resolveRuntimeAttributesArray(AnnotatedBeanDefinition beanDefinition, Properties globalNacosProperties) {
AnnotationMetadata metadata = beanDefinition.getMetadata();
Set<String> annotationTypes = metadata.getAnnotationTypes();
List<Map<String, Object>> annotationAttributesList = new LinkedList();
Iterator var6 = annotationTypes.iterator(); while(var6.hasNext()) {
String annotationType = (String)var6.next();
annotationAttributesList.addAll(this.getAnnotationAttributesList(metadata, annotationType));
} return (Map[])annotationAttributesList.toArray(new Map[0]);
}

以上就是一个过程,后面我们在专题分享他这么多的意义,或者说目的;

这样子一套跳转下来,一个注解类的解析就结束了,下面我们就获得了这个类的相关东东,那些value,以及property,后面我们就看下他如何取值,以及后续相关操作! 

NacosUtils.java
/**
* Get content from {@link ConfigService} via dataId and groupId
*
* @param configService {@link ConfigService}
* @param dataId dataId
* @param groupId groupId
* @return If available , return content , or <code>null</code>
*/
public static String getContent(ConfigService configService, String dataId, String groupId) {
String content = null;
try {
content = configService.getConfig(dataId, groupId, DEFAULT_TIMEOUT);
} catch (NacosException e) {
if (logger.isErrorEnabled()) {
logger.error("Can't get content from dataId : " + dataId + " , groupId : " + groupId, e);
}
}
return content;
}
NacosConfigService.java
 @Override
public String getConfig(String dataId, String group, long timeoutMs) throws NacosException {
return getConfigInner(namespace, dataId, group, timeoutMs);
}

客户端的代码就是通过这个方式去获取的属性值,只要你坚持没有什么是不可能的,加油!

 private String getConfigInner(String tenant, String dataId, String group, long timeoutMs) throws NacosException {
group = this.null2defaultGroup(group);
ParamUtils.checkKeyParam(dataId, group);
ConfigResponse cr = new ConfigResponse();
cr.setDataId(dataId);
cr.setTenant(tenant);
cr.setGroup(group);
// 优先使用本地配置
String content = LocalConfigInfoProcessor.getFailover(this.agent.getName(), dataId, group, tenant);
if (content != null) {
log.warn(this.agent.getName(), "[get-config] get failover ok, dataId={}, group={}, tenant={}, config={}", new Object[]{dataId, group, tenant, ContentUtils.truncateContent(content)});
cr.setContent(content);
this.configFilterChainManager.doFilter((IConfigRequest)null, cr);
content = cr.getContent();
return content;
} else {
try {
content = this.worker.getServerConfig(dataId, group, tenant, timeoutMs);
cr.setContent(content);
this.configFilterChainManager.doFilter((IConfigRequest)null, cr);
content = cr.getContent();
return content;
} catch (NacosException var9) {
if (403 == var9.getErrCode()) {
throw var9;
} else {
log.warn("NACOS-0003", LoggerHelper.getErrorCodeStr("NACOS", "NACOS-0003", "环境问题", "get from server error"));
log.warn(this.agent.getName(), "[get-config] get from server error, dataId={}, group={}, tenant={}, msg={}", new Object[]{dataId, group, tenant, var9.toString()});
log.warn(this.agent.getName(), "[get-config] get snapshot ok, dataId={}, group={}, tenant={}, config={}", new Object[]{dataId, group, tenant, ContentUtils.truncateContent(content)});
content = LocalConfigInfoProcessor.getSnapshot(this.agent.getName(), dataId, group, tenant);
cr.setContent(content);
this.configFilterChainManager.doFilter((IConfigRequest)null, cr);
content = cr.getContent();
return content;
}
}
}
}
public class LocalConfigInfoProcessor {

    private static final Logger LOGGER = LogUtils.logger(LocalConfigInfoProcessor.class);

    static public String getFailover(String serverName, String dataId, String group, String tenant) {
File localPath = getFailoverFile(serverName, dataId, group, tenant);
if (!localPath.exists() || !localPath.isFile()) {
return null;
} try {
return readFile(localPath);
} catch (IOException ioe) {
LOGGER.error("[" + serverName + "] get failover error, " + localPath, ioe);
return null;
}
}
}

还是这个类中的方法

 static File getFailoverFile(String serverName, String dataId, String group, String tenant) {
File tmp = new File(LOCAL_SNAPSHOT_PATH, serverName + "_nacos");
tmp = new File(tmp, "data");
if (StringUtils.isBlank(tenant)) {
tmp = new File(tmp, "config-data");
} else {
tmp = new File(tmp, "config-data-tenant");
tmp = new File(tmp, tenant);
}
return new File(new File(tmp, group), dataId);
}
 public String getServerConfig(String dataId, String group, String tenant, long readTimeout)
throws NacosException {
if (StringUtils.isBlank(group)) {
group = Constants.DEFAULT_GROUP;
} HttpResult result = null;
try {
List<String> params = null;
if (StringUtils.isBlank(tenant)) {
params = Arrays.asList("dataId", dataId, "group", group);
} else {
params = Arrays.asList("dataId", dataId, "group", group, "tenant", tenant);
}
result = agent.httpGet(Constants.CONFIG_CONTROLLER_PATH, null, params, agent.getEncode(), readTimeout);
} catch (IOException e) {
String message = String.format(
"[%s] [sub-server] get server config exception, dataId=%s, group=%s, tenant=%s", agent.getName(),
dataId, group, tenant);
LOGGER.error(message, e);
throw new NacosException(NacosException.SERVER_ERROR, e.getMessage());
} switch (result.code) {
case HttpURLConnection.HTTP_OK:
LocalConfigInfoProcessor.saveSnapshot(agent.getName(), dataId, group, tenant, result.content);
return result.content;
case HttpURLConnection.HTTP_NOT_FOUND:
LocalConfigInfoProcessor.saveSnapshot(agent.getName(), dataId, group, tenant, null);
return null;
case HttpURLConnection.HTTP_CONFLICT: {
LOGGER.error(
"[{}] [sub-server-error] get server config being modified concurrently, dataId={}, group={}, "
+ "tenant={}", agent.getName(), dataId, group, tenant);
throw new NacosException(NacosException.CONFLICT,
"data being modified, dataId=" + dataId + ",group=" + group + ",tenant=" + tenant);
}
case HttpURLConnection.HTTP_FORBIDDEN: {
LOGGER.error("[{}] [sub-server-error] no right, dataId={}, group={}, tenant={}", agent.getName(), dataId,
group, tenant);
throw new NacosException(result.code, result.content);
}
default: {
LOGGER.error("[{}] [sub-server-error] dataId={}, group={}, tenant={}, code={}", agent.getName(), dataId,
group, tenant, result.code);
throw new NacosException(result.code,
"http error, code=" + result.code + ",dataId=" + dataId + ",group=" + group + ",tenant=" + tenant);
}
}
client在取值的话优先通过本地文件的方式去访问,取不到的话再通过http的方式去nacos中去取;这样就是一个取值的闭环了;

我感觉这样主要是client和nacos部署到一起的方式去解决了!

下面我们开始分析Nacos的思想,基本上本篇结束怎个Nacos客户端加载的过程就结束了,启动的时候如何取值,下面我们会分析Nacos发布之后,客户端是如何取值的,
这里我们不妨猜测下,会不会采用了代理模式,我们每次取值的时候,在我们取值前,封装了一部分取值的操作,取值的操作应该就是前面的那套逻辑^_^
加油,go!

Nacos深入浅出(八)的更多相关文章

  1. Nacos深入浅出(十)

    基本上到第9篇,整个请求的一套就结束了,感觉这里跳跳绕绕很多东西,下面我们来做个总结:从Nacos配置平台修改,到Client请求更新,事件触发去取值返回给客户端,整个过程感觉只分析到了4.5层的深度 ...

  2. Nacos深入浅出(九)

    然而Nacos的发布操作并不是上面我们想的那样通过代理去实现,通过下面的代码我们分析下: public class NacosConfigurationPropertiesBindingPostPro ...

  3. Nacos深入浅出(七)

    大家可以把这个也下载下来,结合之前的Nacos一起来看下,感觉前面几篇看了好像冰山一角的感觉 学无止境! https://github.com/nacos-group/nacos-spring-pro ...

  4. Nacos深入浅出(六)

    其实我们发现在我们本地新生成了文件,这个文件就是nacos; 这个文件怎么那么眼熟,不就是我们的controller中的注解里面的参数value么: @Controller @NacosPropert ...

  5. Nacos深入浅出(五)

    四中标色的代码 result = ConfigService.dump(dataId, group, tenant, cf.getContent(), lastModified); 我们看下这个方法 ...

  6. Nacos深入浅出(四)

    private void executeAsyncInvoke() { while (!queue.isEmpty()) { NotifySingleTask task = queue.poll(); ...

  7. Nacos深入浅出(二)

    如果你的服务已经能正常跑起来,个人建议可以先感受下nacos的魅力,也就是怎么使用吧 直接上代码 @Controller @NacosPropertySource(dataId = "spr ...

  8. Nacos深入浅出(一)

    Nacos代码第一次给我的感觉有点小清新,下面就带大家抽丝剥茧看看源代码,看看阿里大神的东东: 建议大家先把Nacos跑起来,网上有很多教程,最好直接去git里面拉代码,在IDEA里面运行: cons ...

  9. Nacos(八):Nacos持久化

    参考和感谢 Spring Cloud Alibaba基础教程:Nacos的数据持久化 前言 前景回顾: Nacos(七):Nacos共享配置 Nacos(六):多环境下如何"管理" ...

随机推荐

  1. VC DLL方法的__declspec导入导出

    https://msdn.microsoft.com/zh-cn/library/a90k134d.aspx https://msdn.microsoft.com/zh-cn/library/ms23 ...

  2. 微信公众号支付 redirect_uri 参数错误

    登录微信公众平台 1.配置 公众号设置-功能设置 JS接口安全域名 网页授权域名 2.配置 微信支付-开发配置 支付授权目录 测试授权目录 测试白名单    

  3. MysqL的root用户不允许远程连接,只能通过PHPMYADMIN

    解决方法:1.改表法 可能是你的帐号不允许从远程登陆,只能在localhost.这个时候只要在localhost的那台电脑,登入mysql后,更改 "mysql" 数据库里的 &q ...

  4. PYTHON 爬虫笔记六:PyQuery库基础用法

    知识点一:PyQuery库详解及其基本使用 初始化 字符串初始化 html = ''' <div> <ul> <li class="item-0"&g ...

  5. Storm worker 并行度等理解

    Storm 调优是非常重要的, 仅次于写出正确的代码, 好在Storm官网上有关于worker executors tasks的介绍, http://storm.incubator.apache.or ...

  6. gVim/Vim 一键编译、连接、运行 C/C++ 单文件

    用于Gvim 或 Vim 配置文件的一键编译与运行函数(注:需要机器上安装了GCC才行) 本代码只加入了对C/C++的编译与运行,如果要加入其语言的可以参考此代码加入即可 同时,本代码加入了对Wind ...

  7. 同程联盟景点门票动态程序 beta1.0源码

    经过一段时间的开发,以及内部测试,同程网联盟景区新版程序正式发布推出,感谢广大联盟会员一直以来的支持与关注! 同程网联盟景区新版程序新功能介绍: 1.统一的页面风格.页面风格将与随后推出的度假线路.酒 ...

  8. python3 - 写一个生成双色球号码的一个程序,生成的号码写到文件里面

    写一个生成双色球号码的一个程序,生成的号码写到文件里面 # 中奖号码由6个红色球号码和1个蓝色球号码组成 # 篮球范围:01-16 # 红球范围:01-33 def swq(num): random. ...

  9. Maven项目中使用JUnit进行单元测试

    1.打开maven项目中的pom.xml,添加JUnit 的jar包 2.在src/test/java下右键新建JUnit Test Cast

  10. 岭回归与Lasso回归

    线性回归的一般形式 过拟合问题及其解决方法 问题:以下面一张图片展示过拟合问题 解决方法:(1):丢弃一些对我们最终预测结果影响不大的特征,具体哪些特征需要丢弃可以通过PCA算法来实现:(2):使用正 ...