1、阅读源码前的准备
配置数据源
将distribution工程下conf文件夹中的nacos-mysql.sql脚本执行,然后在console工程的application.properties中加入以下数据库的配置:
spring.datasource.platform=mysqldb.num=1### Connect URL of DB:db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTCdb.user=rootdb.password=123456
2、阅读源码
2.1 启动类com.alibaba.nacos.Nacos
添加启动参数:-Dnacos.standalone=true -Dnacos.home=D:\nacos,启动工程即可。
问题:
①:客户端怎么和服务端保持长连接
②:配置更新之后如何进行推送更新
当我们通过控制台添加一个配置并发布的时候,代码实际上执行的是:com.alibaba.nacos.config.server.controller.ConfigController#publishConfig
这里面主要做了两件事:
保存配置信息到数据库
persistService.insertOrUpdate(srcIp, srcUser, configInfo, time, configAdvanceInfo, true);
这个persistService在nacos中有两个实现,分别是:
这两个实现本身作为一个Component被加载,而被加载的条件就是使用@Conditional(value = ConditionOnExternalStorage.class)来进行判断:
public class ConditionOnExternalStorage implements Condition {
@Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return !PropertyUtil.isEmbeddedStorage(); } }
发布一个配置变更事件
ConfigChangePublisher .notifyConfigChange(new ConfigDataChangeEvent(false, dataId, group, tenant, time.getTime()));
既然在这里发布事件,那么就肯定有一个地方在监听这个事件,经过查找我们看到了AsyncNotifyService。
com.alibaba.nacos.config.server.service.ConfigChangePublisher#notifyConfigChange
public static void notifyConfigChange(ConfigDataChangeEvent event) {
if (PropertyUtil.isEmbeddedStorage() && !ApplicationUtils.getStandaloneMode()) {
return; } NotifyCenter.publishEvent(event);}
com.alibaba.nacos.common.notify.NotifyCenter#publishEvent(Event)
public static boolean publishEvent(final Event event) {
try {
return publishEvent(event.getClass(), event); } catch (Throwable ex) {
LOGGER.error("There was an exception to the message publishing : {}", ex); return false; }}
private static boolean publishEvent(final Class extends Event> eventType, final Event event) {
final String topic = ClassUtils.getCanonicalName(eventType); if (ClassUtils.isAssignableFrom(SlowEvent.class, eventType)) {
return INSTANCE.sharePublisher.publish(event); } if (INSTANCE.publisherMap.containsKey(topic)) {
EventPublisher publisher = INSTANCE.publisherMap.get(topic); return publisher.publish(event); } LOGGER.warn("There are no [{}] publishers for this event, please register", topic); return false;}
上面这段代码就是从一个事件--->事件发布器中根据事件名称取出发布器,然后执行事件发布,那么接下来,就有几个问题了:
publisherMap是在什么时候填充的呢?
通过搜索代码,我们可以看到这个publisherMap的填充是在com.alibaba.nacos.common.notify.NotifyCenter#registerToPublisher中完成的
registerToPublisher什么时候被调用?
通过观察方法的调用链,我们发现最终是在ServerMemberManager中的构造器里面的init()方法调用到了NotifyCenter#registerToPublisher方法,
最终经过这个方法之后,publisherMap里面就主要有三个元素:
到此解决了上面的两个问题,后续将重点说一下这个ServerMemberManager类。
2.2 发布配置
2.2.1 方法调用链
NacosConfigService#publishConfig
NacosConfigService#publishConfigInner
ConfigController#publishConfig
ConfigChangePublisher#notifyConfigChange
NotifyCenter#publishEvent(Event)
主要是调用/v1/cs/configs的post请求来发布配置,而该端点对应的controller为ConfigController,方法为publishConfig
主要在com.alibaba.nacos.common.notify.EventPublisher#publish中完成,最终由DefaultPublisher#publish方法完成: