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

          2017年12月8日

          在Spring cloud config出來之前, 自己實現了基于ZK的配置中心, 杜絕了本地properties配置文件, 原理很簡單, 只是重載了PropertyPlaceholderConfigurer的mergeProperties():

          /**
          * 重載合并屬性實現
          * 先加載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;
          }

          這個實現在spring項目里用起來還是挺順手的, 但是近期部分spring-boot項目里發現這種placeholder的實現跟spring boot的@ConfigurationProperties(prefix = "xxx") 不能很好的配合工作,
          也就是屬性沒有被resolve處理, 用@Value的方式確可以讀到, 但是@Value配置起來如果屬性多的話還是挺繁瑣的, 還是傾向用@ConfigurationProperties的prefix, 于是看了下spring boot的文檔發現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).
          不難發現其會檢查Java system propeties里的屬性, 也就是說, 只要把mergerProperties讀到的屬性寫入Java system props里即可, 看了下源碼, 找到個切入點

          /**
          * 重載處理屬性實現
          * 根據選項, 決定是否將合并后的props寫入系統屬性, Spring boot需要
          *
          * @param beanFactoryToProcess
          * @param props 合并后的屬性
          * @throws BeansException
          */
          @Override
          protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException {
          // 原有邏輯
          super.processProperties(beanFactoryToProcess, props);
          // 寫入到系統屬性
          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);
          }
          }
          }
          為避免影響過大, 設置了個開關, 是否寫入系統屬性, 如果是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;
          }

          posted @ 2017-12-08 14:13 Milo的海域 閱讀(903) | 評論 (0)編輯 收藏

          主站蜘蛛池模板: 锦屏县| 囊谦县| 连州市| 松滋市| 酒泉市| 定陶县| 互助| 黎城县| 黄石市| 全南县| 蓬溪县| 丰台区| 伊宁县| 崇文区| 平凉市| 大连市| 溧阳市| 二连浩特市| 合水县| 舟曲县| 金塔县| 株洲市| 巴彦淖尔市| 商丘市| 广平县| 松原市| 咸阳市| 双辽市| 城口县| 新疆| 土默特左旗| 孟连| 汉川市| 台东县| 惠东县| 巩留县| 桦甸市| 泗水县| 昭觉县| 丰都县| 加查县|