<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 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    2015年10月21日

    在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)編輯 收藏

    知道activemq現在已經支持了rest api, 但是官方對這部分的介紹一筆帶過 (http://activemq.apache.org/rest.html),


    通過google居然也沒搜到一些有用的, 比如像刪除一個destination, 都是問的多,然后沒下文. 于是花了一些心思研究了一下:


    首先通過rest api獲取當前版本所有已支持的協議

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


    然后根據json輸出關于removeTopic, removeQueue的mbean實現通過rest api刪除destination的方法, 注意到用GET請求而不是POST,不然會報錯 (官網的例子里用的wget給的靈感, 開始用了POST老報錯)


    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);
        }
    }

    其他的請求,應該都是類似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的海域 閱讀(1437) | 評論 (0)編輯 收藏

    用Spring JMS 的JmsTemplate從消息隊列消費消息時發現,使用了CLIENT_ACKNOWLEDGE模式,消息返回后總是自動被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 就不會出現這個情況,搜了下google,發現果然存在這個問題

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

    同步方式拉取消息,暫時沒找到好的封裝,只能暫時用這?;蛘弑M量用listener, 這個問題暫時標記下,或者誰有更好的解決方案可以comment我

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

    默認的配置有時候點不亮顯示器,且分辨率很低,通過tvservice工具不斷調試,發現下面的參數可以完美匹配了
    修改 /boot/config.txt的下列參數

    disable_overscan=1
    hdmi_force_hotplug
    =1
    hdmi_group
    =1
    hdmi_mode
    =16
    hdmi_drive
    =2
    config_hdmi_boost
    =4
    dtparam
    =audio=on

    posted @ 2016-06-15 09:32 Milo的海域 閱讀(223) | 評論 (0)編輯 收藏

    http://stackoverflow.com/questions/3294423/spring-classpath-prefix-difference



      

    SIMPLE DEFINITION

    The classpath*:conf/appContext.xml simply means that all appContext.xml files under conf folders in all your jars on the classpath will be picked up and joined into one big application context.

    In contrast
    , classpath:conf/appContext.xml will load only one such file the first one found on your classpath.


    <bean id="propertyConfigurer"
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
    <list>
    <value>classpath:*.properties</value>
    <value>classpath*:*.properties</value>
    </list>
    </property>
    </bean>

    posted @ 2016-05-26 14:14 Milo的海域 閱讀(769) | 評論 (0)編輯 收藏

    1. IDEA_JDK (or IDEA_JDK_64) environment variable
    2. jre/ (or jre64/) directory in IDEA home
    3. registry
    4. JDK_HOME environment variable
    5. JAVA_HOME environment variable

    posted @ 2016-05-16 08:49 Milo的海域 閱讀(163) | 評論 (0)編輯 收藏

    java里如何修改console的歷史輸出信息呢?如果是當前行的修改可以簡單想到"\r"的方案,但是如果要修改上一行呢? google了下原來還是有方法的,需要用到ansi的control sequences
    ANSI code

    用java寫了個簡單的例子,例子就是把曾經的output修改為其他字符串并恢復之后的打印,代碼里加了sleep,主要方便理解各種控制序列的含義
            //print some test messages
            System.out.println("1");
            Thread.sleep(
    1000);
            System.out.println(
    "22");
            Thread.sleep(
    1000);
            System.out.println(
    "333");
            Thread.sleep(
    1000);
            System.out.println(
    "4444");
            Thread.sleep(
    1000);

            
    /**
             * modify "333" to "-"
             
    */
            
    // Move up two lines
            int count = 2;
            System.out.print(String.format(
    "\033[%dA", count));
            Thread.sleep(
    1000);
            
    // Erase current line content
            System.out.print("\033[2K");
            Thread.sleep(
    1000);
            
    // update with new content
            System.out.print("-");
            Thread.sleep(
    1000);
            
    // Move down two lines
            System.out.print(String.format("\033[%dB", count));
            Thread.sleep(
    1000);
            
    // Move cursor to left beginning
            System.out.print(String.format("\033[D", count));
            
    // continue print others
            Thread.sleep(1000);
            System.out.println(
    "55555");
            Thread.sleep(
    1000);

    posted @ 2016-04-21 17:06 Milo的海域 閱讀(413) | 評論 (0)編輯 收藏

    1. zookeeper basic/fast paxsos 的形象表述 https://www.douban.com/note/208430424/
    2. 詳細介紹 http://blog.csdn.net/xhh198781/article/details/10949697

    posted @ 2016-03-31 14:06 Milo的海域 閱讀(183) | 評論 (0)編輯 收藏

    server.compression.enabled=true 
    server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain
    server.compression.min-response-size=4096
    第一個參數打開壓縮開關,第二個參數添加json reponse(尤其是為rest api),第三個參數是根據reponse的大小設置啟用壓縮的最小值(默認是2K,自己根據實際情況調整)

    參考
    http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#how-to-enable-http-response-compression

    posted @ 2016-03-29 11:50 Milo的海域 閱讀(1899) | 評論 (0)編輯 收藏

    介紹centos7如何安裝3.0以上的新版本mongodb
    https://docs.mongodb.org/manual/tutorial/install-mongodb-on-red-hat/

    posted @ 2016-03-23 10:14 Milo的海域 閱讀(185) | 評論 (0)編輯 收藏

    1. 默認的3個classloader: BootstrapClassloader (Native實現), ExtClassloader, AppClassloader (Java實現)
    2. 3個加載器并不是真正的父子繼承關系,而是邏輯上的,JVM啟動先創建ExtClassloader instance,然后構造AppClassloader的時候傳入ExtClassloader實例作為parent
            Launcher.ExtClassLoader extcl;
            
    try {
                extcl 
    = Launcher.ExtClassLoader.getExtClassLoader();
            } 
    catch (IOException var10) {
                
    throw new InternalError("Could not create extension class loader", var10);
            }

            
    try {
                
    this.loader = Launcher.AppClassLoader.getAppClassLoader(extcl);
            } 
    catch (IOException var9) {
                
    throw new InternalError("Could not create application class loader", var9);
            }

    關于雙親委派原理: 在加載類的時候,會看看parent有沒有設定,如果設定了 就調用parent.loadClass方法,如果沒設定(==null)也就是parent應該是BootstrapClassloader, 會調用native的findBootstrapClass來加載類,代碼:
                    try {
                        
    if(this.parent != null) {
                            c 
    = this.parent.loadClass(name, false);
                        } 
    else {
                            c 
    = this.findBootstrapClassOrNull(name);
                        }
                    } 
    catch (ClassNotFoundException var10) {
                        ;
                    }

    目的是按照一定優先級別裝載系統的lib,系統ext目錄的lib,以及classpath的lib,防止系統的默認行為或者類的實現被修改。

    3. java 類的動態加載
    Java內置的ClassLoader總會在加載一個Class之前檢查這個Class是否已經被加載過,已經被加載過的Class不會加載第二次。因此要想重新加載Class,我們需要實現自己的ClassLoader。
    另外一個問題是,每個被加載的Class都需要被鏈接(link),這是通過執行ClassLoader.resolve()來實現的,這個方法是 final的,因此無法重寫。Resove()方法不允許一個ClassLoader實例link一個Class兩次,因此,當你需要重新加載一個 Class的時候,你需要重新New一個你自己的ClassLoader實例。

    posted @ 2016-03-16 15:40 Milo的海域 閱讀(315) | 評論 (0)編輯 收藏


    maven-shade-plugin 用來打可執行jar包, 可以把所有依賴的三方庫都包括進來
    exec-maven-plugin 可以執行外部命令, 在項目中對python代碼進行編譯, 配合maven-assembly-plugin來生成package
    maven-assembly-plugin 用來構建項目發行包, 要配合xml配置文件來組織包的結構,基本思路是從build環境copy到outputDirectory
    license-maven-plugin 用來生成項目用到的3方庫的版權匯總 或者其他的一些用法
    maven-dependency-plugin 用來生成項目庫之間的依賴關系
    appassembler-maven-plugin 可以為項目生成優雅的啟動腳本 支持linux/win
    rpm-maven-plugin 用來為項目構建rpm安裝包
    maven-compiler-plugin 指定項目的jdk的編譯兼容版本以及encoding類別

    posted @ 2016-01-26 11:41 Milo的海域 閱讀(262) | 評論 (0)編輯 收藏

    快捷鍵migrating
    定位選中字符串下個匹配的位置
    eclipse: ctrl + k
    idea: ctrl + F3       

    eclipse: ctrl + q
    idea: ctrl + shift + backspace
    回到上一次編輯的位置

    持續更新

    posted @ 2015-11-25 16:46 Milo的海域 閱讀(123) | 評論 (0)編輯 收藏

    發現一個不錯的介紹shell中冒號的用法的文章
    http://codingstandards.iteye.com/blog/1160298

    posted @ 2015-11-09 15:11 Milo的海域 閱讀(244) | 評論 (0)編輯 收藏

    項目用mvn exec:exec指令來啟動server, 工作中需要調式server初始化的過程, 很容易想到mvnDebug, 但是發現設置的斷點都沒有hit, 反復調式多次都是如此,折騰了1個多小時, 突然看到stackoverflow 上有人說exec:exec是獨立進程模式, mvnDebug的一些debug選項都被append到了父進程了. idea設置斷點就然并卵了.

    知道了問題所在解決就容易了, 只要修改pom.xml, 然后直接mvn exec:exec就能正常調式了
                <build>
                    <plugins>
                        <plugin>
                            <groupId>org.codehaus.mojo</groupId>
                            <artifactId>exec-maven-plugin</artifactId>
                            <version>${mvnexec.version}</version>
                            <executions>
                                <execution>
                                    <goals>
                                        <goal>exec</goal>
                                    </goals>
                                </execution>
                            </executions>
                            <configuration>
                                <includeProjectDependencies>true</includeProjectDependencies>
                                <executable>java</executable>
                                <workingDirectory>${basedir}/config/sim</workingDirectory>
                                <classpathScope>runtime</classpathScope>
                                <arguments>
                                    <argument>-agentlib:jdwp
    =transport=dt_socket,server=y,suspend=y,address=4000</argument>
                                    <argument>-classpath</argument>
                                    <classpath/>
                                    <argument>com.ymiao.Main</argument>
                                    <argument>server</argument>
                                    <argument>${basedir}/config/sim/sim.yml</argument>
                                </arguments>
                            </configuration>
                        </plugin>
                    </plugins>
                </build>

    總結就是exec:exec是要獨立一個新進程來執行程序的, exec:java就相反, 其實用mvnDebug + exec:java也是理論可行的

    posted @ 2015-10-21 17:12 Milo的海域 閱讀(832) | 評論 (0)編輯 收藏

    主站蜘蛛池模板: 97热久久免费频精品99| 亚洲另类激情综合偷自拍图| 亚洲精品在线视频观看| 中文字幕无码免费久久| 国产自偷亚洲精品页65页| 春意影院午夜爽爽爽免费| 亚洲AV无码不卡在线观看下载| 亚洲欧美日韩久久精品| 成年女人18级毛片毛片免费| 亚洲三级在线免费观看| 中文字幕无码免费久久99| 国产亚洲精品成人AA片| 午夜精品在线免费观看| 亚洲日韩中文字幕一区| 免费观看男人免费桶女人视频| 亚洲爆乳无码专区www| 国产在线观看免费视频播放器| 国产AV无码专区亚洲AV琪琪| 亚洲AV无码一区二区三区在线观看 | 日韩精品视频免费网址| 亚洲av无码兔费综合| 国产男女猛烈无遮挡免费视频网站| 婷婷国产偷v国产偷v亚洲| 亚洲国产成人精品女人久久久| 五月天婷婷精品免费视频| 国产亚洲精品久久久久秋霞| 最近免费中文字幕MV在线视频3 | 男男黄GAY片免费网站WWW| 亚洲精品NV久久久久久久久久| 久久精品成人免费观看97| 亚洲AV无码国产精品麻豆天美| 99久久99热精品免费观看国产 | 国产亚洲精品a在线观看 | 亚洲精彩视频在线观看| 无码免费午夜福利片在线| 亚洲成av人在线观看网站| 亚洲国产精品成人| 亚洲免费观看视频| 亚洲国产精品美女| 日本特黄特黄刺激大片免费| 国产成人无码精品久久久久免费|