<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 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    2016年10月12日

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

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

    這個(gè)實(shí)現(xiàn)在spring項(xiàng)目里用起來(lái)還是挺順手的, 但是近期部分spring-boot項(xiàng)目里發(fā)現(xiàn)這種placeholder的實(shí)現(xiàn)跟spring boot的@ConfigurationProperties(prefix = "xxx") 不能很好的配合工作,
    也就是屬性沒(méi)有被resolve處理, 用@Value的方式確可以讀到, 但是@Value配置起來(lái)如果屬性多的話還是挺繁瑣的, 還是傾向用@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)其會(huì)檢查Java system propeties里的屬性, 也就是說(shuō), 只要把mergerProperties讀到的屬性寫(xiě)入Java system props里即可, 看了下源碼, 找到個(gè)切入點(diǎn)

    /**
    * 重載處理屬性實(shí)現(xiàn)
    * 根據(jù)選項(xiàng), 決定是否將合并后的props寫(xiě)入系統(tǒng)屬性, Spring boot需要
    *
    * @param beanFactoryToProcess
    * @param props 合并后的屬性
    * @throws BeansException
    */
    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException {
    // 原有邏輯
    super.processProperties(beanFactoryToProcess, props);
    // 寫(xiě)入到系統(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ò)大, 設(shè)置了個(gè)開(kāi)關(guān), 是否寫(xiě)入系統(tǒng)屬性, 如果是spring boot的項(xiàng)目, 就開(kāi)啟, 這樣對(duì)線上非spring boot項(xiàng)目做到影響最小, 然后spring boot的@ConfigurationProperties完美讀到屬性;

    具體代碼見(jiàn): 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) | 評(píng)論 (0)編輯 收藏

    Spring默認(rèn)不允許對(duì)類(lèi)的變量, 也就是靜態(tài)變量進(jìn)行注入操作, 但是在某些場(chǎng)景比如單元測(cè)試的@AfterClass要訪問(wèn)注入對(duì)象, 而Junit的這個(gè)方法必須是靜態(tài)的, 也就產(chǎn)生了悖論;

    解決思路有兩個(gè):

    • 思路1: 想辦法對(duì)靜態(tài)變量注入, 也就是繞過(guò)Spring只能運(yùn)行非靜態(tài)變量才能注入依賴的壁壘
    • 思路2: 想辦法@AfterClass改造為非靜態(tài)
      • 實(shí)現(xiàn)Junit RunListener, 覆蓋testRunFinished方法, 這里去實(shí)現(xiàn)類(lèi)似@AfterClass的功能, 這個(gè)方法是非靜態(tài)的
      • 不要用Junit, 改用TestNG, TestNG里的AfterClass是非靜態(tài)的
      • 用Spring的TestExecutionListeners, 實(shí)現(xiàn)個(gè)Listener, 里面也有個(gè)類(lèi)似非靜態(tài)的AfterClass的實(shí)現(xiàn), 覆蓋實(shí)現(xiàn)就行

    思路2的幾個(gè)方法都可以實(shí)現(xiàn), 但是單元測(cè)試Runner需要用

    @RunWith(Theories.class)

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

    繼續(xù)走思路1, 只能去繞過(guò)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);
    }

    其實(shí)就是用了@PostConstruct 來(lái)個(gè)偷梁換柱而已, 多聲明個(gè)靜態(tài)成員指向非靜態(tài)對(duì)象, 兩者其實(shí)是一個(gè)對(duì)象

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

    知道activemq現(xiàn)在已經(jīng)支持了rest api, 但是官方對(duì)這部分的介紹一筆帶過(guò) (http://activemq.apache.org/rest.html),


    通過(guò)google居然也沒(méi)搜到一些有用的, 比如像刪除一個(gè)destination, 都是問(wèn)的多,然后沒(méi)下文. 于是花了一些心思研究了一下:


    首先通過(guò)rest api獲取當(dāng)前版本所有已支持的協(xié)議

        http://172.30.43.206:8161/api/jolokia/list


    然后根據(jù)json輸出關(guān)于removeTopic, removeQueue的mbean實(shí)現(xiàn)通過(guò)rest api刪除destination的方法, 注意到用GET請(qǐng)求而不是POST,不然會(huì)報(bào)錯(cuò) (官網(wǎng)的例子里用的wget給的靈感, 開(kāi)始用了POST老報(bào)錯(cuò))


    import org.apache.activemq.command.ActiveMQQueue;
    import org.apache.activemq.command.ActiveMQTopic;
    import org.apache.http.auth.AuthScope;
    import org.apache.http.auth.UsernamePasswordCredentials;
    import org.apache.http.impl.client.BasicCredentialsProvider;
    import org.apache.http.impl.client.DefaultHttpClient;
    import org.springframework.http.HttpEntity;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpMethod;
    import org.springframework.http.MediaType;
    import org.springframework.http.ResponseEntity;
    import org.springframework.http.client.ClientHttpRequestFactory;
    import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
    import org.springframework.web.client.RestTemplate;

    import javax.jms.Destination;
    import javax.jms.JMSException;
    import java.util.Arrays;


    public class MessageQueueAdmin {
        
    private static final RestTemplate restTemplate = getRestTemplate("admin""admin");

        
    private static String brokerHost = "172.30.43.206";
        
    private static String adminConsolePort = "8161";
        
    private static String protocol = "http";

        
    public static void removeDestination(Destination destination) throws JMSException {
            String destName, destType;
            
    if (destination instanceof ActiveMQQueue) {
                destName 
    = ((ActiveMQQueue) destination).getQueueName();
                destType 
    = "Queue";
            } 
    else {
                destName 
    = ((ActiveMQTopic) destination).getTopicName();
                destType 
    = "Topic";
            }

            
    // build urls
            String url = String.format("%s://%s:%s/api/jolokia/exec/org.apache.activemq:" +
                    
    "brokerName=localhost,type=Broker/remove%s/%s", protocol, brokerHost, adminConsolePort, destType, destName);
            System.out.println(url);
            
    // do operation
            HttpHeaders headers = new HttpHeaders();
            headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
            HttpEntity
    <String> entity = new HttpEntity<String>("parameters", headers);
            ResponseEntity response 
    = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
            System.out.println(response.getBody());
        }

        
    public static void main(String[] args) throws JMSException {
            ActiveMQTopic topic 
    = new ActiveMQTopic("test-activemq-topic");
            removeDestination(topic);
        }


        
    private static RestTemplate getRestTemplate(String user, String password) {
            DefaultHttpClient httpClient 
    = new DefaultHttpClient();
            BasicCredentialsProvider credentialsProvider 
    = new BasicCredentialsProvider();
            credentialsProvider.setCredentials(AuthScope.ANY, 
    new UsernamePasswordCredentials(user, password));
            httpClient.setCredentialsProvider(credentialsProvider);
            ClientHttpRequestFactory rf 
    = new HttpComponentsClientHttpRequestFactory(httpClient);

            
    return new RestTemplate(rf);
        }
    }

    其他的請(qǐng)求,應(yīng)該都是類(lèi)似jolokia的exec get request的格式:


    https://jolokia.org/reference/html/protocol.html#exec


    <base url>/exec/<mbean name>/<operation name>/<arg1>/<arg2>/.

    posted @ 2016-10-22 17:31 Milo的海域 閱讀(1436) | 評(píng)論 (0)編輯 收藏

    用Spring JMS 的JmsTemplate從消息隊(duì)列消費(fèi)消息時(shí)發(fā)現(xiàn),使用了CLIENT_ACKNOWLEDGE模式,消息返回后總是自動(dòng)被ack,也就是被broker "Dequeued"

        protected Message doReceive(Session session, MessageConsumer consumer) throws JMSException {
            
    try {
                
    // Use transaction timeout (if available).
                long timeout = getReceiveTimeout();
                JmsResourceHolder resourceHolder 
    =
                        (JmsResourceHolder) TransactionSynchronizationManager.getResource(getConnectionFactory());
                
    if (resourceHolder != null && resourceHolder.hasTimeout()) {
                    timeout 
    = Math.min(timeout, resourceHolder.getTimeToLiveInMillis());
                }
                Message message 
    = doReceive(consumer, timeout);
                
    if (session.getTransacted()) {
                    
    // Commit necessary - but avoid commit call within a JTA transaction.
                    if (isSessionLocallyTransacted(session)) {
                        
    // Transacted session created by this template -> commit.
                        JmsUtils.commitIfNecessary(session);
                    }
                }
                
    else if (isClientAcknowledge(session)) {
                    
    // Manually acknowledge message, if any.
                    if (message != null) {
                        message.acknowledge();
                    }
                }
                
    return message;
            }
            
    finally {
                JmsUtils.closeMessageConsumer(consumer);
            }
        }

    但是使用異步listener 就不會(huì)出現(xiàn)這個(gè)情況,搜了下google,發(fā)現(xiàn)果然存在這個(gè)問(wèn)題

         https://jira.spring.io/browse/SPR-12995
         https://jira.spring.io/browse/SPR-13255
         http://louisling.iteye.com/blog/241073

    同步方式拉取消息,暫時(shí)沒(méi)找到好的封裝,只能暫時(shí)用這。或者盡量用listener, 這個(gè)問(wèn)題暫時(shí)標(biāo)記下,或者誰(shuí)有更好的解決方案可以comment我

    posted @ 2016-10-12 16:32 Milo的海域 閱讀(1537) | 評(píng)論 (0)編輯 收藏

    主站蜘蛛池模板: 国产人在线成免费视频| 国产精品成人69XXX免费视频| 亚洲国产成+人+综合| 亚洲视频免费在线播放| 精品亚洲综合在线第一区| 久久久久一级精品亚洲国产成人综合AV区 | 亚洲精品人成无码中文毛片| 国产美女无遮挡免费网站| 永久在线毛片免费观看| 曰皮全部过程视频免费国产30分钟| 成年女人看片免费视频播放器| 99re6免费视频| 久久国产乱子伦免费精品| 久久99国产综合精品免费| 免费在线观看h片| 无码日韩精品一区二区免费| 中文字幕亚洲精品| 久久精品国产亚洲AV麻豆不卡 | 无码中文字幕av免费放| 在线观看免费人成视频色9| 亚洲免费网站观看视频| 四虎影视www四虎免费| 免费a级毛片在线观看| 亚洲中文字幕伊人久久无码| 中文字幕人成人乱码亚洲电影| 国产精品亚洲A∨天堂不卡| 亚洲AV成人片色在线观看| 亚洲av产在线精品亚洲第一站| 亚洲成AV人片高潮喷水| jizzjizz亚洲日本少妇| 黄人成a动漫片免费网站| 一区二区三区免费视频观看| 日韩a级无码免费视频| 久草视频免费在线| 国产男女爽爽爽爽爽免费视频| 无码国产精品一区二区免费式直播| 日韩成人在线免费视频| 亚洲午夜福利精品久久| 亚洲精品亚洲人成在线麻豆| 亚洲H在线播放在线观看H| 真人无码作爱免费视频|