<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

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

    2017年4月15日

    在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的海域 閱讀(898) | 評論 (0)編輯 收藏

    Spring默認不允許對類的變量, 也就是靜態變量進行注入操作, 但是在某些場景比如單元測試的@AfterClass要訪問注入對象, 而Junit的這個方法必須是靜態的, 也就產生了悖論;

    解決思路有兩個:

    • 思路1: 想辦法對靜態變量注入, 也就是繞過Spring只能運行非靜態變量才能注入依賴的壁壘
    • 思路2: 想辦法@AfterClass改造為非靜態
      • 實現Junit RunListener, 覆蓋testRunFinished方法, 這里去實現類似@AfterClass的功能, 這個方法是非靜態的
      • 不要用Junit, 改用TestNG, TestNG里的AfterClass是非靜態的
      • 用Spring的TestExecutionListeners, 實現個Listener, 里面也有個類似非靜態的AfterClass的實現, 覆蓋實現就行

    思路2的幾個方法都可以實現, 但是單元測試Runner需要用

    @RunWith(Theories.class)

    而且改用TestNG工程浩大, 只能放棄掉這個思路

    繼續走思路1, 只能去繞過Spring的依賴注入的static壁壘了, 具體代碼如下:

    @Autowired
    private Destination dfsOperationQueue;
    private static Destination dfsOperationQueueStatic; // static version
    @Autowired
    private MessageQueueAPI messageQueueAPI;
    private static MessageQueueAPI messageQueueAPIStatic; // static version


    @PostConstruct
    public void init() {
    dfsOperationQueueStatic = this.dfsOperationQueue;
    messageQueueAPIStatic = this.messageQueueAPI;
    }

    @AfterClass
    public static void afterClass() {
    MessageVO messageVO = messageQueueAPIStatic.removeDestination(dfsOperationQueueStatic);
    System.out.println(messageVO);
    }

    其實就是用了@PostConstruct 來個偷梁換柱而已, 多聲明個靜態成員指向非靜態對象, 兩者其實是一個對象

    posted @ 2017-04-15 10:32 Milo的海域 閱讀(592) | 評論 (0)編輯 收藏

    主站蜘蛛池模板: 久久这里只精品国产免费10| 亚洲精品无码中文久久字幕| 久久免费高清视频| v片免费在线观看| 国产精品免费视频观看拍拍| 4hu四虎免费影院www| 毛片基地看看成人免费| 久久免费99精品国产自在现线| 久久久久久噜噜精品免费直播| 成人免费一区二区三区| 亚洲中文字幕无码久久| 亚洲一区二区无码偷拍| 99久久国产亚洲综合精品| 亚洲最新永久在线观看| 亚洲情a成黄在线观看| 中文字幕亚洲乱码熟女一区二区| 日韩va亚洲va欧洲va国产| 久久综合九九亚洲一区| 久久久久亚洲AV无码永不| 亚洲一级黄色大片| 亚洲日韩国产AV无码无码精品| 国产精品自拍亚洲| 亚洲一区二区三区在线观看网站 | 日韩成全视频观看免费观看高清| 男女交性永久免费视频播放| 亚洲成av人片天堂网老年人| 亚洲精品少妇30p| 亚洲精品在线免费观看视频| 国产色在线|亚洲| 人妻仑刮八A级毛片免费看| 免费网站观看WWW在线观看| 亚洲香蕉免费有线视频| 国产真人无码作爱免费视频| 污污网站18禁在线永久免费观看| 18勿入网站免费永久| 久久99国产综合精品免费| 国产成人免费爽爽爽视频| 在线看片无码永久免费aⅴ| 国产av无码专区亚洲av果冻传媒 | 午夜国产大片免费观看| 亚洲国产精品SSS在线观看AV|