001Diamond学习003源码分析
1 服务端
1.1 数据初始化
在初始化PersistService后,会对数据源进行初始化:
1 @PostConstruct 2 public void initDataSource() throws Exception { 3 // 读取jdbc.properties配置, 加载数据源 4 Properties props = ResourceUtils.getResourceAsProperties("jdbc.properties"); 5 BasicDataSource ds = new BasicDataSource(); 6 ds.setDriverClassName(JDBC_DRIVER_NAME); 7 ds.setUrl(ensurePropValueNotNull(props.getProperty("db.url"))); 8 ds.setUsername(ensurePropValueNotNull(props.getProperty("db.user"))); 9 ds.setPassword(ensurePropValueNotNull(props.getProperty("db.password"))); 10 ds.setInitialSize(Integer.parseInt(ensurePropValueNotNull(props.getProperty("db.initialSize")))); 11 ds.setMaxActive(Integer.parseInt(ensurePropValueNotNull(props.getProperty("db.maxActive")))); 12 ds.setMaxIdle(Integer.parseInt(ensurePropValueNotNull(props.getProperty("db.maxIdle")))); 13 ds.setMaxWait(Long.parseLong(ensurePropValueNotNull(props.getProperty("db.maxWait")))); 14 ds.setPoolPreparedStatements(Boolean.parseBoolean(ensurePropValueNotNull(props 15 .getProperty("db.poolPreparedStatements")))); 16 17 this.jt = new JdbcTemplate(); 18 this.jt.setDataSource(ds); 19 // 设置最大记录数,防止内存膨胀 20 this.jt.setMaxRows(MAX_ROWS); 21 // 设置JDBC执行超时时间 22 this.jt.setQueryTimeout(QUERY_TIMEOUT); 23 }
在TimerTaskService中,会初始化一个定时任务,用于每隔600秒从数据库查询最新数据,查询数据后,首先更新缓存,然后写入磁盘:
1 @PostConstruct 2 public void init() { 3 this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { 4 5 public Thread newThread(Runnable r) { 6 Thread t = new Thread(r); 7 t.setName(THREAD_NAME); 8 t.setDaemon(true); 9 return t; 10 } 11 12 }); 13 14 DumpConfigInfoTask dumpTask = new DumpConfigInfoTask(this); 15 dumpTask.run(); 16 this.scheduledExecutorService.scheduleWithFixedDelay(dumpTask, SystemConfig.getDumpConfigInterval(), 17 SystemConfig.getDumpConfigInterval(), TimeUnit.SECONDS); 18 }
在NotifyService中,会读取配置文件加载服务端节点:
1 @PostConstruct 2 public void loadNodes() { 3 InputStream in = null; 4 try { 5 in = ResourceUtils.getResourceAsStream("node.properties"); 6 nodeProperties.load(in); 7 } 8 catch (IOException e) { 9 log.error("加载节点配置文件失败"); 10 } 11 finally { 12 try { 13 if (in != null) 14 in.close(); 15 } 16 catch (IOException e) { 17 log.error("关闭node.properties失败", e); 18 } 19 } 20 log.info("节点列表:" + nodeProperties); 21 }
1.2 更新配置
登录过程省略,提交数据进入AdminController类的postConfig方法。
先对参数进行检验处理,在进入具体的处理操作。
源码如下:
1 @RequestMapping(params = "method=postConfig", method = RequestMethod.POST) 2 public String postConfig(HttpServletRequest request, HttpServletResponse response, 3 @RequestParam("dataId") String dataId, @RequestParam("group") String group, 4 @RequestParam("content") String content, ModelMap modelMap) { 5 response.setCharacterEncoding("GBK"); 6 7 boolean checkSuccess = true; 8 String errorMessage = "参数错误"; 9 if (StringUtils.isBlank(dataId) || DiamondUtils.hasInvalidChar(dataId.trim())) { 10 checkSuccess = false; 11 errorMessage = "无效的DataId"; 12 } 13 if (StringUtils.isBlank(group) || DiamondUtils.hasInvalidChar(group.trim())) { 14 checkSuccess = false; 15 errorMessage = "无效的分组"; 16 } 17 if (StringUtils.isBlank(content)) { 18 checkSuccess = false; 19 errorMessage = "无效的内容"; 20 } 21 if (!checkSuccess) { 22 modelMap.addAttribute("message", errorMessage); 23 return "/admin/config/new"; 24 } 25 26 dataId = dataId.trim(); 27 group = group.trim(); 28 29 this.configService.addConfigInfo(dataId, group, content); 30 31 modelMap.addAttribute("message", "提交成功!"); 32 return listConfig(request, response, dataId, group, 1, 20, modelMap); 33 }
进入ConfigService类的addConfigInfo方法。
先将数据保存到数据库,然后更新缓存,再保存到本地磁盘。
最后还需要通知其他服务节点同步更改。
源码如下:
1 public void addConfigInfo(String dataId, String group, String content) { 2 checkParameter(dataId, group, content); 3 ConfigInfo configInfo = new ConfigInfo(dataId, group, content); 4 // 保存顺序:先数据库,再磁盘 5 try { 6 persistService.addConfigInfo(configInfo); 7 // 切记更新缓存 8 this.contentMD5Cache.put(generateMD5CacheKey(dataId, group), configInfo.getMd5()); 9 diskService.saveToDisk(configInfo); 10 // 通知其他节点 11 this.notifyOtherNodes(dataId, group); 12 } 13 catch (Exception e) { 14 log.error("保存ConfigInfo失败", e); 15 throw new ConfigServiceException(e); 16 } 17 }
1.3 节点通知
在ConfigService类中调用Service类的notifyConfigInfoChange方法。
在更新配置后,还需要通知其他节点重新从数据库上同步配置。
源码如下:
1 private void notifyOtherNodes(String dataId, String group) { 2 this.notifyService.notifyConfigInfoChange(dataId, group); 3 }
进入NotifyService类的notifyConfigInfoChange方法。
通过URL调用通知节点的接口。
源码如下:
1 public void notifyConfigInfoChange(String dataId, String group) { 2 Enumeration<?> enu = nodeProperties.propertyNames(); 3 while (enu.hasMoreElements()) { 4 String address = (String) enu.nextElement(); 5 if (address.contains(SystemConfig.LOCAL_IP)) { 6 continue; 7 } 8 String urlString = generateNotifyConfigInfoPath(dataId, group, address); 9 final String result = invokeURL(urlString); 10 log.info("通知节点" + address + "分组信息改变:" + result); 11 } 12 }
进入NotifyController类的notifyConfigInfo方法。
执行同步逻辑。
源码如下:
1 @RequestMapping(method = RequestMethod.GET, params = "method=notifyConfigInfo") 2 public String notifyConfigInfo(@RequestParam("dataId") String dataId, @RequestParam("group") String group) { 3 dataId = dataId.trim(); 4 group = group.trim(); 5 this.configService.loadConfigInfoToDisk(dataId, group); 6 return "200"; 7 }
进入ConfigService类的loadConfigInfoDisk方法。
先更新缓存,然后保存到本地磁盘。
源码如下:
1 public void loadConfigInfoToDisk(String dataId, String group) { 2 try { 3 ConfigInfo configInfo = this.persistService.findConfigInfo(dataId, group); 4 if (configInfo != null) { 5 this.contentMD5Cache.put(generateMD5CacheKey(dataId, group), configInfo.getMd5()); 6 this.diskService.saveToDisk(configInfo); 7 } 8 else { 9 // 删除文件 10 this.contentMD5Cache.remove(generateMD5CacheKey(dataId, group)); 11 this.diskService.removeConfigInfo(dataId, group); 12 } 13 } 14 catch (Exception e) { 15 log.error("保存ConfigInfo到磁盘失败", e); 16 throw new ConfigServiceException(e); 17 } 18 }
2 客户端
2.1 DiamondManager
创建DiamondManager,通过DefaultDiamondManager构造器创建。
通过DiamondManager的getAvailableConfigureInfomation方法获取配置内容。
源码如下:
1 @Test 2 void testClient() { 3 DiamondManager diamondManager = new DefaultDiamondManager("cnpark", "cnpark-station", new ManagerListener() { 4 public void receiveConfigInfo(String configInfo) { 5 System.out.println("receiveConfigInfo" + configInfo); 6 } 7 public Executor getExecutor() { 8 return null; 9 } 10 }); 11 diamondManager.getDiamondConfigure().setPort(8080); 12 String availableConfigureInfomation = diamondManager.getAvailableConfigureInfomation(5000); 13 System.out.println("content" + availableConfigureInfomation); 14 }
构造DefaultDiamondManager对象。
创建并启动DiamondSubscriber。
源码如下:
1 public DefaultDiamondManager(String group, String dataId, ManagerListener managerListener) { 2 this.dataId = dataId; 3 this.group = group; 4 5 diamondSubscriber = DiamondClientFactory.getSingletonDiamondSubscriber(); 6 7 this.managerListeners.add(managerListener); 8 ((DefaultSubscriberListener) diamondSubscriber.getSubscriberListener()).addManagerListeners(this.dataId, 9 this.group, this.managerListeners); 10 diamondSubscriber.addDataId(this.dataId, this.group); 11 diamondSubscriber.start(); 12 }
2.2 ManagerListener
ManagerListener是一个接口,需要实现并重写其方法。
receiveConfigInfo方法用于接收配置信息,当配置信息发生改动时,可以最新配置信息。
源码如下:
1 public interface ManagerListener { 2 3 public Executor getExecutor(); 4 5 public void receiveConfigInfo(final String configInfo); 6 }
2.3 DiamondSubscriber
通过DiamondClientFactory创建DiamondSubscriber,实际上创建的是DefaultDiamondSubscriber。
DiamondSubscriber用于订阅持久的文本配置信息。
源码如下:
1 private static DiamondSubscriber diamondSubscriber = new DefaultDiamondSubscriber(new DefaultSubscriberListener()); 2 3 public static DiamondSubscriber getSingletonDiamondSubscriber() { 4 return diamondSubscriber; 5 }
创建DefaultDiamondSubscriber。
传入SubscriberListener,创建DiamondConfigure。
源码如下:
1 public DefaultDiamondSubscriber(SubscriberListener subscriberListener) { 2 this.subscriberListener = subscriberListener; 3 this.diamondConfigure = new DiamondConfigure(); 4 }
2.4 SubscriberListener
创建SubscriberListener,实际上创建的是DefaultSubscriberListener。
源码如下:
1 public Executor getExecutor(); 2 3 public void receiveConfigInfo(final ConfigureInfomation configureInfomation);
DefaultSubscriberListener中维护了一个ManagerListener的Map集合,Key是dataId和group的组合,Value是ManagerListener的List集合。
重写了receiveConfigInfo方法,配置改动时会遍历ManagerListener并执行其receiveConfigInfo方法。
源码如下:
1 public void receiveConfigInfo(final ConfigureInfomation configureInfomation) { 2 String dataId = configureInfomation.getDataId(); 3 String group = configureInfomation.getGroup(); 4 if (null == dataId) { 5 dataLog.error("[receiveConfigInfo] dataId is null"); 6 return; 7 } 8 9 String key = makeKey(dataId, group); 10 CopyOnWriteArrayList<ManagerListener> listeners = allListeners.get(key); 11 if (listeners == null || listeners.isEmpty()) { 12 dataLog.warn("[notify-listener] no listener for dataId=" + dataId + ", group=" + group); 13 return; 14 } 15 16 for (ManagerListener listener : listeners) { 17 try { 18 notifyListener(configureInfomation, listener); 19 } 20 catch (Throwable t) { 21 dataLog.error("call listener error, dataId=" + dataId + ", group=" + group, t); 22 } 23 } 24 } 25 26 private void notifyListener(final ConfigureInfomation configureInfomation, final ManagerListener listener) { 27 if (listener == null) { 28 return; 29 } 30 31 final String dataId = configureInfomation.getDataId(); 32 final String group = configureInfomation.getGroup(); 33 final String content = configureInfomation.getConfigureInfomation(); 34 35 dataLog.info("[notify-listener] call listener " + listener.getClass().getName() + ", for " + dataId + ", " 36 + group + ", " + content); 37 38 Runnable job = new Runnable() { 39 public void run() { 40 try { 41 listener.receiveConfigInfo(content); 42 } 43 catch (Throwable t) { 44 dataLog.error(t.getMessage(), t); 45 } 46 } 47 }; 48 49 if (null != listener.getExecutor()) { 50 listener.getExecutor().execute(job); 51 } 52 else { 53 job.run(); 54 } 55 }
2.5 DiamondConfigure
创建DiamondConfigure。
DiamondConfigure封装了客户端的一些配置信息,并且会在磁盘上创建一个配置目录。
源码如下:
1 public DiamondConfigure() { 2 filePath = System.getProperty("user.home") + "/diamond"; 3 File dir = new File(filePath); 4 dir.mkdirs(); 5 6 if (!dir.exists()) { 7 throw new RuntimeException("创建diamond目录失败:" + filePath); 8 } 9 }
2.6 启动DiamondSubscriber
在方法中依次启动LocalConfigInfoProcessor和ServerAddressProcessor,最后轮询获取配置。
源码如下:
1 public synchronized void start() { 2 if (isRun) { 3 return; 4 } 5 6 if (null == scheduledExecutor || scheduledExecutor.isTerminated()) { 7 scheduledExecutor = Executors.newSingleThreadScheduledExecutor(); 8 } 9 10 localConfigInfoProcessor.start(this.diamondConfigure.getFilePath() + "/" + DATA_DIR); 11 serverAddressProcessor = new ServerAddressProcessor(this.diamondConfigure, this.scheduledExecutor); 12 serverAddressProcessor.start(); 13 14 this.snapshotConfigInfoProcessor = 15 new SnapshotConfigInfoProcessor(this.diamondConfigure.getFilePath() + "/" + SNAPSHOT_DIR); 16 // 设置domainNamePos值 17 randomDomainNamePos(); 18 initHttpClient(); 19 20 // 初始化完毕 21 isRun = true; 22 23 if (log.isInfoEnabled()) { 24 log.info("当前使用的域名有:" + this.diamondConfigure.getDomainNameList()); 25 } 26 27 if (MockServer.isTestMode()) { 28 bFirstCheck = false; 29 } 30 else { 31 // 设置轮询间隔时间 32 this.diamondConfigure.setPollingIntervalTime(Constants.POLLING_INTERVAL_TIME); 33 } 34 // 轮询 35 rotateCheckConfigInfo(); 36 37 addShutdownHook(); 38 }
2.7 启动LocalConfigInfoProcessor
通过LocalConfigInfoProcessor的start方法创建数据目录。
源码如下:
1 public synchronized void start(String rootPath) { 2 if (this.isRun) { 3 return; 4 } 5 this.rootPath = rootPath; 6 this.isRun = true; 7 if (this.singleExecutor == null || singleExecutor.isTerminated()) { 8 singleExecutor = Executors.newSingleThreadScheduledExecutor(); 9 } 10 initDataDir(rootPath); 11 startCheckLocalDir(rootPath); 12 }
2.8 启动ServerAddressProcessor
如果是本地优先,通过本地文件获取ServerAddress,默认非本地优先。
如果非本地优先,首次同步获取ServerAddress,然后定时异步获取ServerAddress,默认执行此步骤。
源码如下:
1 public synchronized void start() { 2 if (isRun) { 3 return; 4 } 5 isRun = true; 6 initHttpClient(); 7 if (this.diamondConfigure.isLocalFirst()) { 8 acquireServerAddressFromLocal(); 9 } 10 else { 11 synAcquireServerAddress(); 12 asynAcquireServerAddress(); 13 } 14 }
2.8.1 同步获取ServerAddress
调用acquireServerAddressOnce方法,先从线上服务器获取,再从日常服务器获取,最后从本地文件获取。
如果从服务器获取成功,则更新本地文件。
源码如下:
1 protected void synAcquireServerAddress() { 2 if (!isRun) { 3 throw new RuntimeException("ServerAddressProcessor不在运行状态,无法同步获取服务器地址列表"); 4 } 5 if (MockServer.isTestMode()) { 6 diamondConfigure.addDomainName("测试模式,没有使用的真实服务器"); 7 return; 8 } 9 int acquireCount = 0; 10 if (diamondConfigure.getDomainNameList().size() == 0) { 11 if (!acquireServerAddressOnce(acquireCount)) { 12 acquireCount++; 13 if (acquireServerAddressOnce(acquireCount)) { 14 // 存入本地文件 15 storeServerAddressesToLocal(); 16 log.info("在同步获取服务器列表时,向日常ConfigServer服务器获取到了服务器列表"); 17 } 18 else { 19 log.info("从本地获取Diamond地址列表"); 20 reloadServerAddresses(); 21 if (diamondConfigure.getDomainNameList().size() == 0) 22 throw new RuntimeException("当前没有可用的服务器列表"); 23 } 24 } 25 else { 26 log.info("在同步获取服务器列表时,向线上ConfigServer服务器获取到了服务器列表"); 27 // 存入本地文件 28 storeServerAddressesToLocal(); 29 } 30 } 31 }
2.8.2 定时异步获取ServiceAddress
调用acquireServerAddressOnce方法,先从线上服务器获取,再从日常服务器获取。
如果从服务器获取成功,则更新本地文件。
每300秒更新一次。
源码如下:
1 protected void asynAcquireServerAddress() { 2 if (MockServer.isTestMode()) { 3 return; 4 } 5 this.scheduledExecutor.schedule(new Runnable() { 6 public void run() { 7 if (!isRun) { 8 log.warn("ServerAddressProcessor不在运行状态,无法异步获取服务器地址列表"); 9 return; 10 } 11 int acquireCount = 0; 12 if (!acquireServerAddressOnce(acquireCount)) { 13 acquireCount++; 14 if (acquireServerAddressOnce(acquireCount)) { 15 // 存入本地文件 16 storeServerAddressesToLocal(); 17 } 18 } 19 else { 20 // 存入本地文件 21 storeServerAddressesToLocal(); 22 } 23 asynAcquireServerAddress(); 24 } 25 }, asynAcquireIntervalInSec, TimeUnit.SECONDS); 26 }
2.8.3 从服务器获取ServiceAddress
获取服务器地址和端口,以及文件名称,获取文件中保存的ServiceAddress。
源码如下:
1 private boolean acquireServerAddressOnce(int acquireCount) { 2 HostConfiguration hostConfiguration = configHttpClient.getHostConfiguration(); 3 String configServerAddress; 4 int port; 5 if (null != diamondConfigure.getConfigServerAddress()) { 6 configServerAddress = diamondConfigure.getConfigServerAddress(); 7 port = diamondConfigure.getConfigServerPort(); 8 } 9 else { 10 if (acquireCount == 0) { 11 configServerAddress = Constants.DEFAULT_DOMAINNAME; 12 port = Constants.DEFAULT_PORT; 13 } 14 else { 15 configServerAddress = Constants.DAILY_DOMAINNAME; 16 port = Constants.DEFAULT_PORT; 17 } 18 } 19 hostConfiguration.setHost(configServerAddress, port); 20 21 String serverAddressUrl = Constants.CONFIG_HTTP_URI_FILE; 22 23 HttpMethod httpMethod = new GetMethod(serverAddressUrl); 24 // 设置HttpMethod的参数 25 HttpMethodParams params = new HttpMethodParams(); 26 params.setSoTimeout(diamondConfigure.getOnceTimeout()); 27 // /////////////////////// 28 httpMethod.setParams(params); 29 30 try { 31 if (SC_OK == configHttpClient.executeMethod(httpMethod)) { 32 InputStreamReader reader = new InputStreamReader(httpMethod.getResponseBodyAsStream()); 33 BufferedReader bufferedReader = new BufferedReader(reader); 34 String address = null; 35 List<String> newDomainNameList = new LinkedList<String>(); 36 while ((address = bufferedReader.readLine()) != null) { 37 address = address.trim(); 38 if (StringUtils.isNotBlank(address)) { 39 newDomainNameList.add(address); 40 } 41 } 42 if (newDomainNameList.size() > 0) { 43 log.debug("更新使用的服务器列表"); 44 this.diamondConfigure.setDomainNameList(newDomainNameList); 45 return true; 46 } 47 } 48 else { 49 log.warn("没有可用的新服务器列表"); 50 } 51 } 52 catch (HttpException e) { 53 log.error(getErrorMessage(configServerAddress) + ", " + e); 54 } 55 catch (IOException e) { 56 log.error(getErrorMessage(configServerAddress) + ", " + e); 57 } 58 catch (Exception e) { 59 log.error(getErrorMessage(configServerAddress) + ", " + e); 60 } 61 finally { 62 httpMethod.releaseConnection(); 63 } 64 return false; 65 }
2.8.4 保存到本地文件
如果是从服务器获取的ServiceAddress,还需要将读取的地址保存到ServiceAddress文件。
源码如下:
1 void storeServerAddressesToLocal() { 2 List<String> domainNameList = new ArrayList<String>(diamondConfigure.getDomainNameList()); 3 PrintWriter printWriter = null; 4 BufferedWriter bufferedWriter = null; 5 try { 6 File serverAddressFile = 7 new File(generateLocalFilePath(this.diamondConfigure.getFilePath(), "ServerAddress")); 8 if (!serverAddressFile.exists()) { 9 serverAddressFile.createNewFile(); 10 } 11 printWriter = new PrintWriter(serverAddressFile); 12 bufferedWriter = new BufferedWriter(printWriter); 13 for (String serveraddress : domainNameList) { 14 bufferedWriter.write(serveraddress); 15 bufferedWriter.newLine(); 16 } 17 bufferedWriter.flush(); 18 } 19 catch (Exception e) { 20 log.error("存储服务器地址到本地文件失败", e); 21 } 22 finally { 23 if (bufferedWriter != null) { 24 try { 25 bufferedWriter.close(); 26 } 27 catch (IOException e) { 28 // ignore 29 } 30 } 31 if (printWriter != null) { 32 printWriter.close(); 33 } 34 } 35 }
2.8.5 从本地文件读取ServerAddress
如果没有从服务器中获取,只能从文件中读取。
源码如下:
1 void reloadServerAddresses() { 2 FileInputStream fis = null; 3 InputStreamReader reader = null; 4 BufferedReader bufferedReader = null; 5 try { 6 File serverAddressFile = 7 new File(generateLocalFilePath(this.diamondConfigure.getFilePath(), "ServerAddress")); 8 if (!serverAddressFile.exists()) { 9 return; 10 } 11 fis = new FileInputStream(serverAddressFile); 12 reader = new InputStreamReader(fis); 13 bufferedReader = new BufferedReader(reader); 14 String address = null; 15 while ((address = bufferedReader.readLine()) != null) { 16 address = address.trim(); 17 if (StringUtils.isNotBlank(address)) { 18 diamondConfigure.getDomainNameList().add(address); 19 } 20 } 21 bufferedReader.close(); 22 reader.close(); 23 fis.close(); 24 } 25 catch (Exception e) { 26 log.error("从本地文件取服务器地址失败", e); 27 } 28 finally { 29 if (bufferedReader != null) { 30 try { 31 bufferedReader.close(); 32 } 33 catch (Exception e) { 34 } 35 } 36 if (reader != null) { 37 try { 38 reader.close(); 39 } 40 catch (Exception e) { 41 } 42 } 43 if (fis != null) { 44 try { 45 fis.close(); 46 } 47 catch (Exception e) { 48 } 49 } 50 } 51 }
2.9 轮询获取配置
循环探测配置信息是否发生变化,通过三种途径:
1)检查本地配置文件,用缓存中的配置和本地配置文件中的配置比较,如果发生改变,则更新缓存,然后调用popConfigInfo方法。
2)检查服务器配置文件,用缓存中的配置和服务器配置文件中的配置比较,如果发生改变,则更新缓存,然后调用popConfigInfo方法。
3)检查本地磁盘快照,如果没有从本地配置文件中读取配置,也没有从服务器配置文件中读取配置,则获取本地磁盘快照中的配置,并更新缓存,然后调用popConfigInfo方法。
调用popConfigInfo方法后,会推送配置改动的订阅信息到监听器,然后调用saveSnapshot方法更新磁盘快照。
源码如下:
1 private void rotateCheckConfigInfo() { 2 scheduledExecutor.schedule(new Runnable() { 3 public void run() { 4 if (!isRun) { 5 log.warn("DiamondSubscriber不在运行状态中,退出查询循环"); 6 return; 7 } 8 try { 9 checkLocalConfigInfo(); 10 checkDiamondServerConfigInfo(); 11 checkSnapshot(); 12 } 13 catch (Exception e) { 14 e.printStackTrace(); 15 log.error("循环探测发生异常", e); 16 } 17 finally { 18 rotateCheckConfigInfo(); 19 } 20 } 21 }, bFirstCheck ? 60 : diamondConfigure.getPollingIntervalTime(), TimeUnit.SECONDS); 22 bFirstCheck = false; 23 }
2.10 获取配置
通过DiamondManager的getAvailableConfigureInfomation方法获取服务器上的配置。
实际上调用的是DefaultDiamondManager的getAvailableConfigureInfomation方法。
源码如下:
1 public String getAvailableConfigureInfomation(long timeout) { 2 return diamondSubscriber.getAvailableConfigureInfomation(dataId, group, timeout); 3 }
继续调用DiamondSubscriber的getAvailableConfigureInfomation方法。
实际上调用的是DefaultDiamondSubscriber的getAvailableConfigureInfomation方法。
源码如下:
1 public String getAvailableConfigureInfomation(String dataId, String group, long timeout) { 2 // 尝试先从本地和网络获取配置信息 3 try { 4 String result = getConfigureInfomation(dataId, group, timeout); 5 if (result != null && result.length() > 0) { 6 return result; 7 } 8 } 9 catch (Throwable t) { 10 log.error(t.getMessage(), t); 11 } 12 13 // 测试模式不使用本地dump 14 if (MockServer.isTestMode()) { 15 return null; 16 } 17 return getSnapshotConfiginfomation(dataId, group); 18 }
2.10.1 从本地和服务器获取配置
调用getConfigureInfomation方法。
尝试从本地配置文件获取配置,获取成功则更新缓存,并更新本地磁盘快照。
尝试从服务器配置文件获取配置,获取成功则更新缓存,并更新本地磁盘快照。
源码如下:
1 public String getConfigureInfomation(String dataId, String group, long timeout) { 2 // 同步接口流控 3 // flowControl(); 4 if (null == group) { 5 group = Constants.DEFAULT_GROUP; 6 } 7 CacheData cacheData = getCacheData(dataId, group); 8 // 优先使用本地配置 9 try { 10 String localConfig = localConfigInfoProcessor.getLocalConfigureInfomation(cacheData, true); 11 if (localConfig != null) { 12 cacheData.incrementFetchCountAndGet(); 13 saveSnapshot(dataId, group, localConfig); 14 return localConfig; 15 } 16 } 17 catch (IOException e) { 18 log.error("获取本地配置文件出错", e); 19 } 20 // 获取本地配置失败,从网络取 21 String result = getConfigureInfomation(dataId, group, timeout, false); 22 if (result != null) { 23 saveSnapshot(dataId, group, result); 24 cacheData.incrementFetchCountAndGet(); 25 } 26 return result; 27 }
2.10.2 从本地磁盘快照获取配置
调用getSnapshotConfiginfomation方法。
源码如下:
1 private String getSnapshotConfiginfomation(String dataId, String group) { 2 if (group == null) { 3 group = Constants.DEFAULT_GROUP; 4 } 5 try { 6 CacheData cacheData = getCacheData(dataId, group); 7 String config = this.snapshotConfigInfoProcessor.getConfigInfomation(dataId, group); 8 if (config != null && cacheData != null) { 9 cacheData.incrementFetchCountAndGet(); 10 } 11 return config; 12 } 13 catch (Exception e) { 14 log.error("获取snapshot出错, dataId=" + dataId + ",group=" + group, e); 15 return null; 16 } 17 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)