配置中心框架IConfCenter

神牛003發表於2018-09-18

本篇和大家分享的是一個簡易配置中心框架IConfCenter,框架是利用空餘時間寫的,主要以配置檔案+redis儲存方式作為資料同步驅動,目前支援的配置檔案格式有 .properties 和 .config,後期有時間可能增加 .xml 和 .yml檔案的識別。

框架結構簡單分為:

  • confserver - 服務端

    confAdmin - 配置中心後臺管理

    confCenter - 配置中心

  • confclient - 客戶端

    每分鐘獲取配置

    訂閱配置中心重新整理配置

發一張配置中心應用到專案中的手工設計圖:

 

confAdmin - 配置中心後臺管理

後臺管理主要就是一個簡單的操作介面,採用springboot+thymeleaf+jquery搭建,目前主要有兩個功能:展示配置檔案列表和啟用某個配置

展示配置檔案列表:其實就是讀取本地磁碟目錄中的配置檔案資訊,主要的service程式碼如下:

 1     /**
 2      * 配置檔案列表
 3      *
 4      * @return
 5      */
 6     public List<File> getListConf() {
 7         File baseFile = new File(confCenterConf.confserver_confs_basepath);
 8         File[] files = baseFile.listFiles();
 9         List<File> list = Arrays.asList(files).
10                 stream().
11                 sorted(Comparator.comparing(File::lastModified).reversed()).
12                 collect(Collectors.toList());
13         return list;
14     }

啟用某個配置:主要通過介面按鈕觸發ajax提交一個啟動post請求,後端通過解析指定配置檔案內容為Map結構,並永久儲存於Redis快取中(直到下一次配置內容更新),最後通過Redis的釋出功能通知給訂閱該配置的客戶端,讓客戶端通過api重新獲取並更新本地配置。主要的Service程式碼如下:

 1     /**
 2      * 啟用某個配置+通知消費端(訂閱channel規則:confs_配置檔名)
 3      *
 4      * @param confPath
 5      * @return
 6      */
 7     public MoRp qyConf(String confPath) {
 8         MoRp rp = new MoRp();
 9         rp.setStatus(EnumHelper.EmRpStatus.失敗.getVal());
10 
11         try {
12             //讀取配置檔案
13             Map<String, Object> map = LoadConf.readConfToMap(confPath);
14             if (map.isEmpty()) {
15                 rp.setMessage("載入配置檔案失敗,稍後重試");
16                 return rp;
17             }
18 
19             //檔名稱
20             String filePathToName = LoadConf.getFilePathToName(confPath, true);
21 
22             //快取key
23             String cacheKey = String.format("confs_%s", filePathToName);
24 
25             //2018.09.13 臨時增加配置檔案修改時間
26             File file = new File(confPath);
27             MoGetConfRp confRp = new MoGetConfRp();
28             confRp.setConfLastModified(file.lastModified());
29             confRp.setConfs(map);
30             confRp.setConfVersion(filePathToName);
31             confRp.setStatus(EnumHelper.EmRpStatus.成功.getVal());
32 
33             //儲存到快取中 永久
34             if (jedisTool.set(cacheKey, confRp, 0)) {
35 
36                 //釋出訊息,通知客戶端更新配置
37                 jedisTool.publish(cacheKey, confRp.getConfVersion());
38                 rp.setStatus(EnumHelper.EmRpStatus.成功.getVal());
39                 rp.setMessage(EnumHelper.EmRpStatus.成功.toString());
40             }
41         } catch (IOException e) {
42             e.printStackTrace();
43         }
44         return rp;
45     }

confCenter - 配置中心

主要提供了一個獲取指定版本的配置檔案資訊api,資訊來源由Redis快取提供,當Redis快取不存在時不會去解析配置檔案,因此主要用ConfiAdmin管理後臺觸發資料來源。其主要程式碼:

    /**
     * 獲取配置資訊
     *
     * @param rq
     * @return
     */
    public MoGetConfRp getconf(MoGetConfRq rq) {

        MoGetConfRp rp = new MoGetConfRp();
        try {
            //未指定配置版本,採用預設配置版本
            if (rq.getConfVersion().isEmpty()) {
                rq.setConfVersion(confCenterConf.confserver_confs_currentConfVersion);
            }
            if (rq.getConfVersion().isEmpty()) {
                rp.setMessage("未找到配置版本");
                return rp;
            }

            //快取key
            String cacheKey = String.format("confs_%s", rq.getConfVersion());

            //獲取快取中是否存在
            rp = jedisTool.get(cacheKey, MoGetConfRp.class);
            if (rp.getStatus() == EnumHelper.EmRpStatus.成功.getVal() &&
                    rp.getConfs().size() >= 1) {
                rp.setStatus(EnumHelper.EmRpStatus.成功.getVal());
                rp.setMessage(EnumHelper.EmRpStatus.成功.toString());
                return rp;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return rp;
    }

confclient - 客戶端

主要乾了兩個事情:每分鐘獲取配置和訂閱配置中心重新整理配置。該客戶端專案各位可以打包成jar引入專案中,加上相關配置即可引入配置中心客戶端

每分鐘獲取配置

為了配置內容的一致性,這裡採用了Scheduled每隔一分鐘請求一下配置中心api,然後通過版本號對比是否有更新,如果對比有新版本那麼即可更新快取於本地的配置資訊。主要程式碼如:

 1 /**
 2      * 每分鐘獲取配置,版本號不一致更新本地快取
 3      * 
 4      */
 5     @Scheduled(initialDelay =  1000 * 60,fixedDelay = 1000 * 60)
 6     public void refreshConf() {
 7         System.out.println(new Date() + ":當前配置版本" +
 8                 confCenterConf.confserver_confs_currentConfVersion);
 9         if (confCenterConf.confserver_confs_currentConfVersion.isEmpty()) {
10             System.out.println("版本為空,無法自動拉取配置");
11             return;
12         }
13         updateConf(confCenterConf.confserver_confs_currentConfVersion);
14     }
15 
16     /**
17      * 更新本地配置
18      * @param strVersion
19      */
20     private void updateConf(String strVersion) {
21         //獲取配置中心配置
22         MoGetConfRp rp = confCenterClientService.getConfCenterConf(strVersion);
23         if (rp.getStatus() != EnumHelper.EmRpStatus.成功.getVal()) {
24             return;
25         }else if(rp.getConfLastModified() == confCenterClientService.getConfLastModified()){
26             return;
27         }
28         System.out.println(new Date() + ":更新本地配置");
29         //版本不一致,更新本地快取
30         confCenterClientService.setConf(rp);
31     }

訂閱配置中心重新整理配置

通過實現CommandLineRunner介面的run方法,在專案啟動時通過Redis訂閱配置中心訊息,達到配置中心主動通知更新配置的目的。主要程式碼:

    /**
     * 程式啟動執行服務 訂閱配置中心重新整理配置通道
     * 
     * @param strings
     * @throws Exception
     */
    @Override
    public void run(String... strings) throws Exception {
        //訂閱配置中心重新整理配置通道
        jedisTool.subscribe(
                "confs_" + confCenterConf.confserver_confs_currentConfVersion,
                b -> {
                    System.out.println(new Date() + ":收到配置中心重新整理配置通知,版本-" + b);
                    updateConf(b.toString());
                });
    }

在文章結尾時,發一張配置中心後臺管理介面圖,並希望各位能夠喜歡配置中心框架IConfCenter

 

相關文章