四中标色的代码
result = ConfigService.dump(dataId, group, tenant, cf.getContent(), lastModified);
我们看下这个方法
/** * 保存配置文件,并缓存md5. */ static public boolean dump(String dataId, String group, String tenant, String content, long lastModifiedTs) { String groupKey = GroupKey2.getKey(dataId, group, tenant); makeSure(groupKey); final int lockResult = tryWriteLock(groupKey); assert (lockResult != 0); if (lockResult < 0) { dumpLog.warn("[dump-error] write lock failed. {}", groupKey); return false; } try { final String md5 = MD5.getInstance().getMD5String(content); if (md5.equals(ConfigService.getContentMd5(groupKey))) { dumpLog.warn( "[dump-ignore] ignore to save cache file. groupKey={}, md5={}, lastModifiedOld={}, " + "lastModifiedNew={}", groupKey, md5, ConfigService.getLastModifiedTs(groupKey), lastModifiedTs); } else if (!STANDALONE_MODE || PropertyUtil.isStandaloneUseMysql()) { DiskUtil.saveToDisk(dataId, group, tenant, content); } updateMd5(groupKey, md5, lastModifiedTs); return true; } catch (IOException ioe) { dumpLog.error("[dump-exception] save disk error. " + groupKey + ", " + ioe.toString(), ioe); if (ioe.getMessage() != null) { String errMsg = ioe.getMessage(); if (NO_SPACE_CN.equals(errMsg) || NO_SPACE_EN.equals(errMsg) || errMsg.contains(DISK_QUATA_CN) || errMsg.contains(DISK_QUATA_EN)) { // 磁盘写满保护代码 fatalLog.error("磁盘满自杀退出", ioe); System.exit(0); } } return false; } finally { releaseWriteLock(groupKey); } }
这里MD5加密的意义就体现出来了,如果content的值没有变,这不需要激活
LocalDataChangeEvent,不然则激活,这里又是另一个天地了;也是我们感兴趣的地方,go!
public static void updateMd5(String groupKey, String md5, long lastModifiedTs) { CacheItem cache = makeSure(groupKey); if (cache.md5 == null || !cache.md5.equals(md5)) { cache.md5 = md5; cache.lastModifiedTs = lastModifiedTs; EventDispatcher.fireEvent(new LocalDataChangeEvent(groupKey)); } }
这个LocalDataChangeEvent比较简单,大家简单的过下,
public class LocalDataChangeEvent implements Event { final public String groupKey; final public boolean isBeta; final public List<String> betaIps; final public String tag; public LocalDataChangeEvent(String groupKey) { this.groupKey = groupKey; this.isBeta = false; this.betaIps = null; this.tag = null; } public LocalDataChangeEvent(String groupKey, boolean isBeta, List<String> betaIps) { this.groupKey = groupKey; this.isBeta = isBeta; this.betaIps = betaIps; this.tag = null; } public LocalDataChangeEvent(String groupKey, boolean isBeta, List<String> betaIps, String tag) { this.groupKey = groupKey; this.isBeta = isBeta; this.betaIps = betaIps; this.tag = tag; } }
我们主要看这个fireEvent里面的这个onEvent是如何处理的,上代码
LongPollingService.java
@Override public void onEvent(Event event) { if (isFixedPolling()) { // ignore } else { if (event instanceof LocalDataChangeEvent) { LocalDataChangeEvent evt = (LocalDataChangeEvent)event; scheduler.execute(new DataChangeTask(evt.groupKey, evt.isBeta, evt.betaIps)); } } }
DataChangeTask这个类,看看他的庐山真面目!
class DataChangeTask implements Runnable { @Override public void run() { try { ConfigService.getContentBetaMd5(groupKey); for (Iterator<ClientLongPolling> iter = allSubs.iterator(); iter.hasNext(); ) { ClientLongPolling clientSub = iter.next(); if (clientSub.clientMd5Map.containsKey(groupKey)) { // 如果beta发布且不在beta列表直接跳过 if (isBeta && !betaIps.contains(clientSub.ip)) { continue; } // 如果tag发布且不在tag列表直接跳过 if (StringUtils.isNotBlank(tag) && !tag.equals(clientSub.tag)) { continue; } getRetainIps().put(clientSub.ip, System.currentTimeMillis()); iter.remove(); // 删除订阅关系 LogUtil.clientLog.info("{}|{}|{}|{}|{}|{}|{}", (System.currentTimeMillis() - changeTime), "in-advance", RequestUtil.getRemoteIp((HttpServletRequest)clientSub.asyncContext.getRequest()), "polling", clientSub.clientMd5Map.size(), clientSub.probeRequestSize, groupKey); clientSub.sendResponse(Arrays.asList(groupKey)); } } } catch (Throwable t) { LogUtil.defaultLog.error("data change error:" + t.getMessage(), t.getCause()); } } DataChangeTask(String groupKey) { this(groupKey, false, null); } DataChangeTask(String groupKey, boolean isBeta, List<String> betaIps) { this(groupKey, isBeta, betaIps, null); } DataChangeTask(String groupKey, boolean isBeta, List<String> betaIps, String tag) { this.groupKey = groupKey; this.isBeta = isBeta; this.betaIps = betaIps; this.tag = tag; } final String groupKey; final long changeTime = System.currentTimeMillis(); final boolean isBeta; final List<String> betaIps; final String tag; }
到这里感觉好像还是没看到究竟是在哪变了,奇怪哦,咱们继续想办法,既然跟代码没跟出什么名堂,我不妨停下来想想?
1、client在请求处理nacos参数的时候调用什么rpc服务,用的是返回的value么?
2、如果没有请求的话 数据无非就几种载体,DB,cache,file
DB不可能,我们的业务库根本就没有创建过相应的存储表,所以pass;
cache也不可能,我们重启服务之后,数据还是在的,所以呢,肯定就是file了,会不会像我们的property一样,存在某个地方,然后按照一定的规则去取值,
是不是?继续往下走,goo!