NacosValue 定义在 nacos-api 工程中:com.alibaba.nacos.api.config.annotation.NacosValue

注解解析在 nacos-spring-project 工程中:

com.alibaba.nacos.spring.util.NacosBeanUtils#registerNacosValueAnnotationBeanPostProcessor

com.alibaba.nacos.spring.context.annotation.config.NacosValueAnnotationBeanPostProcessor

实现 BeanPostProcessor 接口,可以在创建 bean 的过程中插入自定义逻辑,NacosValueAnnotationBeanPostProcessor 扫描属性和方法上的 NacosValue 注解。

执行顺序:bean 的构造方法,postProcessBeforeInitialization,init,postProcessAfterInitialization

@Override
public Object postProcessBeforeInitialization(Object bean, final String beanName)
throws BeansException { doWithFields(bean, beanName); doWithMethods(bean, beanName); return super.postProcessBeforeInitialization(bean, beanName);
}

nacos 客户端定时从 nacos server 拉取更新,如果有更新,则通过事件把新值注入到属性中。

com.alibaba.nacos.client.config.impl.ClientWorker.LongPullingRunnable
com.alibaba.nacos.client.config.impl.CacheData#safeNotifyListener
检测到变化

// 配置文件发生变化,把这种变化转化为 spring 事件
private void safeNotifyListener(final String dataId, final String group, final String content,
final String md5, final ManagerListenerWrap listenerWrap) {
final Listener listener = listenerWrap.listener; // 把逻辑封装成 job,可异步可同步
Runnable job = new Runnable() {
public void run() {
ClassLoader myClassLoader = Thread.currentThread().getContextClassLoader();
ClassLoader appClassLoader = listener.getClass().getClassLoader();
try {
if (listener instanceof AbstractSharedListener) {
AbstractSharedListener adapter = (AbstractSharedListener) listener;
adapter.fillContext(dataId, group);
LOGGER.info("[{}] [notify-context] dataId={}, group={}, md5={}", name, dataId, group, md5);
}
// 执行回调之前先将线程classloader设置为具体webapp的classloader,以免回调方法中调用spi接口是出现异常或错用(多应用部署才会有该问题)。
Thread.currentThread().setContextClassLoader(appClassLoader); ConfigResponse cr = new ConfigResponse();
cr.setDataId(dataId);
cr.setGroup(group);
cr.setContent(content);
configFilterChainManager.doFilter(null, cr);
String contentTmp = cr.getContent();
// 真正发布事件的地方
listener.receiveConfigInfo(contentTmp);
listenerWrap.lastCallMd5 = md5;
LOGGER.info("[{}] [notify-ok] dataId={}, group={}, md5={}, listener={} ", name, dataId, group, md5,
listener);
} catch (NacosException de) {
LOGGER.error("[{}] [notify-error] dataId={}, group={}, md5={}, listener={} errCode={} errMsg={}", name,
dataId, group, md5, listener, de.getErrCode(), de.getErrMsg());
} catch (Throwable t) {
LOGGER.error("[{}] [notify-error] dataId={}, group={}, md5={}, listener={} tx={}", name, dataId, group,
md5, listener, t.getCause());
} finally {
Thread.currentThread().setContextClassLoader(myClassLoader);
}
}
}; final long startNotify = System.currentTimeMillis();
try {
if (null != listener.getExecutor()) {
listener.getExecutor().execute(job);
} else {
job.run();
}
} catch (Throwable t) {
LOGGER.error("[{}] [notify-error] dataId={}, group={}, md5={}, listener={} throwable={}", name, dataId, group,
md5, listener, t.getCause());
}
final long finishNotify = System.currentTimeMillis();
LOGGER.info("[{}] [notify-listener] time cost={}ms in ClientWorker, dataId={}, group={}, md5={}, listener={} ",
name, (finishNotify - startNotify), dataId, group, md5, listener);
}

发布事件

com.alibaba.nacos.spring.context.event.config.DelegatingEventPublishingListener#publishEvent

DelegatingEventPublishingListener 类在 nacos-spring-context 工程中

private void publishEvent(String content) {
NacosConfigReceivedEvent event = new NacosConfigReceivedEvent(configService, dataId, groupId, content);
applicationEventPublisher.publishEvent(event);
}

消费事件

com.alibaba.nacos.spring.context.annotation.config.NacosValueAnnotationBeanPostProcessor#onApplicationEvent

NacosValueAnnotationBeanPostProcessor 类在 nacos-spring-context 工程中

NacosValueAnnotationBeanPostProcessor 实现了 ApplicationListener<NacosConfigReceivedEvent> 接口,NacosConfigReceivedEvent 继承自 ApplicationEvent。

public void onApplicationEvent(NacosConfigReceivedEvent event) {
String content = event.getContent();
if (content != null) {
Properties configProperties = toProperties(content); for (Object key : configProperties.keySet()) {
String propertyKey = (String)key; List<NacosValueTarget> beanPropertyList = placeholderNacosValueTargetMap.get(propertyKey);
if (beanPropertyList == null) {
continue;
} String propertyValue = configProperties.getProperty(propertyKey);
for (NacosValueTarget nacosValueTarget : beanPropertyList) {
if (nacosValueTarget.method == null) {
setField(nacosValueTarget, propertyValue);
} else {
setMethod(nacosValueTarget, propertyValue);
}
}
}
}
}

最新文章

  1. How to install ruby on mac/ change ruby source in china
  2. 基于Andoird 4.2.2的同步框架源代码学习——同步发起端
  3. android99 拍照摄像
  4. DateTimePicker时间控件:
  5. Android Studio学习随笔-模拟耗时操作(sleep)
  6. 将vim改造成C/C++开发环境(IDE) 2011
  7. 数据分析与展示——Matplotlib库入门
  8. 24 服务AIDL
  9. PHP内核之旅-6.垃圾回收机制
  10. App 基本图片配置(I)
  11. HOWTO: Avizo/Amira使用前的显卡设置(Volume Rendering,Volren不显示)
  12. 剑指offer(14)链表中倒数第K个节点
  13. 【Java】 剑指offer(17) 在O(1)时间删除链表结点
  14. mysql5.7 生成列 generated column
  15. python 基础 列表生成式 生成器
  16. highcharts柱状图实现legend和数据列一一对应效果
  17. Spring MVC、MyBatis整合文件配置详解
  18. c++重在运算符
  19. 样条曲线catmull rom转bezier
  20. java 文件操作知识点

热门文章

  1. 手摸手教你如何在 Python 编码中做到小细节大优化
  2. PHP通过exec执行git pull
  3. 利用AXI VDMA实现OV5640摄像头采集
  4. linux安装mysql8(完整图文笔记)
  5. Ionic创建混合App(二)
  6. CentOS7.6中 KVM虚拟机内存、CPU调整
  7. Linux包安装及搭建服务
  8. web框架-(一)初识web框架
  9. JavaScript设计模式 样例三 —— 装饰模式
  10. EffectiveC++01-03