posts - 88, comments - 3, trackbacks - 0, articles - 0
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          Spring boot外部配置-配置中心化

          Posted on 2017-12-08 14:13 Milo的海域 閱讀(903) 評論(0)  編輯  收藏 所屬分類: Java
          在Spring cloud config出來之前, 自己實現(xiàn)了基于ZK的配置中心, 杜絕了本地properties配置文件, 原理很簡單, 只是重載了PropertyPlaceholderConfigurer的mergeProperties():

          /**
          * 重載合并屬性實現(xiàn)
          * 先加載file properties, 然后并入ZK配置中心讀取的properties
          *
          * @return 合并后的屬性集合
          * @throws IOException 異常
          */
          @Override
          protected Properties mergeProperties() throws IOException {
          Properties result = new Properties();
          // 加載父類的配置
          Properties mergeProperties = super.mergeProperties();
          result.putAll(mergeProperties);
          // 加載從zk中讀取到的配置
          Map<String, String> configs = loadZkConfigs();
          result.putAll(configs);
          return result;
          }

          這個實現(xiàn)在spring項目里用起來還是挺順手的, 但是近期部分spring-boot項目里發(fā)現(xiàn)這種placeholder的實現(xiàn)跟spring boot的@ConfigurationProperties(prefix = "xxx") 不能很好的配合工作,
          也就是屬性沒有被resolve處理, 用@Value的方式確可以讀到, 但是@Value配置起來如果屬性多的話還是挺繁瑣的, 還是傾向用@ConfigurationProperties的prefix, 于是看了下spring boot的文檔發(fā)現(xiàn)PropertySource order:
             * Devtools global settings properties on your home directory (~/.spring-boot-devtools.properties when devtools is active).
             * @TestPropertySource annotations on your tests.
             * @SpringBootTest#properties annotation attribute on your tests.
             * Command line arguments.
             * Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property)
             * ServletConfig init parameters.
             * ServletContext init parameters.
             * JNDI attributes from java:comp/env.
             * Java System properties (System.getProperties()).
             * OS environment variables.
             * A RandomValuePropertySource that only has properties in random.*.
             * Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants)
             * Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants)
             * Application properties outside of your packaged jar (application.properties and YAML variants).
             * Application properties packaged inside your jar (application.properties and YAML variants).
             * @PropertySource annotations on your @Configuration classes.
             * Default properties (specified using SpringApplication.setDefaultProperties).
          不難發(fā)現(xiàn)其會檢查Java system propeties里的屬性, 也就是說, 只要把mergerProperties讀到的屬性寫入Java system props里即可, 看了下源碼, 找到個切入點

          /**
          * 重載處理屬性實現(xiàn)
          * 根據(jù)選項, 決定是否將合并后的props寫入系統(tǒng)屬性, Spring boot需要
          *
          * @param beanFactoryToProcess
          * @param props 合并后的屬性
          * @throws BeansException
          */
          @Override
          protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException {
          // 原有邏輯
          super.processProperties(beanFactoryToProcess, props);
          // 寫入到系統(tǒng)屬性
          if (writePropsToSystem) {
          // write all properties to system for spring boot
          Enumeration<?> propertyNames = props.propertyNames();
          while (propertyNames.hasMoreElements()) {
          String propertyName = (String) propertyNames.nextElement();
          String propertyValue = props.getProperty(propertyName);
          System.setProperty(propertyName, propertyValue);
          }
          }
          }
          為避免影響過大, 設置了個開關(guān), 是否寫入系統(tǒng)屬性, 如果是spring boot的項目, 就開啟, 這樣對線上非spring boot項目做到影響最小, 然后spring boot的@ConfigurationProperties完美讀到屬性;

          具體代碼見: org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor

          @Override
          public Object postProcessBeforeInitialization(Object bean, String beanName)
          throws BeansException {
          ConfigurationProperties annotation = AnnotationUtils
          .findAnnotation(bean.getClass(), ConfigurationProperties.class);
          if (annotation != null) {
          postProcessBeforeInitialization(bean, beanName, annotation);
          }
          annotation = this.beans.findFactoryAnnotation(beanName,
          ConfigurationProperties.class);
          if (annotation != null) {
          postProcessBeforeInitialization(bean, beanName, annotation);
          }
          return bean;
          }

          主站蜘蛛池模板: 张家港市| 苏尼特左旗| 吉木乃县| 河津市| 巴南区| 绍兴市| 汉中市| 崇阳县| 金沙县| 潼南县| 中卫市| 高碑店市| 托克托县| 孟州市| 汤阴县| 南城县| 新田县| 牙克石市| 顺义区| 永胜县| 临沂市| 安国市| 威远县| 柏乡县| 吐鲁番市| 沙坪坝区| 宁津县| 富民县| 太原市| 龙口市| 香港 | 广丰县| 安陆市| 朝阳县| 兖州市| 福海县| 阿拉善右旗| 团风县| 天柱县| 会宁县| 磴口县|