<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      基于NACOS和JAVA反射機(jī)制動(dòng)態(tài)更新JAVA靜態(tài)常量非@Value注解

      1.前言

      項(xiàng)目中都會(huì)使用常量類文件, 這些值如果需要變動(dòng)需要重新提交代碼,或者基于@Value注解實(shí)現(xiàn)動(dòng)態(tài)刷新, 如果常量太多也是很麻煩; 那么 能不能有更加簡便的實(shí)現(xiàn)方式呢?

      本文講述的方式是, 一個(gè)JAVA類對應(yīng)NACOS中的一個(gè)配置文件,優(yōu)先使用nacos中的配置,不配置則使用程序中的默認(rèn)值;

      2.正文

      nacos的配置如下圖所示,為了滿足大多數(shù)情況,配置了 namespace命名空間和group;

       

       

       新建個(gè)測試工程 cloud-sm.

      bootstrap.yml 中添加nacos相關(guān)配置;

      為了支持多配置文件需要注意ext-config節(jié)點(diǎn),group對應(yīng)nacos的添加的配置文件的group; data-id 對應(yīng)nacos上配置的data-id

      配置如下:

      server:
        port: 9010
        servlet:
          context-path: /sm
      spring:
        application:
          name: cloud-sm
        cloud:
          nacos:
            discovery:
              server-addr: 192.168.100.101:8848 #Nacos服務(wù)注冊中心地址
              namespace: 1
            config:
              server-addr: 192.168.100.101:8848 #Nacos作為配置中心地址
              namespace: 1
              ext-config:
                - group: TEST_GROUP
                  data-id: cloud-sm.yaml
                  refresh: true
                - group: TEST_GROUP
                  data-id: cloud-sm-constant.properties
                  refresh: true

      接下來是本文重點(diǎn):

      1)新建注解ConfigModule,用于在配置類上;一個(gè)value屬性;

      2)新建個(gè)監(jiān)聽類,用于獲取最新配置,并更新常量值

      實(shí)現(xiàn)流程:

      1)項(xiàng)目初始化時(shí)獲取所有nacos的配置

      2)遍歷這些配置文件,從nacos上獲取配置

      3)遍歷nacos配置文件,獲取MODULE_NAME的值

      4)尋找配置文件對應(yīng)的常量類,從spring容器中尋找 常量類 有注解ConfigModule 且值是 MODULE_NAME對應(yīng)的

      5)使用JAVA反射更改常量類的值

      6)增加監(jiān)聽,用于動(dòng)態(tài)刷新

       

      import org.springframework.stereotype.Component;
      import java.lang.annotation.Documented;
      import java.lang.annotation.ElementType;
      import java.lang.annotation.Retention;
      import java.lang.annotation.RetentionPolicy;
      import java.lang.annotation.Target;
      @Component
      @Documented
      @Retention(RetentionPolicy.RUNTIME)
      @Target({ElementType.TYPE})
      public @interface ConfigModule {
          /**
           *  對應(yīng)配置文件里面key為( MODULE_NAME ) 的值
           * @return
           */
          String value();
      }
      import com.alibaba.cloud.nacos.NacosConfigProperties;
      import com.alibaba.druid.support.json.JSONUtils;
      import com.alibaba.nacos.api.NacosFactory;
      import com.alibaba.nacos.api.PropertyKeyConst;
      import com.alibaba.nacos.api.config.ConfigService;
      import com.alibaba.nacos.api.config.listener.Listener;
      import com.alibaba.nacos.api.exception.NacosException;
      import com.alibaba.nacos.client.utils.LogUtils;
      import org.apache.commons.lang3.StringUtils;
      import org.slf4j.Logger;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.context.ApplicationContext;
      import org.springframework.stereotype.Component;
      
      import javax.annotation.PostConstruct;
      import java.io.IOException;
      import java.io.StringReader;
      import java.lang.reflect.Field;
      import java.util.Enumeration;
      import java.util.List;
      import java.util.Map;
      import java.util.Properties;
      import java.util.concurrent.Executor;
      
      /**
       * nacos 自定義監(jiān)聽
       *
       * @author zch
       */
      @Component
      public class NacosConfigListener {
          private Logger LOGGER = LogUtils.logger(NacosConfigListener.class);
          @Autowired
          private NacosConfigProperties configs;
          @Value("${spring.cloud.nacos.config.server-addr:}")
          private String serverAddr;
          @Value("${spring.cloud.nacos.config.namespace:}")
          private String namespace;
          @Autowired
          private ApplicationContext applicationContext;
          /**
           * 目前只考慮properties 文件
           */
          private String fileType = "properties";
          /**
           * 需要在配置文件中增加一條 MODULE_NAME 的配置,用于找到對應(yīng)的 常量類
           */
          private String MODULE_NAME = "MODULE_NAME";
      
          /**
           * NACOS監(jiān)聽方法
           *
           * @throws NacosException
           */
          public void listener() throws NacosException {
              if (StringUtils.isBlank(serverAddr)) {
                  LOGGER.info("未找到 spring.cloud.nacos.config.server-addr");
                  return;
              }
              Properties properties = new Properties();
              properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr.split(":")[0]);
              if (StringUtils.isNotBlank(namespace)) {
                  properties.put(PropertyKeyConst.NAMESPACE, namespace);
              }
      
              ConfigService configService = NacosFactory.createConfigService(properties);
              // 處理每個(gè)配置文件
              for (NacosConfigProperties.Config config : configs.getExtConfig()) {
                  String dataId = config.getDataId();
                  String group = config.getGroup();
                  //目前只考慮properties 文件
                  if (!dataId.endsWith(fileType)) continue;
      
                  changeValue(configService.getConfig(dataId, group, 5000));
      
                  configService.addListener(dataId, group, new Listener() {
                      @Override
                      public void receiveConfigInfo(String configInfo) {
                          changeValue(configInfo);
                      }
      
                      @Override
                      public Executor getExecutor() {
                          return null;
                      }
                  });
              }
          }
      
          /**
           * 改變 常量類的 值
           *
           * @param configInfo
           */
          private void changeValue(String configInfo) {
              if(StringUtils.isBlank(configInfo)) return;
              Properties proper = new Properties();
              try {
                  proper.load(new StringReader(configInfo)); //把字符串轉(zhuǎn)為reader
              } catch (IOException e) {
                  e.printStackTrace();
              }
              String moduleName = "";
              Enumeration enumeration = proper.propertyNames();
              //尋找MODULE_NAME的值
              while (enumeration.hasMoreElements()) {
                  String strKey = (String) enumeration.nextElement();
                  if (MODULE_NAME.equals(strKey)) {
                      moduleName = proper.getProperty(strKey);
                      break;
                  }
              }
              if (StringUtils.isBlank(moduleName)) return;
              Class curClazz = null;
              // 尋找配置文件對應(yīng)的常量類
              // 從spring容器中 尋找類的注解有ConfigModule 且值是 MODULE_NAME對應(yīng)的
              for (String beanName : applicationContext.getBeanDefinitionNames()) {
                  Class clazz = applicationContext.getBean(beanName).getClass();
                  ConfigModule configModule = (ConfigModule) clazz.getAnnotation(ConfigModule.class);
                  if (configModule != null && moduleName.equals(configModule.value())) {
                      curClazz = clazz;
                      break;
                  }
              }
              if (curClazz == null) return;
              // 使用JAVA反射機(jī)制 更改常量
              enumeration = proper.propertyNames();
              while (enumeration.hasMoreElements()) {
                  String key = (String) enumeration.nextElement();
                  String value = proper.getProperty(key);
                  if (MODULE_NAME.equals(key)) continue;
                  try {
                      Field field = curClazz.getDeclaredField(key);
                      //忽略屬性的訪問權(quán)限
                      field.setAccessible(true);
                      Class<?> curFieldType = field.getType();
                      //其他類型自行拓展
                      if (curFieldType.equals(String.class)) {
                          field.set(null, value);
                      } else if (curFieldType.equals(List.class)) { // 集合List元素
                          field.set(null, JSONUtils.parse(value));
                      } else if (curFieldType.equals(Map.class)) { //Map
                          field.set(null, JSONUtils.parse(value));
                      }
                  } catch (NoSuchFieldException | IllegalAccessException e) {
                      LOGGER.info("設(shè)置屬性失敗:{} {} = {} ", curClazz.toString(), key, value);
                  }
              }
          }
      
          @PostConstruct
          public void init() throws NacosException {
              listener();
          }
      }

       3.測試

      1)新建常量類Constant,增加注解@ConfigModule("sm"),盡量測試全面, 添加常量類型有 String, List,Map

      @ConfigModule("sm")
      public class Constant {
      
          public static volatile String TEST = new String("test");
      
          public static volatile List<String> TEST_LIST = new ArrayList<>();
          static {
              TEST_LIST.add("默認(rèn)值");
          }
          public static volatile Map<String,Object> TEST_MAP = new HashMap<>();
          static {
              TEST_MAP.put("KEY","初始化默認(rèn)值");
          }
          public static volatile List<Integer> TEST_LIST_INT = new ArrayList<>();
          static {
              TEST_LIST_INT.add(1);
          }
      }

      2)新建個(gè)Controller用于測試這些值

      @RestController
      public class TestController {
      
          @GetMapping("/t1")
          public Map<String, Object> test1() {
              Map<String, Object> result = new HashMap<>();
      
              result.put("string" , Constant.TEST);
              result.put("list" , Constant.TEST_LIST);
              result.put("map" , Constant.TEST_MAP);
              result.put("list_int" , Constant.TEST_LIST_INT);
              result.put("code" , 1);
              return result;
          }
      }

      3)當(dāng)前nacos的配置文件cloud-sm-constant.properties為空

       4)訪問測試路徑localhost:9010/sm/t1,返回為默認(rèn)值

      {
          "code": 1,
          "string": "test",
          "list_int": [
              1
          ],
          "list": [
              "默認(rèn)值"
          ],
          "map": {
              "KEY": "初始化默認(rèn)值"
          }
      }

      5)然后更改nacos的配置文件cloud-sm-constant.properties;

       6)再次訪問測試路徑localhost:9010/sm/t1,返回為nacos中的值

      {
          "code": 1,
          "string": "12351",
          "list_int": [
              1,
              23,
              4
          ],
          "list": [
              "123",
              "sss"
          ],
          "map": {
              "A": 12,
              "B": 432
          }
      }

      4.結(jié)語

      這種實(shí)現(xiàn)方式優(yōu)點(diǎn)如下:

      1)動(dòng)態(tài)刷新配置,不需要重啟即可改變程序中的靜態(tài)常量值

      2)使用簡單,只需在常量類上添加一個(gè)注解

      3)避免在程序中大量使用@Value,@RefreshScope注解

       不足:

      此代碼是個(gè)人業(yè)余時(shí)間的想法,未經(jīng)過生產(chǎn)驗(yàn)證,實(shí)現(xiàn)的數(shù)據(jù)類型暫時(shí)只寫幾個(gè),其余的需要自行拓展

      posted @ 2020-06-18 20:32  若星漢浮云  Views(2748)  Comments(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 午夜精品久久久久久久2023| 玩两个丰满老熟女久久网| 日韩精品人妻av一区二区三区| 国产精品一二二区视在线| 丰满少妇被猛烈进出69影院 | 日韩国产精品无码一区二区三区| 国产亚洲国产亚洲国产亚洲| 影音先锋人妻啪啪av资源网站| 免费av深夜在线观看| 浪潮av色综合久久天堂| 国产精品国产三级国产午| 99精品视频在线观看婷婷| 色狠狠色婷婷丁香五月| 先锋影音男人av资源| 亚洲午夜无码久久久久蜜臀av| 激情六月丁香婷婷四房播| 国产av不卡一区二区| 日本高清在线播放一区二区三区| 国产99视频精品免费视频36| 成人麻豆日韩在无码视频| 亚洲色成人网站www永久下载| 亚洲av成人精品日韩一区| 亚洲天堂av 在线| 亚洲国内精品一区二区| 国产欧美va欧美va在线| 午夜性爽视频男人的天堂| 亚洲久悠悠色悠在线播放| 亚洲AV无码秘?蜜桃蘑菇| 成人区人妻精品一区二蜜臀| 韩国18禁啪啪无遮挡免费| 亚洲 日本 欧洲 欧美 视频| 亚洲中文字幕久久精品码| 欧美乱码伦视频免费| 国产精品久久久久免费观看| 久久亚洲精品亚洲人av| 日韩熟妇中文色在线视频| 中文字幕在线日韩| 正在播放肥臀熟妇在线视频| 亚洲精品成人无限看| 久久精品国产久精国产| 国产成人一区二区三区免费|