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

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

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

    云自無心水自閑

    天平山上白云泉,云自無心水自閑。何必奔沖山下去,更添波浪向人間!
    posts - 288, comments - 524, trackbacks - 0, articles - 6
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    2014年2月14日

    1. java zip 多個(gè)文件時(shí),如果先添加了一個(gè)excel文件,然后再想添加其他的文件時(shí)會(huì)出現(xiàn) steam is closed的錯(cuò)誤。這是因?yàn)閣ork.write(outputSteam)后,出調(diào)用outputSteam.close(),關(guān)閉輸出流。
    解決方法:
    將原來的程序:
                ZipEntry entry = new ZipEntry( "file3.txt" );
                zos.putNextEntry( entry );
                workbook.write( zos );
                zos.closeEntry();
    改為:
                ZipEntry entry = new ZipEntry( "file3.txt" );
                zos.putNextEntry( entry );
                workbook.write( new NonCloseableOutputStream( zos ) );
                zos.closeEntry();

    其中 NonCloseableOutputStream 定義如下:
    public class NonCloseableOutputStream extends java.io.FilterOutputStream {
        public NonCloseableOutputStream(OutputStream out) {
            super(out);
        }
        @Override public void close() throws IOException {
            flush();
        }
    }



    2. 使用binary使得mysql區(qū)分大小寫
    select * from table1 where binary field1 = 'abc';

    posted @ 2017-08-09 19:52 云自無心水自閑 閱讀(428) | 評(píng)論 (0)編輯 收藏

    https://notepad-plus-plus.org/community/topic/13661/plugin-manager-x64-available-submit-your-plugins

    posted @ 2017-06-26 09:33 云自無心水自閑 閱讀(396) | 評(píng)論 (0)編輯 收藏

    move Git Server to a new IP/URL:

    you can just edit 
    .git/config and change the URLs there

    也可以在git視圖中,右鍵點(diǎn)擊項(xiàng)目,選擇屬性,然后修改url中的地址

    posted @ 2017-06-15 08:40 云自無心水自閑 閱讀(320) | 評(píng)論 (0)編輯 收藏

    autohotkey
    listary
    cmder可以split screen,在一個(gè)窗口中同時(shí)運(yùn)行數(shù)個(gè)cmd

    posted @ 2017-05-24 07:13 云自無心水自閑 閱讀(17853) | 評(píng)論 (0)編輯 收藏

    官網(wǎng)地址:autohotkey.com

    ; fill password
    ^Numpad2::
    Send, root{tab}root{enter}
    Return
    ^Numpad3::
    IfWinExist, ahk_exe OUTLOOK.EXE
    {
        WinActivate ahk_exe OUTLOOK.EXE ; Automatically uses the window found above.
        ; WinMaximize  ; same
        ;Send, Some text.{Enter}
    msgbox Outlook is running.
    }
    Return

    posted @ 2017-03-08 13:06 云自無心水自閑 閱讀(368) | 評(píng)論 (0)編輯 收藏

    <html>
    <head>
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
        <script>
            window.onload = function () {
                var app = new Vue({
                    el: '#app',
                    data: {
                        message: 'Hello Vue!'
                    }
                });
            }    
        </script>
    </head>

    <body>
        <div id="app">
          {{ message }}
        </div>
    </body>
    </html>

    posted @ 2017-02-09 07:41 云自無心水自閑 閱讀(402) | 評(píng)論 (0)編輯 收藏


    String[] splits=someString.split("a,b,c,d", ",");
    logger.debug( "array: {}", (Object) splits );

    這里要注意的就是要把數(shù)組的數(shù)據(jù)類型強(qiáng)制轉(zhuǎn)換為Object 

    posted @ 2016-12-29 11:51 云自無心水自閑 閱讀(1619) | 評(píng)論 (0)編輯 收藏

    在windows環(huán)境中,可以用如下方法重置root密碼

    1、先停止mysql數(shù)據(jù)庫

    2、保存密碼重置sql文件
         5.7.6(包括)以后的版本:ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass';
         5.7.5(包括)以前的版本:SET PASSWORD FOR 'root'@'localhost' = PASSWORD('MyNewPass');
    假設(shè)保存到文件: c:\reset.txt

    3、以管理員身份打開命令行窗口,運(yùn)行
    C:\> cd "C:\Program Files\MySQL\MySQL Server 5.5\bin"
    C:\> mysqld --init-file=C:\reset.txt

    4、啟動(dòng)后,還不能馬上用新密碼連接數(shù)據(jù)庫,需要重啟mysql數(shù)據(jù)庫

    posted @ 2016-12-21 07:12 云自無心水自閑 閱讀(370) | 評(píng)論 (0)編輯 收藏

    This is a general step that happens when m2e/m2eclipse (Maven integration for Eclipse) is installed, whether projects are actively using it or not.
    這是因?yàn)閙2eclipse(maven插件)要在啟動(dòng)時(shí)需要進(jìn)行的一個(gè)步驟。

    This step can be disabled through the Eclipse preferences: Window / Preferences / Maven / "Download repository index updates on startup". This option is on the main "Maven" preference page (not a child page). Just uncheck the box to prevent this from happening.
    我們可以停止這個(gè)動(dòng)作。方法:Windows -> Preferences -> Maven 取消勾選 Download repository index updates on startup

    posted @ 2016-11-29 08:38 云自無心水自閑 閱讀(1310) | 評(píng)論 (0)編輯 收藏

    有好幾個(gè)java library都可以實(shí)現(xiàn)這個(gè)功能,但是從pdf提取文本的一個(gè)問題是,提取出來的文本沒有固定的順序,不容易比較好的還原其格式。

    我的做法是使用pdfclown來進(jìn)行這項(xiàng)工作。官方網(wǎng)站是:https://pdfclown.org/ 先下載其最新版本。
    參考其示例代碼:https://pdfclown.org/2010/01/02/upcoming-0-0-8-whats-going-to-be-new/#more-30

    使用這段代碼,我們不僅可以得到文本的字符串,還能得到文本的頁數(shù)和相對(duì)坐標(biāo)。
    我的思路是先把所有文本的字符串和坐標(biāo)提取出來。然后排序,排序的順序是縱坐標(biāo),然后橫坐標(biāo)。
    這樣排序完畢后,就能比較好的解決文本格式問題。

    posted @ 2016-11-28 11:03 云自無心水自閑 閱讀(385) | 評(píng)論 (0)編輯 收藏


    1, 先定義一個(gè)input, 做為datepicker的容器。
    <input type='text' class="form-control" id="dateTo" name="dateTo" required/>

    2, 在后面加上glyphicon, 注意關(guān)鍵是label 中的for的id需要是前面定義的容器的id, 這樣點(diǎn)擊glyphicon的時(shí)候就會(huì)觸發(fā)彈出日期選擇框。
    <label for="dateTo" class="input-group-addon"><span class="glyphicon glyphicon-time"></span></label>

    posted @ 2016-10-10 19:57 云自無心水自閑 閱讀(219) | 評(píng)論 (0)編輯 收藏

    在日志文件中看到這個(gè)錯(cuò)誤信息
    Cause: java.sql.SQLException: #HY000

    后來才知道這是因?yàn)閿?shù)據(jù)庫中有個(gè)別字段要求不能為空, 但是insert語句中沒有提供數(shù)據(jù),造成了這個(gè)錯(cuò)誤。

    關(guān)鍵是錯(cuò)誤信息不明確直觀,不容易知道是這個(gè)原因


    posted @ 2016-09-28 13:13 云自無心水自閑 閱讀(1067) | 評(píng)論 (0)編輯 收藏

        public void afterJFinalStart(){
            Configuration config = FreeMarkerRender.getConfiguration();
            config.setTemplateUpdateDelayMilliseconds( 2 );
            config.setAPIBuiltinEnabled( true );
        }

    posted @ 2016-09-21 14:02 云自無心水自閑 閱讀(239) | 評(píng)論 (0)編輯 收藏


    中文版地址  https://angular.cn/

    posted @ 2016-09-16 13:13 云自無心水自閑 閱讀(2108) | 評(píng)論 (0)編輯 收藏

    1, call ##002# to cancel "call diversion"

    2, call 121600, choose option "2" to cancel "Active call catcher"

    posted @ 2016-08-25 12:58 云自無心水自閑 閱讀(154) | 評(píng)論 (0)編輯 收藏

    1. 格式化XML的插件
    可以安裝“XML Tools", 安裝完畢后,選擇 插件->XML Tools->Pretty Print(XML Only - with line breaks)

    2. 格式化JSON的插件
    可以安裝”JSON Viewer", 安裝完畢后,選擇 插件->JSON Viewer->Format JSON

    3. 格式化SQL的插件
    可以安裝“Poor man's T-Sql Formatter", 選擇 插件->Poor man's T-Sql Formatter->Format T-Sql Code

    posted @ 2016-08-12 15:14 云自無心水自閑 閱讀(1052) | 評(píng)論 (0)編輯 收藏

     
    使用的工具

    1. Apache HttpClient
    2. Firefox + FireBug
    3. Burp Suite ( https://portswigger.net/burp ) + Firefox FoxyProxy

    Firefox + FireBug 主要用于查看渲染出的頁面中的信息(比如:表單項(xiàng)的名稱,節(jié)點(diǎn)ID等等)
    Burp Suite 主要用于動(dòng)態(tài)攔截頁面的交互,查看Ajax的調(diào)用。
    HttpClient 用于最后程序的編制。搞清楚了網(wǎng)頁交互的過程,就可以自主決定程序需要包含的內(nèi)容。
    在實(shí)際網(wǎng)頁中,可能需要點(diǎn)開數(shù)級(jí)菜單,才能最后看到需要的內(nèi)容。
    但是在程序中,可以直接跳到最后一步。

    posted @ 2016-06-05 19:00 云自無心水自閑 閱讀(198) | 評(píng)論 (0)編輯 收藏

    1. 表格文字右對(duì)齊 
     <table>
    <tr>
        <td><p style="text-align:right;margin:0;padding:0">文字右對(duì)齊</p></td>
        <td>文字左對(duì)齊</td>
    </tr>
    </table>

    2. 表格邊緣的margin 需要在表格外再套一個(gè)div
    <div style="margin:10px">
        <table>
        ......
        </table>
    </div>

    3. btn-toolbar class can put a margin between 2 "pull-right" buttons
            <div class="row">
                <div class="col-md-2"></div>
                <div class="col-md-8 btn-toolbar">
                    <input type="submit" class="btn btn-warning pull-right" value="Submit">
                    <input type="button" id="profilePassBackBtn" class="btn btn-info pull-right" value="Back">
                </div>
                <div class="col-md-2">
                </div>
            </div>

    posted @ 2016-05-31 11:39 云自無心水自閑 閱讀(378) | 評(píng)論 (0)編輯 收藏

     AngularJS 2.0 已經(jīng)發(fā)布了Beta版本,相信正式版不久以后就會(huì)發(fā)布了。

    下面是官網(wǎng)上的新功能介紹:

    1. 更快更高效。AngularJS 2 將會(huì)比 AnuglarJS 1 快很多。因?yàn)樗鼤?huì)支持:從遠(yuǎn)程胳快速加載、離線編譯以便于更快啟動(dòng)、以及超快的變動(dòng)檢測和為使?jié)L動(dòng)更平滑的視圖緩存等等。

    2. 更加簡單清晰。語法將會(huì)顯得更加自然,易于編寫

    3. 跨越平臺(tái)。無論是臺(tái)式機(jī)、手機(jī)瀏覽器、安卓、IOS平臺(tái),AngularJS都能提供相應(yīng)的支持。

    4. 無縫從 AngularJS 1 升級(jí)到 2

    5. 簡便的開發(fā)。支持各種開發(fā)語言,ES5, TypeScript, Dart

    6. 全面完備的路由。 方便地映射URL到應(yīng)用組件,并提供多種高級(jí)功能,比如:嵌套和鄰接路由,支持卡片棧導(dǎo)航、動(dòng)畫過渡、手機(jī)用戶延遲加載等等

    7. 依賴注入。

    8. 舊瀏覽器的良好支持

    9. 動(dòng)畫效果 (仍在開發(fā)中)

    10. 國際化支持(仍在開發(fā)中)

    posted @ 2016-04-18 20:09 云自無心水自閑 閱讀(265) | 評(píng)論 (0)編輯 收藏

    1. Go to web project properties.
    2. Deployment Assembly (Left).
    3. Add > Select project > Select your lib project > Check "Assemble projects into the WEB-INF/lib folder of the web application" if not checked > Finish.

    posted @ 2016-04-13 10:35 云自無心水自閑 閱讀(171) | 評(píng)論 (0)編輯 收藏

     使用酷狗就可以轉(zhuǎn)換。
    右鍵點(diǎn)擊歌曲 ,工具,格式轉(zhuǎn)換。
    唯一要注意的是要先登錄。

    posted @ 2016-03-17 20:20 云自無心水自閑 閱讀(1595) | 評(píng)論 (0)編輯 收藏

    今天把commons dbcp 和 pool都升級(jí)到2.x, 結(jié)果發(fā)現(xiàn)不能正常的工作,卡在new BasicDataSource()上了.
    后來才發(fā)現(xiàn)原因是因?yàn)闆]有加入commons-logging的jar文件

    幾個(gè)注意點(diǎn):
    1. commons dbcp2.x 和 commons pool需要同時(shí)升到2.x
    2. dbcp 2.x要運(yùn)行在java 7以上 
    3. mysql connector要5.1.11以上
    4. 需要有commons-logging的包,我使用的是slf4j, 就需要加一個(gè)jcl-over-slf4j

    posted @ 2016-02-09 11:44 云自無心水自閑 閱讀(615) | 評(píng)論 (0)編輯 收藏

    Error
    com.jcraft.jsch.JSchException: The cipher 'aes256-cbc' is required, but it is not available.
    or
    Caused by: java.security.InvalidKeyException: Illegal key size


    posted @ 2016-02-05 13:51 云自無心水自閑 閱讀(270) | 評(píng)論 (0)編輯 收藏


    我在網(wǎng)上搜索了一下如何使用Selenium下載文件,其中確實(shí)有幾篇文件介紹了實(shí)現(xiàn)的方法。
    但是其主要思想都是使用httpClient或者URL獲得InputStream, 然后保存到文件中。
    但是,其中的問題是用戶登錄的Session不能維持。

    我發(fā)現(xiàn)了一個(gè)簡單的方法。
    直接使用WebDriver.get, 示例如下:

    webDriver.get("https://website.com/login");
    WebElement element = driver.findElement( By.id( "userID" ) );
    element.sendKeys( "user01" );

    element = driver.findElement( By.id( "passwd" ) );
    element.sendKeys( "password" );

    element = driver.findElement( By.name( "Login" ) );
    element.submit();

    webDriver.get("https://website.cm/download.do?start=xx&end=yy");
    String source = webDriver.getPageSource();

    這個(gè)source就是我們想保存的要下載的內(nèi)容。
    只要把這個(gè)String寫到一個(gè)文件中,就實(shí)現(xiàn)了文件下載的目的

    posted @ 2016-01-28 18:06 云自無心水自閑 閱讀(470) | 評(píng)論 (0)編輯 收藏

         摘要: 在我的上一篇文章中介紹了如何進(jìn)行GPG加密解密。
    加密解密的基本操作流程是,用戶使用公鑰對(duì)明文進(jìn)行加密,解密方使用私鑰對(duì)密文進(jìn)行解密。

    在實(shí)際應(yīng)用中,除了加密保證文本內(nèi)容不泄露外,同時(shí)還要考慮能夠驗(yàn)證密文發(fā)送方的身份,比較普遍使用的方法就是簽名。
    本文主要對(duì)具體的方法進(jìn)行介紹并附上源代碼。  閱讀全文

    posted @ 2015-12-11 21:40 云自無心水自閑 閱讀(1268) | 評(píng)論 (0)編輯 收藏

    Java程序中訪問擁有全部讀寫權(quán)限的目錄相對(duì)比較簡單,和普通的目錄沒有什么差別。
    但是要訪問一個(gè)需要用戶和密碼驗(yàn)證的目錄就需要一點(diǎn)點(diǎn)小技巧了。
    這里介紹一個(gè)開源的庫能夠比較容易的實(shí)現(xiàn)這一需求。
    1。 下載庫文件:
     https://jcifs.samba.org/
    下載的zip文件中, 不僅包含了jar文件,還有文檔和示例。

    2。拷貝jcif-1.3.18.jar到類路徑中。

    3。代碼示例:
     1     String user = "your_user_name";
     2     String pass ="your_pass_word";
     3 
     4     String sharedFolder="shared";
     5     String path="smb://ip_address/"+sharedFolder+"/test.txt";
     6     NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("",user, pass);
     7     SmbFile smbFile = new SmbFile(path,auth);
     8     SmbFileOutputStream smbfos = new SmbFileOutputStream(smbFile);
     9     smbfos.write("testing.and writing to a file".getBytes());
    10     System.out.println("completed nice !");
    說明: 如果有一個(gè)共享目錄,比如: \\192.168.1.2\testdir\
    那么smb的路徑就是:smb://192.168.1.2/testdir/
    NtlmPasswordAuthentication需要三個(gè)參數(shù), 第一個(gè)是名,沒有的話,填null, 第二個(gè)是用戶名,第三個(gè)是密碼

    得到SmbFile之后,操作就和java.io.File基本一樣了。
    另外還有一些功能比如:
    SmbFile.copyTo
    SmbFile.renameTo
    等等

    posted @ 2015-11-20 14:03 云自無心水自閑 閱讀(12984) | 評(píng)論 (0)編輯 收藏

    先將my.default.ini改名為my.ini放到bin目錄
    命令行執(zhí)行: mysqld --initialize --user=mysql --console
    先執(zhí)行以上命令, 生成庫. 注意有個(gè)臨時(shí)密碼, 要記下來.

    安裝服務(wù):mysqld.exe --install MySql5.7 --defaults-file=c:\mysql\mysql5.7\my.ini

    然后啟動(dòng)服務(wù). 
    然后再命令行:
    mysql -uroot -p
    輸入密碼,
    再輸入: 
    set password = password('root')
    改密碼成功, 然后就可以操作了.

    posted @ 2015-11-09 15:25 云自無心水自閑 閱讀(736) | 評(píng)論 (0)編輯 收藏

    如果只是在beforeSubmit()中 調(diào)用$('#fieldname').val(2)是不能成功修改表單的值的。
    因?yàn)榇藭r(shí)ajaxForm已經(jīng)把表單中所有的內(nèi)容存儲(chǔ)在arr之中了。

        $('#form1').ajaxForm({
            beforeSubmit: function(arr){
                for ( var i = 0; i < arr.length; i ++ ) {
                    if ( arr[i].name == "fieldName1" ) {
                        arr[i].value = '新的值';
                    }
                }
            }
        });
    需要使用這種方式進(jìn)行修改。

    posted @ 2015-11-02 19:13 云自無心水自閑 閱讀(1218) | 評(píng)論 (0)編輯 收藏

    今天在運(yùn)行myeclipse的時(shí)候,突然報(bào)nullPointerException.

    具體的錯(cuò)誤信息如下:

    Message: Errors running builder ‘DeploymentBuilder’ on project XXX’.
    Exception Stack Trace
    java.lang.NullPointerException

    解決方法:

    1. Shut down the workspace.

    2. Delete the file com.genuitec.eclipse.ast.deploy.core.prefs which is located at <workspace dir>/.metadata/.plugins/org.eclipse.core.runtime/.settings/com.genuitec.eclipse.ast.deploy.core.prefs

    3. Start the IDE.

    posted @ 2015-10-21 09:21 云自無心水自閑 閱讀(364) | 評(píng)論 (0)編輯 收藏

     
    ipconfig /flushdns
    ipconfig /registerdns
    netsh winsock reset

    重新啟動(dòng)電腦。

    posted @ 2015-10-13 16:31 云自無心水自閑 閱讀(1787) | 評(píng)論 (0)編輯 收藏

    今天下載了Apache James 3.0 Beta 5, 文件名:james-server-app-3.0.0-beta5-20150627.102412-1076-app.zip
    解壓,運(yùn)行run.bat

    然后,注冊(cè)domain
    james-cli --host localhost adddomain example.com
    添加用戶
    james-cli.bat --host localhost adduser test@example.com password

    然后測試發(fā)送郵件,客戶端顯示發(fā)送成功,但是james服務(wù)器報(bào)錯(cuò),找不到MimeConfig的無參數(shù)構(gòu)造函數(shù)。
    解決方法:
    使用舊的mime4j的jar包替換james 3.0 beta5中自帶的最新包。
    beta5中自帶的是0.8.0版,apache網(wǎng)站中可以下載到0.7.2
    下載apache-mime4j-0.7.2-bin.zip, 將其中的apache-mime4j-core-0.7.2.jar, apache-mime4j-dom-0.7.2.jar復(fù)制到j(luò)ames\lib目錄,
    并將其更名覆蓋原有的
    apache-mime4j-core-0.8.0-20150617.024907-738.jar
    apache-mime4j-dom-0.8.0-20150617.024927-735.jar
    重新啟動(dòng)james, 發(fā)送郵件, 成功。

    posted @ 2015-10-08 08:45 云自無心水自閑 閱讀(3277) | 評(píng)論 (0)編輯 收藏

         摘要: 解壓/生成有密碼保護(hù)的壓縮文件, 研發(fā)過程中,作者研究了壓縮文件格式文檔: http://www.pkware.com/documents/casestudies/APPNOTE.TXT,并且參考了7-zip的實(shí)現(xiàn)。
      閱讀全文

    posted @ 2015-08-19 10:16 云自無心水自閑 閱讀(9954) | 評(píng)論 (0)編輯 收藏

         摘要: 花了兩天時(shí)間終于把windows10安裝好了,以下是我的一些個(gè)人的體會(huì)
      閱讀全文

    posted @ 2015-08-03 18:56 云自無心水自閑 閱讀(6251) | 評(píng)論 (0)編輯 收藏

    在JfinalConfig的繼承類中,
    configConstant() 需要設(shè)置me.setDevMode(true);

    1. 只有在DevMode下,才能禁止freeMarker的緩存。
    Configuration config = FreeMarkerRender.getConfiguration();
    config.setTemplateUpdateDelayMilliseconds(0);
    才會(huì)生效


    2. 這時(shí)才會(huì)有JFinal Action Report日志輸出

    posted @ 2015-07-24 19:58 云自無心水自閑 閱讀(416) | 評(píng)論 (0)編輯 收藏

    本文將簡單介紹如何使用PowerMock和Mockito來mock
    1. 構(gòu)造函數(shù)
    2. 靜態(tài)函數(shù)
    3. 枚舉實(shí)現(xiàn)的單例
    4. 選擇參數(shù)值做為函數(shù)的返回值
    5. 在調(diào)用mock出來的方法中,改變方法參數(shù)的值

    一點(diǎn)簡要說明:Mockito其實(shí)已經(jīng)可以滿足大部分的需求,但是它的實(shí)現(xiàn)機(jī)制是使用cglib來動(dòng)態(tài)創(chuàng)建接口的類的實(shí)例。但是這種實(shí)現(xiàn)方式不能用于構(gòu)造函數(shù)和靜態(tài)函數(shù),因?yàn)槟切枰褂妙惖淖止?jié)碼(比如使用javassist). 所以我們才需要結(jié)合使用PowerMock.

    1. mock構(gòu)造函數(shù), 如果有代碼沒有使用DI注入依賴實(shí)例,在單元測試中可以使用PowerMock來模擬創(chuàng)建對(duì)象。
    注意的開始兩行的2個(gè)注解 @RunWith 和 @PrepareForTest
    @RunWith比較簡單,后面始終是PowerMockRunner.class
    @PrepareForText后面需要加的是調(diào)用構(gòu)造函數(shù)的類名,而不是有構(gòu)造函數(shù)的類本身。
    在下面的例子中,我們要測試的類是:Helper, 在Helper類中調(diào)用了Somthing類的構(gòu)造函數(shù)來創(chuàng)建實(shí)例。
    @RunWith(PowerMockRunner.class)
    @PrepareForTest(Helper.
    class)
    public class HelperTest {
      @Mock
      
    private Something mockSomething;
          
      @InjectMocks
      
    private Helper helper;
          
      @Test
      
    public void doSomething() throws Exception {
          String argument 
    = "arg";
              
          PowerMockito.whenNew(Something.
    class).withArguments(argument).thenReturn(mockSomething);
             
          // 調(diào)用需要測試方法
          helper.doSomething(argument);
             
          // 進(jìn)行驗(yàn)證
          verify(mockSomething).doIt();
      }
    }


    public class Helper {
      public void doSomething(String arg) {
          Something something = new Something(arg);
          something.doit();
      }
    }


    2,mock 靜態(tài)函數(shù), 單例模式就是一個(gè)典型的會(huì)調(diào)用靜態(tài)函數(shù)的例子。 注意要點(diǎn)與mock構(gòu)造函數(shù)相同。
    class ClassWithStatics {
      
    public static String getString() {
        
    return "String";
      }

      
    public static int getInt() {
        
    return 1;
      }
    }

    @RunWith(PowerMockRunner.
    class)
    @PrepareForTest(ClassWithStatics.
    class)
    public class StubJustOneStatic {
      @Test
      
    public void test() {
        PowerMockito.mockStatic(ClassWithStatics.
    class);

        when(ClassWithStatics.getString()).thenReturn(
    "Hello!");

        System.out.println(
    "String: " + ClassWithStatics.getString());
        System.out.println(
    "Int: " + ClassWithStatics.getInt());
      }
    }

    3。mock枚舉實(shí)現(xiàn)的單例
    SingletonObject.java
    public enum SingletonObject { 
        INSTANCE
    ;
        private
    int num;
        protected
    void setNum(int num) {
            this.num = num;
        }
        public int getNum() {
            return
    num;
        }

    }
    SingletonConsumer.java

    public class SingletonConsumer {
        public String consumeSingletonObject() { 
            return
    String.valueOf(SingletonObject.INSTANCE.getNum());
        }
    }
    SingletonConsumerTest.java
    @RunWith(PowerMockRunner.class) 
    @PrepareForTest({SingletonObject.class})
    public class SingletonConsumerTest {
        @Test public void testConsumeSingletonObject() throws Exception {
            SingletonObject
    mockInstance = mock(SingletonObject.class);
            Whitebox
    .setInternalState(SingletonObject.class, "INSTANCE", mockInstance);
            when
    (mockInstance.getNum()).thenReturn(42);
            assertEquals
    ("42", new SingletonConsumer().consumeSingletonObject());
        }
    }
    4。返回參數(shù)值做為函數(shù)返回值。
    mockito 1.9.5之后,提供一個(gè)方便的方法來實(shí)現(xiàn)這個(gè)需要,在這之前可以使用一個(gè)匿名函數(shù)來返回一個(gè)answer來實(shí)現(xiàn)。
    when(myMock.myFunction(anyString())).then(returnsFirstArg());
    其中returnsFirstArg()是org.mockito.AdditionalAnswers中的一個(gè)靜態(tài)方法。
    在這個(gè)類中還有其他的一些類似方法
    returnsSecondArg()
    returnsLastArg()
    ReturnsArgumentAt(int position)

    5. 在調(diào)用mock出來的方法中,改變方法參數(shù)的值
    when( myMock.someMethod( any( List.class ) ) ).thenAnswer( ( new Answer<Void>() {
        @Override
        
    public Void answer( InvocationOnMock invocation )
                
    throws Throwable {
            Object[] args 
    = invocation.getArguments();
            List arg1 
    = (List)args[0];
            arg1.add(
    "12345");
            
    return null;
        }
    } ) );



    Verifying with generic parameters
    verify(someService).process(Matchers.<Collection<Person>>any());
    verify(adunoMasterBaseProcessor).processBinFiles( anyListOf(File.class) );

    posted @ 2015-06-16 21:27 云自無心水自閑 閱讀(18458) | 評(píng)論 (0)編輯 收藏

    Oracle提供的JDK其實(shí)已經(jīng)自帶一定程度的熱加載功能,但是如果你修改了類名,方法名,或者添加了新類,新方法的話。
    Tomcat都需要重新啟動(dòng)來使得剛才的更改生效。
    而JRebel和springloaded都能有效地解決這個(gè)問題。其中springloaded是開源軟件,可以免費(fèi)使用,尤其難得。
    其主頁:https://github.com/spring-projects/spring-loaded
    在官方頁面的簡單介紹中,作者只講述了如何在java程序中應(yīng)用springloaded,而沒有說明如何在tomcat中進(jìn)行配置。
    本文將簡要進(jìn)行介紹。

    1,下載springloaded到本地目錄,比如:c:\temp\springloaded-1.2.3.RELEASE.jar

    2. 修改tomcat的應(yīng)用,禁止tomcat自己的熱加載,方法是在META-INF目錄下創(chuàng)建context.xml文件,里面包含如下語句,關(guān)鍵便是其中設(shè)置reloadable為false
    <?xml version="1.0" encoding="UTF-8"?>
    <Context antiResourceLocking="false" privileged="true" useHttpOnly="true" reloadable="false" />

    3.在運(yùn)行環(huán)境中添加springloaded的jar文件,在eclipse中右鍵點(diǎn)擊項(xiàng)目,run as->run configuration
    在彈出的窗口中,選擇Arguments標(biāo)簽,在vm arguments的末尾添加:
    -javaagent:C:\temp\springloaded-1.2.3.RELEASE.jar -noverify
    點(diǎn)擊應(yīng)用按鈕。

    以上便完成了所有的配置,步驟并不復(fù)雜。

    posted @ 2015-06-11 21:59 云自無心水自閑 閱讀(7714) | 評(píng)論 (0)編輯 收藏

    java wrapper是一個(gè)可以用于將java應(yīng)用程序包裝成windows服務(wù)的工具。
    并且可以通過簡單的配置來允許使用visualVM進(jìn)行監(jiān)控。

    配置方法:
    在wrapper.conf中添加如下3行

    wrapper.java.additional.1=-Dcom.sun.management.jmxremote.port=9898 #這里的端口號(hào)可以自行選擇。
    wrapper.java.additional.2=-Dcom.sun.management.jmxremote.ssl=false
    wrapper.java.additional.3=-Dcom.sun.management.jmxremote.authenticate=false

    修改完畢保存后重新啟動(dòng)服務(wù)。

    打開visualVM, 在菜單中選擇 file->Add JMX Connection。
    在彈出窗口中,connection一項(xiàng)中輸入: localhost:9898 即可。

    此配置對(duì)于jconsole也同樣有效。

    posted @ 2015-06-11 14:09 云自無心水自閑 閱讀(4817) | 評(píng)論 (0)編輯 收藏

    在一些歷史遺留代碼中,會(huì)用到j(luò)ava.util.logging. 如果在新的項(xiàng)目中引用了這些代碼,而又不希望去一個(gè)一個(gè)的修改原來的代碼。
    可以使用slf4j提供的類來轉(zhuǎn)接這部分的日志輸出。

    方法:
    1、類路徑中添加
        slf4j-api-1.7.10.jar
        jul-to-slf4j.1.7.10.jar ( 用于將java.util.logging的日志橋接到slf4j中)
        logback-core.1.1.2.jar
        logback-classic-1.1.2.jar

    2、在代碼中添加:
             // Optionally remove existing handlers attached to j.u.l root logger
             SLF4JBridgeHandler.removeHandlersForRootLogger();  // (since SLF4J 1.6.5)

             // add SLF4JBridgeHandler to j.u.l's root logger, should be done once during
             // the initialization phase of your application
             SLF4JBridgeHandler.install();

    注意事項(xiàng):
    1、這個(gè)橋接可以會(huì)造成性能問題。
    和其他的橋接實(shí)現(xiàn)(比如:log4j, commons logging)不同,這個(gè)模塊并不真正的完全替代java.util.logging類,因?yàn)檫@個(gè)java.util.logging是java自帶的。
    所以只是把原來的日志對(duì)象進(jìn)行了轉(zhuǎn)換,簡單的說,這個(gè)轉(zhuǎn)換過程是有開銷的。
    關(guān)鍵在于,不管日志語句有沒有根據(jù)日志級(jí)別被關(guān)閉,這個(gè)轉(zhuǎn)換無法避免。

    2、不能在類路徑中放入
    slf4j-jkd14.jar
    jul-toslf4j.jar

    posted @ 2015-04-27 15:31 云自無心水自閑 閱讀(1551) | 評(píng)論 (0)編輯 收藏

     1. Text Editor: Notepad++/Syncplify.me Notepad!
     2. Browser: Chrome/Firefox
     3. 文件管理: XYplorer Lite/Explorer++/Q-Dir
     4. Mind map: XMind Free
     5. Video player: PotPlayer
     6. Music player: Kugou
     7. Mysql client: HeidiSql
     8. PDF reader: Foxit Reader
     9. File/Folder synchronize : FreeFileSync
    10. MP3 tools: Audacity/MP3 Gain
    11. Zip: 7-zip
    12. Partition Management: EaseUS Partition Master Free / MiniTool Free Partition Manager 
    13. Data Recovery: EaseUS Data Recovery Wizard Free / MiniTool Free Data Recovery
    14. PDF Printer: PDF reDirect v2
    15. 個(gè)人信息管理: EssentialPIM Free Edition
    16. 遠(yuǎn)程登錄: Terminals
    17. 文本比較合并: winmerge
    18. (s)FTP client: WinSCP
    19. 圖像處理: GIMP

    posted @ 2015-04-14 21:21 云自無心水自閑 閱讀(726) | 評(píng)論 (0)編輯 收藏

    Ember 是一個(gè)旨在創(chuàng)建大型web應(yīng)用的JavaScript框架,它消除了樣板(boilerplate)并提供了標(biāo)準(zhǔn)的應(yīng)用程序架構(gòu)。

    Manning: Ember.js in action 第一章
    Manning: Ember.js in action 第五章

    posted @ 2015-03-23 12:37 云自無心水自閑 閱讀(3707) | 評(píng)論 (1)編輯 收藏

    先給一個(gè)例子:
    $http. get('/remote/item' ). then(function(response) {
    console.log('成功。');
    }, function(errResponse) {
    console. error('出錯(cuò).' );
    });

    一。介紹Promise
    在這個(gè)例子中,$http.get()函數(shù)返回了一個(gè)Promise對(duì)象, 有了這個(gè)對(duì)象,我們才能很方便地直接在后面添加then函數(shù)的定義。
    Promise對(duì)象在AngularJS中是一個(gè)非常重要的存在。它提供了強(qiáng)大的功能和便利性。

    1。異步性
    從定義的語法上看,操作似乎是同步的,但是Promise的工作其實(shí)是異步的,只有在服務(wù)端返回?cái)?shù)據(jù)后,后續(xù)的函數(shù)才會(huì)被調(diào)用。這是一個(gè)事件驅(qū)動(dòng),非阻塞式的框架。

    2。它避免了其它框架的嵌套回調(diào)函數(shù)的缺點(diǎn)。
    -所有異步任務(wù)都會(huì)返回一個(gè)Promise對(duì)象
    -每個(gè)Promise對(duì)象都有一個(gè)then函數(shù),then函數(shù)有兩個(gè)參數(shù),分別是成功處理函數(shù)和失敗處理函數(shù)
    -失敗處理函數(shù)和成功處理函數(shù)都只會(huì)在異步處理完成后被調(diào)用一次
    -then函數(shù)也會(huì)返回Promise對(duì)象,這樣,我們可以把多個(gè)函數(shù)串連起來成為一個(gè)函數(shù)鏈
    -成功處理函數(shù)和失敗處理函數(shù)的返回值可以被傳遞到函數(shù)鏈下一個(gè)的函數(shù)中
    -如果在成功(或者失敗)處理函數(shù)中,又開始了一個(gè)異步調(diào)用,那么函數(shù)鏈中的函數(shù)將會(huì)在這個(gè)異步調(diào)用結(jié)束后才開始

    二。異步鏈?zhǔn)秸{(diào)用的后續(xù)處理
    假如我們定義了如下的函數(shù)鏈:
    $http.get('/item').then(s1, e1).then(s2, e2).then(s3, e3);
    我們?nèi)绾巫灾鞯母鶕?jù)函數(shù)鏈中每個(gè)函數(shù)的運(yùn)行結(jié)果,決定觸發(fā)后續(xù)函數(shù)的成功處理函數(shù)或者失敗處理函數(shù)呢?
    比如說,在s1處理過程中,發(fā)生問題,于是我們觸發(fā)了e2, 但是在e2處理完后,我們又想觸發(fā)s3.
    AnguarJS提供了$q來滿足這樣的需求。
    如果我們想觸發(fā)函數(shù)鏈中下一個(gè)函數(shù)的成功處理,我們只需要最后給出一個(gè)返回值,有了返回值,AngularJS會(huì)認(rèn)為函數(shù)執(zhí)行正確,自動(dòng)調(diào)用下一個(gè)函數(shù)中的成功處理
    如果想觸發(fā)失敗處理,那么可以簡單地返回$q.reject(data),這樣就會(huì)觸發(fā)下一個(gè)函數(shù)的失敗處理

    posted @ 2015-02-27 18:39 云自無心水自閑 閱讀(2616) | 評(píng)論 (1)編輯 收藏



    在前文(http://www.tkk7.com/usherlight/archive/2015/02/01/422633.html)中我們?cè)?jīng)介紹過,定義controller時(shí),需要2個(gè)參數(shù),第一個(gè)參數(shù)是controller的名稱,第二個(gè)參數(shù)是一個(gè)數(shù)組,數(shù)組的最后一個(gè)元素將是controller的函數(shù),前面的參數(shù)是controller的依賴項(xiàng)。我們現(xiàn)在就來仔細(xì)分析一下其中的具體過程。

    先給一個(gè)例子:
    angular. module('notesApp' , [])
     . controller('MainCtrl' , ['$log' , function($log) {
     var self = this;
     self. logStuff = function() {
     $log. log('The button was pressed' );
     };
     }])

    在這個(gè)例子中可以看到,我們?cè)诘谝粋€(gè)參數(shù)中用字符串(服務(wù)名稱)添加了一個(gè)依賴項(xiàng)。當(dāng)我們通過字符串聲明了這一個(gè)服務(wù)之后,我們就可以把它當(dāng)作一個(gè)變量注入到函數(shù)中。AngularJS會(huì)自動(dòng)查找字符串名稱對(duì)應(yīng)的服務(wù)名,按照順序?qū)⑵渥⑷氲胶瘮?shù)中。
    myModule.controller("MainCtrl",  ["$log", "$window", function($l, $w) {}]);
    在這個(gè)例子中,$log, $windows是AngularJS自帶的兩個(gè)服務(wù),在數(shù)組中通過名稱聲明后,會(huì)被注入到函數(shù)的兩個(gè)參數(shù)中。
    比較常用的AngularJS自帶的服務(wù)有:$window, $location, $http等

    從上面的例子中可以看出,AngularJS的設(shè)計(jì)思想就是不要在函數(shù)中自己去實(shí)例化或者通過其它途徑來獲取服務(wù)的實(shí)例,而是聲明需要的對(duì)象,由AngularJS來注入具體的實(shí)例。

    創(chuàng)建自己的服務(wù)
    什么時(shí)候應(yīng)該創(chuàng)建服務(wù),而不是controller呢?
    1。 需要重用的時(shí)候
    2。需要保留應(yīng)用級(jí)的狀態(tài)。這是非常重要的一點(diǎn),controller是會(huì)不斷地被創(chuàng)建和銷毀的,如果需要保存應(yīng)用級(jí)的狀態(tài),就需要使用service
    3。和頁面顯示無關(guān)
    4。需要和第三方服務(wù)整合
    5。緩存

    服務(wù)是會(huì)被延遲加載的,也就是說只有在第一次被引用的時(shí)候,才會(huì)被創(chuàng)建。
    服務(wù)將會(huì)被定義一次,也只會(huì)被實(shí)例化一次。

    posted @ 2015-02-09 19:28 云自無心水自閑 閱讀(7281) | 評(píng)論 (0)編輯 收藏

         摘要: 默認(rèn)情況下,每隔一秒種,SpringLoaded就會(huì)掃描類路徑,自動(dòng)加載改變過的類, 而不需要重新啟動(dòng)應(yīng)用  閱讀全文

    posted @ 2015-02-07 09:16 云自無心水自閑 閱讀(11098) | 評(píng)論 (4)編輯 收藏

    07. ng-repeart
    a. 在循環(huán)map的時(shí)候,會(huì)自動(dòng)根據(jù)鍵值進(jìn)行排序。
    b. 一些自帶的變量,$first(是否是第一個(gè)), $last(是否是最后一個(gè)), $middle(是否是中間的), $index(下標(biāo),根據(jù)鍵值排序后的下標(biāo)), $even, $odd
    08. 自己定義新變量時(shí)不要使用$$開頭。
    09. 可以使用track-by表達(dá)式來優(yōu)化對(duì)DOM的操作,對(duì)DOM對(duì)象使用從數(shù)據(jù)庫取得的ID來進(jìn)行標(biāo)記,這樣的話,當(dāng)我們重復(fù)多次從數(shù)據(jù)庫中取出相同的數(shù)據(jù)的時(shí)候,DOM對(duì)象就能夠被重用。
    10. 數(shù)據(jù)雙向綁定的好處
    a. 如果我們想改變頁面Form中的數(shù)值,我們不需要在Javascript中,根據(jù)ID或者名稱來查找相應(yīng)的Form控件,只需要改變Controller變量的值,不需要JQuery的Selector,也不需要findElementByID
    b. 如果我們想在javascript中獲取Form控件的值,在控件的變量中就能直接獲得。
    11. 使用ng-submit比在button上使用ng-click要好一些。HTML的表單的提交有多種方式,比如在輸入域中按回車鍵就會(huì)觸發(fā)ng-submit,而不會(huì)觸發(fā)button的ng-click事件。
    12. 在ng-model中,可以直接引用一個(gè)對(duì)象,比如:<input type="text" ng-model="ctrl.user.name">,而不需要事先在model中以self.user={}定義。在AngularJS中,使用了ng-model的話,AngularJS在初始化數(shù)據(jù)綁定的時(shí)候,自動(dòng)創(chuàng)建其中的對(duì)象和鍵值。在剛才的例子中,一旦用戶開始在輸入域中鍵入第一個(gè)字母,用戶user就會(huì)被自動(dòng)創(chuàng)建。
    13. 推薦使用將相關(guān)數(shù)據(jù)集中到一個(gè)對(duì)象的方式來進(jìn)行數(shù)據(jù)綁定,比如,用戶名和密碼,推薦使用:
    <input type="text" ng-model="ctrl.user.name">
    <input type="text" ng-model="ctrl.user.password">
    而不是:
    <input type="text" ng-model="ctrl.name">
    <input type="text" ng-model="ctrl.password">

    posted @ 2015-02-03 19:36 云自無心水自閑 閱讀(2638) | 評(píng)論 (1)編輯 收藏

    1. AngularJS的module函數(shù)有兩種用法,
    a. 定義一個(gè)module, 需要傳入2個(gè)參數(shù),module('moduleName', []), 第一個(gè)參數(shù)是新的module名稱,第二個(gè)參數(shù)是新module所依賴的module數(shù)組。
    b. 載入一個(gè)module, 只需要1個(gè)參數(shù),module('moduleName'), 唯一的一個(gè)參數(shù)指定要載入的module名稱。
    2. 使用controller函數(shù)來定義一個(gè)控制器(controller), 用ng-controller將控制器綁定到具體的HTML組件上。定義控制器的controller函數(shù)也需要2個(gè)參數(shù),第一個(gè)是控制器名稱,第二個(gè)參數(shù)同樣也是一個(gè)數(shù)組,數(shù)組的最后一個(gè)元素就是controller本身的函數(shù),前面的元素用字符串的形式指定其需要的依賴項(xiàng)。如果沒有依賴項(xiàng),那就只需要定義函數(shù)。比如:
    angular.module('app1', [])
    .controller('mainControl', [function() {
    console.log('controller created.');
    }]);
    3. 在controller函數(shù)中用var定義的局部變量,在HTML中是不可見的。
    4. 推薦在controller函數(shù)中盡量避免直接引用this, 比較好的做法是使用代理。原因是一個(gè)函數(shù)中的this關(guān)鍵詞在被外部調(diào)用的時(shí)候,是會(huì)被覆蓋掉的。這樣的話,在函數(shù)內(nèi)部和外部的this會(huì)是完全不同兩個(gè)對(duì)象。
    代理用法示例:
    angular.module('app1', [])
    .controller('mainControl', [function() {
    var self = this;
    self.message = 'Hello world';
    self.changeMessage = function() {
    self.message = 'Goodbye.';
    };
    }]);
    5. ng-bind與雙大括號(hào)的區(qū)別, ng-bind和{{}}可以說基本上是可以互相替換的,但是也有區(qū)別。區(qū)別在于:AngularJS在啟動(dòng)的時(shí)候就會(huì)執(zhí)行ng-bind, 而{{}}的替換時(shí)間會(huì)稍晚一些。有可能發(fā)現(xiàn)頁面在加載的時(shí)候,雙括號(hào)被一閃而過地替換掉(只在頁面初次加載的時(shí)候發(fā)生)。但是ng-bind就沒有這個(gè)問題。
    6. ng-cloak可以用于解決雙括號(hào)閃現(xiàn)的問題。

    posted @ 2015-02-01 19:19 云自無心水自閑 閱讀(5029) | 評(píng)論 (1)編輯 收藏

    1. HTML頁面的加載,這會(huì)觸發(fā)加載頁面包含的所有JS (包括 AngularJS)
    2. AngularJS啟動(dòng),搜尋所有的指令(directive)
    3. 找到ng-app,搜尋其指定的模塊(Module),并將其附加到ng-app所在的組件上。
    4. AnguarJS遍歷所有的子組件,查找指令和bind命令
    5. 每次發(fā)現(xiàn)ng-controller或者ng-repeart的時(shí)候,它會(huì)創(chuàng)建一個(gè)作用域(scope),這個(gè)作用域就是組件的上下文。作用域指明了每個(gè)DOM組件對(duì)函數(shù)、變量的訪問權(quán)。
    6. AngularJS然后會(huì)添加對(duì)變量的監(jiān)聽器,并監(jiān)控每個(gè)變量的當(dāng)前值。一旦值發(fā)生變化,AngularJS會(huì)更新其在頁面上的顯示。
    7. AngularJS優(yōu)化了檢查變量的算法,它只會(huì)在某些特殊的事件觸發(fā)時(shí),才會(huì)去檢查數(shù)據(jù)的更新,而不是簡單地在后臺(tái)不停地輪詢。

    posted @ 2015-01-31 20:36 云自無心水自閑 閱讀(4779) | 評(píng)論 (2)編輯 收藏

    Java虛擬機(jī)規(guī)范規(guī)定JVM的內(nèi)存分為了好幾塊,比如堆,棧,程序計(jì)數(shù)器,方法區(qū)等,而Hotspot jvm的實(shí)現(xiàn)中,將堆內(nèi)存分為了三部分,新生代,老年代,持久帶,其中持久帶實(shí)現(xiàn)了規(guī)范中規(guī)定的方法區(qū),而內(nèi)存模型中不同的部分都會(huì)出現(xiàn)相應(yīng)的OOM錯(cuò)誤,接下來我們就分開來討論一下。 

    棧溢出(StackOverflowError) 

    棧溢出拋出java.lang.StackOverflowError錯(cuò)誤,出現(xiàn)此種情況是因?yàn)榉椒ㄟ\(yùn)行的時(shí)候棧的深度超過了虛擬機(jī)容許的最大深度所致。 

    出現(xiàn)這種情況,一般情況下是程序錯(cuò)誤所致的,比如寫了一個(gè)死遞歸,就有可能造成此種情況。 下面我們通過一段代碼來模擬一下此種情況的內(nèi)存溢出。 
    Java代碼 
    1. import java.util.*;  
    2. import java.lang.*;  
    3. public class OOMTest{  
    4.    
    5.   public void stackOverFlowMethod(){  
    6.       stackOverFlowMethod();  
    7.   }  
    8.    
    9.   public static void main(String... args){  
    10.       OOMTest oom = new OOMTest();  
    11.       oom.stackOverFlowMethod();  
    12.   }  
    13.    
    14. }  

    運(yùn)行上面的代碼,會(huì)拋出如下的異常: 
    引用

    Exception in thread "main" java.lang.StackOverflowError 
            at OOMTest.stackOverFlowMethod(OOMTest.java:6) 

    堆溢出(OutOfMemoryError:java heap space) 

    堆內(nèi)存溢出的時(shí)候,虛擬機(jī)會(huì)拋出java.lang.OutOfMemoryError:java heap space,出現(xiàn)此種情況的時(shí)候,我們需要根據(jù)內(nèi)存溢出的時(shí)候產(chǎn)生的dump文件來具體分析(需要增加-XX:+HeapDumpOnOutOfMemoryErrorjvm啟動(dòng)參數(shù))。出現(xiàn)此種問題的時(shí)候有可能是內(nèi)存泄露,也有可能是內(nèi)存溢出了。 
    如果內(nèi)存泄露,我們要找出泄露的對(duì)象是怎么被GC ROOT引用起來,然后通過引用鏈來具體分析泄露的原因。 
    如果出現(xiàn)了內(nèi)存溢出問題,這往往是程序本生需要的內(nèi)存大于了我們給虛擬機(jī)配置的內(nèi)存,這種情況下,我們可以采用調(diào)大-Xmx來解決這種問題。 

    下面我們通過如下的代碼來演示一下此種情況的溢出: 
    Java代碼 
    1. import java.util.*;  
    2. import java.lang.*;  
    3. public class OOMTest{  
    4.    
    5.         public static void main(String... args){  
    6.                 List<byte[]> buffer = new ArrayList<byte[]>();  
    7.                 buffer.add(new byte[10*1024*1024]);  
    8.         }  
    9.    
    10. }  

    我們通過如下的命令運(yùn)行上面的代碼: 

    Java代碼 
    1. java -verbose:gc -Xmn10M -Xms20M -Xmx20M -XX:+PrintGC OOMTest  


    程序輸入如下的信息: 
    引用

    [GC 1180K->366K(19456K), 0.0037311 secs] 
    [Full GC 366K->330K(19456K), 0.0098740 secs] 
    [Full GC 330K->292K(19456K), 0.0090244 secs] 
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 
            at OOMTest.main(OOMTest.java:7) 

    從運(yùn)行結(jié)果可以看出,JVM進(jìn)行了一次Minor gc和兩次的Major gc,從Major gc的輸出可以看出,gc以后old區(qū)使用率為134K,而字節(jié)數(shù)組為10M,加起來大于了old generation的空間,所以拋出了異常,如果調(diào)整-Xms21M,-Xmx21M,那么就不會(huì)觸發(fā)gc操作也不會(huì)出現(xiàn)異常了。 

    通過上面的實(shí)驗(yàn)其實(shí)也從側(cè)面驗(yàn)證了一個(gè)結(jié)論:當(dāng)對(duì)象大于新生代剩余內(nèi)存的時(shí)候,將直接放入老年代,當(dāng)老年代剩余內(nèi)存還是無法放下的時(shí)候,出發(fā)垃圾收集,收集后還是不能放下就會(huì)拋出內(nèi)存溢出異常了 

    持久帶溢出(OutOfMemoryError: PermGen space) 

    我們知道Hotspot jvm通過持久帶實(shí)現(xiàn)了Java虛擬機(jī)規(guī)范中的方法區(qū),而運(yùn)行時(shí)的常量池就是保存在方法區(qū)中的,因此持久帶溢出有可能是運(yùn)行時(shí)常量池溢出,也有可能是方法區(qū)中保存的class對(duì)象沒有被及時(shí)回收掉或者class信息占用的內(nèi)存超過了我們配置。當(dāng)持久帶溢出的時(shí)候拋出java.lang.OutOfMemoryError: PermGen space。 
    我在工作可能在如下幾種場景下出現(xiàn)此問題。 

    1.使用一些應(yīng)用服務(wù)器的熱部署的時(shí)候,我們就會(huì)遇到熱部署幾次以后發(fā)現(xiàn)內(nèi)存溢出了,這種情況就是因?yàn)槊看螣岵渴鸬暮螅瓉淼腸lass沒有被卸載掉。 
    2.如果應(yīng)用程序本身比較大,涉及的類庫比較多,但是我們分配給持久帶的內(nèi)存(通過-XX:PermSize和-XX:MaxPermSize來設(shè)置)比較小的時(shí)候也可能出現(xiàn)此種問題。 
    3.一些第三方框架,比如spring,hibernate都通過字節(jié)碼生成技術(shù)(比如CGLib)來實(shí)現(xiàn)一些增強(qiáng)的功能,這種情況可能需要更大的方法區(qū)來存儲(chǔ)動(dòng)態(tài)生成的Class文件。 
    我們知道Java中字符串常量是放在常量池中的,String.intern()這個(gè)方法運(yùn)行的時(shí)候,會(huì)檢查常量池中是否存和本字符串相等的對(duì)象,如果存在直接返回對(duì)常量池中對(duì)象的引用,不存在的話,先把此字符串加入常量池,然后再返回字符串的引用。那么我們就可以通過String.intern方法來模擬一下運(yùn)行時(shí)常量區(qū)的溢出.下面我們通過如下的代碼來模擬此種情況: 
    Java代碼 
    1. import java.util.*;  
    2. import java.lang.*;  
    3. public class OOMTest{  
    4.    
    5.         public static void main(String... args){  
    6.                 List<String> list = new ArrayList<String>();  
    7.                 while(true){  
    8.                         list.add(UUID.randomUUID().toString().intern());  
    9.                 }  
    10.         }  
    11.    
    12. }  

    我們通過如下的命令運(yùn)行上面代碼: 
    java -verbose:gc -Xmn5M -Xms10M -Xmx10M -XX:MaxPermSize=1M -XX:+PrintGC OOMTest 
    運(yùn)行后的輸入如下圖所示: 
    引用

    Exception in thread "main" java.lang.OutOfMemoryError: PermGen space 
            at java.lang.String.intern(Native Method) 
            at OOMTest.main(OOMTest.java:8) 

    通過上面的代碼,我們成功模擬了運(yùn)行時(shí)常量池溢出的情況,從輸出中的PermGen space可以看出確實(shí)是持久帶發(fā)生了溢出,這也驗(yàn)證了,我們前面說的Hotspot jvm通過持久帶來實(shí)現(xiàn)方法區(qū)的說法。 

    OutOfMemoryError:unable to create native thread 

    最后我們?cè)趤砜纯磈ava.lang.OutOfMemoryError:unable to create natvie thread這種錯(cuò)誤。 出現(xiàn)這種情況的時(shí)候,一般是下面兩種情況導(dǎo)致的: 

    1.程序創(chuàng)建的線程數(shù)超過了操作系統(tǒng)的限制。對(duì)于Linux系統(tǒng),我們可以通過ulimit -u來查看此限制。 
    給虛擬機(jī)分配的內(nèi)存過大,導(dǎo)致創(chuàng)建線程的時(shí)候需要的native內(nèi)存太少。我們都知道操作系統(tǒng)對(duì)每個(gè)進(jìn)程的內(nèi)存是有限制的,我們啟動(dòng)Jvm,相當(dāng)于啟動(dòng)了一個(gè)進(jìn)程,假如我們一個(gè)進(jìn)程占用了4G的內(nèi)存,那么通過下面的公式計(jì)算出來的剩余內(nèi)存就是建立線程棧的時(shí)候可以用的內(nèi)存。 線程棧總可用內(nèi)存=4G-(-Xmx的值)- (-XX:MaxPermSize的值)- 程序計(jì)數(shù)器占用的內(nèi)存 通過上面的公式我們可以看出,-Xmx 和 MaxPermSize的值越大,那么留給線程棧可用的空間就越小,在-Xss參數(shù)配置的棧容量不變的情況下,可以創(chuàng)建的線程數(shù)也就越小。因此如果是因?yàn)檫@種情況導(dǎo)致的unable to create native thread,那么要么我們?cè)龃筮M(jìn)程所占用的總內(nèi)存,或者減少-Xmx或者-Xss來達(dá)到創(chuàng)建更多線程的目的。

    posted @ 2015-01-20 07:12 云自無心水自閑 閱讀(872) | 評(píng)論 (0)編輯 收藏

    現(xiàn)在的顯示屏都在飚像素,商家的宣傳一個(gè)比一個(gè)噱頭大,什么 Retina、4K、8K 這種名詞一個(gè)接一個(gè)的出來, 這些到底都是啥意思?
     
    首先,Retina 和 4K 以及 8K 并不是同一層面的定義。屏幕一般是以像素點(diǎn)做單位的,4K 和 8K 就是直接限定了像素點(diǎn)的多少,而 Retina 則是沒有硬性的規(guī)范。

    Retina 屏幕的概念最早由蘋果公司執(zhí)行長史蒂夫·喬布斯(Steve Jobs)于 WWDC2010 發(fā)布 iPhone 4 時(shí)提出的。

      定義是:要求在正常觀看距離下,足以使人肉眼無法分辨其中的單獨(dú)像素。因此它并沒有限定像素值多少。

    4K 就是水平方向每一行的像素值達(dá)到或是接近 1024 的 4 倍,8K 就是達(dá)到或接近 8 倍。

      以此為標(biāo)準(zhǔn),4K 一般圖像就是指 4096*2160 的分辨率。當(dāng)然,這也不是硬性要求,像市場上很多 4K 屏幕其實(shí)是 3840*2160 或是 3656*2664,這些都是 4K 圖像分辨率的范疇。

      8K 就是分辨率在 7680*4320 左右。

    順便說一下,720p 則是指豎直方向的像素點(diǎn)達(dá)到 720 個(gè),1080p 則是 1080 個(gè),“P”是逐行掃描的意思

    問:那到底 Retina 和 4K 或是 Retina 和 8K 哪個(gè)更清楚呢?

      答:不一定,二者不能平行比較。

      因?yàn)?4K 和 8K 是限定了像素點(diǎn)的多少,而 Retina 是要求正常距離看不到像素點(diǎn)。

      舉個(gè)例子:如果放到正常的 42 寸屏幕上,4K 和 8K 在正常距離觀看下都看不到像素點(diǎn),那么兩者都可以被稱作“Retina 屏幕”。

          可是如果給你一臺(tái) 500 寸的巨大屏幕,那么即便是 8K 也會(huì)到處是馬賽克,這時(shí) Retina 觀感依然是高清無像素點(diǎn),必然比 8K 和 4K 清楚的多。

    posted @ 2015-01-15 07:17 云自無心水自閑 閱讀(651) | 評(píng)論 (0)編輯 收藏


    Last_SQL_Error: Error 'Lock wait timeout exceeded; try restarting transaction' on query. Default database: 'test'. Query: 'DELETE FROM table1 WHERE id = 361'
    1 row in set (0.00 sec)

    solution:
    restart slave;

    stop slave;
    start slave;

    posted @ 2015-01-13 08:01 云自無心水自閑 閱讀(596) | 評(píng)論 (0)編輯 收藏

    1. server.xml
    在<engine>中添加
    <Realm className="org.apache.catalina.realm.MemoryRealm" />
    2. tomcat-user.xml
    <role rolename="manager"/>   
    <role rolename="manager-gui"/>

    <user username="admin" password="tomcat" roles="manager"/>

    posted @ 2015-01-09 09:32 云自無心水自閑 閱讀(667) | 評(píng)論 (0)編輯 收藏


    1. 自動(dòng)掃描配置文件改動(dòng)
    <configuration scan="true" scanPeriod="30 seconds">
    ....
    </configuration

    2. 日志每天歸檔,同時(shí)目錄名包含相應(yīng)的年份和月份
    <fileNamePattern>F:\Programs\GlobalPos\GatewayCiti\logs\%d{yyyy/MM,aux}\G%d{dd}-%i.log</fileNamePattern>
    注意其中aux的使用,在fileNamePatter中如果出現(xiàn)多個(gè)%d的情況下,只能有一個(gè)為主配置,其他都需要使用aux標(biāo)記為附屬配置
    其中的%i請(qǐng)參看下節(jié)的介紹

    3. 文件同時(shí)根據(jù)日期和大小滾動(dòng)創(chuàng)建
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!-- rollover daily -->
                <!-- 
                <fileNamePattern>F:\Programs\GlobalPos\NetReport\logs\Portal-%d{yyyyMMdd}.log</fileNamePattern>
                
    -->
                
                <!-- Size and time based archiving -->
                <fileNamePattern>D:\logs\%d{yyyy/MM,aux}\L%d{dd}-%i.log</fileNamePattern>
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>100MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>            
            </rollingPolicy>

    fileNamePattern在上一節(jié)已經(jīng)介紹,這里主要介紹timeBasedFileNamingAndTriggeringPolicy,此處配置對(duì)文件大小的限定,由fileNamePattern的%i在確定下標(biāo)在文件名中的位置
    此示例產(chǎn)生的日志文件將會(huì)是:
    D:\logs\2015\01\L05-0.log 
    如果該文件大于100M,就會(huì)生成D:\logs\2015\01\L05-1.log

    posted @ 2015-01-07 09:40 云自無心水自閑 閱讀(7365) | 評(píng)論 (0)編輯 收藏

    OpenPGP 號(hào)稱是世界上使用最廣泛的郵件加密標(biāo)準(zhǔn).  OpenPGP is the most widely used email encryption standard in the world. ( http://www.openpgp.org/ )
    這篇例子介紹如何使用這個(gè)標(biāo)準(zhǔn)進(jìn)行文件的加密解密 (https://www.bouncycastle.org/latest_releases.html, 需要下載: bcprov-jdk15on-151.jar, bcpg-jdk15on-151.jar).

    主要是使用bouncycastle提供的OpenPGP的庫來完成這個(gè)功能,參照了其提供的示例程序,進(jìn)行了部分改動(dòng) ( Bouncy Castle 是一種用于 Java 平臺(tái)的開放源碼的輕量級(jí)密碼術(shù)包。它支持大量的密碼術(shù)算法,并提供 JCE 1.2.1 的實(shí)現(xiàn)。因?yàn)?Bouncy Castle 被設(shè)計(jì)成輕量級(jí)的,所以從 J2SE 1.4 到 J2ME(包括 MIDP)平臺(tái),它都可以運(yùn)行。它是在 MIDP 上運(yùn)行的唯一完整的密碼術(shù)包。)
    1. 添加循環(huán)遍歷來查找第一個(gè)可用的message
    2. 需要注意的是在main函數(shù)中的,如果不添加這一句的話 Security.addProvider(new BouncyCastleProvider()); 程序運(yùn)行中會(huì)報(bào)錯(cuò):No such Provider "BC"
    3. 
    錯(cuò)誤Exception in thread "main" java.security.InvalidKeyException: Illegal key size or default parameters , 這是因?yàn)閖ava缺省的庫支持的key長度比較短,需要到oracle的網(wǎng)站上去下載一個(gè)支持更長key的庫覆蓋原有的庫文件
    <JAVA_HOME>/lib/securty/ 目錄下的兩個(gè)jar文件
    local_policy.jar and US_export_policy.jar
    搜索這個(gè)文件: Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files

    package org.bouncycastle.openpgp.examples;

    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.security.NoSuchProviderException;
    import java.security.SecureRandom;
    import java.security.Security;
    import java.util.Iterator;

    import org.bouncycastle.bcpg.ArmoredOutputStream;
    import org.bouncycastle.bcpg.CompressionAlgorithmTags;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import org.bouncycastle.openpgp.PGPCompressedData;
    import org.bouncycastle.openpgp.PGPEncryptedData;
    import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
    import org.bouncycastle.openpgp.PGPEncryptedDataList;
    import org.bouncycastle.openpgp.PGPException;
    import org.bouncycastle.openpgp.PGPLiteralData;
    import org.bouncycastle.openpgp.PGPOnePassSignatureList;
    import org.bouncycastle.openpgp.PGPPrivateKey;
    import org.bouncycastle.openpgp.PGPPublicKey;
    import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
    import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
    import org.bouncycastle.openpgp.PGPSignatureList;
    import org.bouncycastle.openpgp.PGPUtil;
    import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
    import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
    import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
    import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
    import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
    import org.bouncycastle.util.io.Streams;

    /**
     * A simple utility class that encrypts/decrypts public key based
     * encryption files.
     * <p>
     * To encrypt a file: KeyBasedFileProcessor -e [-a|-ai] fileName publicKeyFile.<br>
     * If -a is specified the output file will be "ascii-armored".
     * If -i is specified the output file will be have integrity checking added.
     * <p>
     * To decrypt: KeyBasedFileProcessor -d fileName secretKeyFile passPhrase.
     * <p>
     * Note 1: this example will silently overwrite files, nor does it pay any attention to
     * the specification of "_CONSOLE" in the filename. It also expects that a single pass phrase
     * will have been used.
     * <p>
     * Note 2: if an empty file name has been specified in the literal data object contained in the
     * encrypted packet a file with the name filename.out will be generated in the current working directory.
     
    */
    public class KeyBasedFileProcessor
    {
        private static void decryptFile(
            String inputFileName,
            String keyFileName,
            char[] passwd,
            String defaultFileName)
            throws IOException, NoSuchProviderException
        {
            InputStream in = new BufferedInputStream(new FileInputStream(inputFileName));
            InputStream keyIn = new BufferedInputStream(new FileInputStream(keyFileName));
            decryptFile(in, keyIn, passwd, defaultFileName);
            keyIn.close();
            in.close();
        }

        /**
         * decrypt the passed in message stream
         
    */
        private static void decryptFile(
            InputStream in,
            InputStream keyIn,
            char[]      passwd,
            String      defaultFileName)
            throws IOException, NoSuchProviderException
        {
            in = PGPUtil.getDecoderStream(in);
            
            try
            {
                JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(in);
                PGPEncryptedDataList    enc;

                Object                  o = pgpF.nextObject();
                //
                
    // the first object might be a PGP marker packet.
                
    //
                if (o instanceof PGPEncryptedDataList)
                {
                    enc = (PGPEncryptedDataList)o;
                }
                else
                {
                    enc = (PGPEncryptedDataList)pgpF.nextObject();
                }
                
                //
                
    // find the secret key
                
    //
                Iterator                    it = enc.getEncryptedDataObjects();
                PGPPrivateKey               sKey = null;
                PGPPublicKeyEncryptedData   pbe = null;
                PGPSecretKeyRingCollection  pgpSec = new PGPSecretKeyRingCollection(
                    PGPUtil.getDecoderStream(keyIn), new JcaKeyFingerprintCalculator());

                while (sKey == null && it.hasNext())
                {
                    pbe = (PGPPublicKeyEncryptedData)it.next();
                    
                    sKey = PGPExampleUtil.findSecretKey(pgpSec, pbe.getKeyID(), passwd);
                }
                
                if (sKey == null)
                {
                    throw new IllegalArgumentException("secret key for message not found.");
                }
        
                InputStream         clear = pbe.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(sKey));
                
                JcaPGPObjectFactory    plainFact = new JcaPGPObjectFactory(clear);
                
                Object              message = plainFact.nextObject();
        
                while ( true ) {
                    if (message instanceof PGPCompressedData)
                    {
                        PGPCompressedData   cData = (PGPCompressedData)message;
                        JcaPGPObjectFactory    pgpFact = new JcaPGPObjectFactory(cData.getDataStream());
                        
                        message = pgpFact.nextObject();
                    }
                    
                    if (message instanceof PGPLiteralData)
                    {
                        PGPLiteralData ld = (PGPLiteralData)message;

                        String outFileName = ld.getFileName();
                        if (outFileName.length() == 0)
                        {
                            outFileName = defaultFileName;
                        }

                        InputStream unc = ld.getInputStream();
                        OutputStream fOut = new BufferedOutputStream(new FileOutputStream(outFileName));

                        Streams.pipeAll(unc, fOut);

                        fOut.close();
                        break;
                    }
                    else if (message instanceof PGPOnePassSignatureList)
                    {
                        System.out.println("encrypted message contains a signed message - not literal data.");
                    }
                    else if (message instanceof PGPSignatureList)
                    {
                        System.out.println("encrypted message contains a signed message - not literal data.");
                    }
                    else
                    {
                        throw new PGPException("message is not a simple encrypted file - type unknown.");
                    }
                    message = plainFact.nextObject();
                }
                
                if (pbe.isIntegrityProtected())
                {
                    if (!pbe.verify())
                    {
                        System.err.println("message failed integrity check");
                    }
                    else
                    {
                        System.err.println("message integrity check passed");
                    }
                }
                else
                {
                    System.err.println("no message integrity check");
                }
            }
            catch (PGPException e)
            {
                System.err.println(e);
                if (e.getUnderlyingException() != null)
                {
                    e.getUnderlyingException().printStackTrace();
                }
            }
        }

        private static void encryptFile(
            String          outputFileName,
            String          inputFileName,
            String          encKeyFileName,
            boolean         armor,
            boolean         withIntegrityCheck)
            throws IOException, NoSuchProviderException, PGPException
        {
            OutputStream out = new BufferedOutputStream(new FileOutputStream(outputFileName));
            PGPPublicKey encKey = PGPExampleUtil.readPublicKey(encKeyFileName);
            encryptFile(out, inputFileName, encKey, armor, withIntegrityCheck);
            out.close();
        }

        private static void encryptFile(
            OutputStream    out,
            String          fileName,
            PGPPublicKey    encKey,
            boolean         armor,
            boolean         withIntegrityCheck)
            throws IOException, NoSuchProviderException
        {
            if (armor)
            {
                out = new ArmoredOutputStream(out);
            }

            try
            {
                byte[] bytes = PGPExampleUtil.compressFile(fileName, CompressionAlgorithmTags.ZIP);

                PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
                    new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setWithIntegrityPacket(withIntegrityCheck).setSecureRandom(new SecureRandom()).setProvider("BC"));

                encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encKey).setProvider("BC"));

                OutputStream cOut = encGen.open(out, bytes.length);

                cOut.write(bytes);
                cOut.close();

                if (armor)
                {
                    out.close();
                }
            }
            catch (PGPException e)
            {
                System.err.println(e);
                if (e.getUnderlyingException() != null)
                {
                    e.getUnderlyingException().printStackTrace();
                }
            }
        }

        public static void main(
            String[] args)
            throws Exception
        {
            Security.addProvider(new BouncyCastleProvider());

            if (args.length == 0)
            {
                System.err.println("usage: KeyBasedFileProcessor -e|-d [-a|ai] file [secretKeyFile passPhrase|pubKeyFile]");
                return;
            }

            if (args[0].equals("-e"))
            {
                if (args[1].equals("-a") || args[1].equals("-ai") || args[1].equals("-ia"))
                {
                    encryptFile(args[2] + ".asc", args[2], args[3], true, (args[1].indexOf('i') > 0));
                }
                else if (args[1].equals("-i"))
                {
                    encryptFile(args[2] + ".bpg", args[2], args[3], falsetrue);
                }
                else
                {
                    encryptFile(args[1] + ".bpg", args[1], args[2], falsefalse);
                }
            }
            else if (args[0].equals("-d"))
            {
                decryptFile(args[1], args[2], args[3].toCharArray(), new File(args[1]).getName() + ".out");
            }
            else
            {
                System.err.println("usage: KeyBasedFileProcessor -d|-e [-a|ai] file [secretKeyFile passPhrase|pubKeyFile]");
            }
        }
    }


    asdf

    posted @ 2014-12-10 06:50 云自無心水自閑 閱讀(11804) | 評(píng)論 (5)編輯 收藏

     Netty作為一個(gè)異步非阻塞式的框架,是不允許在ChannelHandler中長時(shí)間處理事務(wù)(比如數(shù)據(jù)庫的操作),阻塞I/O的讀寫處理的。

    在Netty in Action中是這樣描述的:
    While the I/O thread must not be blocked at all, thus prohibiting any direct blocking operations within your ChannelHandler, there is a way to implement this requirement. 
    You can specify an EventExecutorGroup when adding ChannelHandlers to the ChannelPipeline. 
    This EventExecutorGroup will then be used to obtain an EventExecutor, which will execute all the methods of the ChannelHandler. 
    This EventExecutor will use a different thread from the I/O thread, thus freeing up the EventLoop.
    I/O線程是不允許被阻塞的,也就是不能在ChannelHandler中進(jìn)行任何阻塞式的處理,但是對(duì)此我們也有相應(yīng)的解決方法.
    就是在把ChannelHanders添加到ChannelPipeline的時(shí)候,指定一個(gè)EventExecutorGroup,ChannelHandler中所有的方法都將會(huì)在這個(gè)指定的EventExecutorGroup中運(yùn)行。
    而這個(gè)EVentExecutorGroup運(yùn)行的線程與I/O線程不同,達(dá)到不阻塞I/O的目的。 
    程序示例如下:
    Channel ch = ...;
    ChannelPipeline p = ch.pipeline();
    EventExecutor e1 = new DefaultEventExecutorGroup(16);
    EventExecutor e2 = new DefaultEventExecutorGroup(8);
     
    p.addLast(new MyProtocolCodec());
    p.addLast(e1, new MyDatabaseAccessingHandler());
    p.addLast(e2, new MyHardDiskAccessingHandler());
    需要補(bǔ)充說明一下,上面的示例程序似乎有點(diǎn)問題。使用上述方法添加ChannelHandler到pipeline中以后,channelHandler的所有方法確實(shí)什么在一個(gè)單獨(dú)的線程中被處理。
    但是,每次DefaultEventExcutorGroup線程池中的線程不能被重用,每次都會(huì)生成一個(gè)新的線程,然后在新的線程中調(diào)用ChannelHandler, 在visualvm可以看到線程數(shù)量直線增長。

    解決的方法是:不能使用局部變量形式的DefaultEventExecutorGroup。而使用類靜態(tài)成員變量:
    static final EventExecutor e1 = new DefaultEventExecutorGroup(16);

    我分析原因可能是:在新的連接到來,創(chuàng)建ChannelPipeline給新Channel的時(shí)候,如果不使用靜態(tài)的共享變量,而使用局部變量的話,就造成DefaultEventExecutorGroup被多次重復(fù)創(chuàng)建。因此,雖然一個(gè)DefaultEventExecutorGroup中的Thread數(shù)量是固定的,但是卻產(chǎn)生了多余的DefaultEventExecutorGroup。從VisualVM中也可以看到,DefaultEventExecutorGroup線程的名字會(huì)是:
    xxx-2-1
    xxx-3-1
    xxx-4-1
    xxx-n-1
    說明是Group的數(shù)量(第一個(gè)數(shù)字)在增多,而不是Group中的線程數(shù)量(第二個(gè)數(shù)字)在增多
    改成靜態(tài)變量后,線程名會(huì)是:
    xxx-2-1
    xxx-2-2
    xxx-2-3
    xxx-2-n
    最后一個(gè)n就是在創(chuàng)建DefaultEventExecutorGroup時(shí)候,傳入的線程個(gè)數(shù)參數(shù)的大小。

    posted @ 2014-11-27 07:36 云自無心水自閑 閱讀(9864) | 評(píng)論 (0)編輯 收藏

    Netty
    1. there're 2 EventLoopGroup in netty, bossGroup and workerGroup, (1 implementation NioEventLoopGroup is a kind of thread pool)
    2. bossGroup is Acceptor,is responsible for creating Channels for incoming connection requests
    3. workerGroup is the Reactor/Selector?, handling I/O requests. 
    4. a thread in bossGroup will be listening in the port, Once a connection has been accepted workerGroup assigns an EventLoop to its Channel
    5. multiple channels can be registered into 1 EventLoop, multiple EventLoops will exist in workerGroup
    6. workerGroup will iterate all the EventLoop, and iterate all the channels in EventLoop, if any of the channel is ready to execute/process
    7. it will invoke all the channelHandlers in the channelPipeline
    8. ChannelPipelines are containers for chains of ChannelHandlers which executed in order
    9. There are, in fact, two ways of sending messages in Netty. You can write directly to the Channel or write to the ChannelHandlerContext object. The main difference is that the former approach causes the message to start from the tail of the ChannelPipeline, while the latter causes the message to start from the next handler in the ChannelPipeline.
    10. While the I/O thread must not be blocked at all, thus prohibiting any direct blocking operations within your ChannelHandler, there is a way to implement this requirement.
    You can specify an EventExecutorGroup when adding ChannelHandlers to the ChannelPipeline.
    This EventExecutorGroup will then be used to obtain an EventExecutor, which will execute all the methods of the ChannelHandler.
    This EventExecutor will use a different thread from the I/O thread, thus freeing up the EventLoop.

    Channel ch = ...;
    ChannelPipeline p = ch.pipeline();
    EventExecutor e1 = new DefaultEventExecutor(16);
    EventExecutor e2 = new DefaultEventExecutor(8);
     
    p.addLast(new MyProtocolCodec());
    p.addLast(e1, new MyDatabaseAccessingHandler());
    p.addLast(e2, new MyHardDiskAccessingHandler());

    http://stackoverflow.com/questions/12928723/netty-4-eventloopgroup-eventloop-eventexecutor-thread-affinity

    posted @ 2014-11-21 14:18 云自無心水自閑 閱讀(527) | 評(píng)論 (0)編輯 收藏

    http://denis.doublebuffer.net/lablog/2012/11/19/fixing-the-screen-flickering-on-a-dell-inspiron-n5720-and-maybe-many-others/
    A Dell Inspiron N5720 has a nVidia GT 630M and an Intel HD Graphics 4000. Let’s see what the Intel Graphics Control panel looks like. To open it, follow these instructions.
    Select Advanced mode.
    Go to the Power menu and change the power source to “On battery”. Now uncheck the little check box that says “Display Refresh Rate Switch”. Apply. OK. And you’re done.

    posted @ 2014-02-14 19:58 云自無心水自閑 閱讀(547) | 評(píng)論 (0)編輯 收藏

    主站蜘蛛池模板: 亚洲乱码日产一区三区| 老色鬼久久亚洲AV综合| A片在线免费观看| 亚洲伊人久久大香线蕉| 国产又粗又猛又爽又黄的免费视频 | 国产乱子伦精品免费无码专区| 2022免费国产精品福利在线| 精品亚洲成a人片在线观看少妇| 午夜高清免费在线观看| 两个人www免费高清视频| 日韩亚洲产在线观看| 亚洲熟妇无码另类久久久| 国产精品成人免费视频网站京东| 成人午夜影视全部免费看| 亚洲精品国产免费| 亚洲精品在线视频| 一二三四视频在线观看中文版免费 | 免费人成视频在线播放| 亚洲第一成年网站大全亚洲| 亚洲国产主播精品极品网红| 久久国内免费视频| 你懂的在线免费观看| 亚洲AV成人精品日韩一区 | 亚洲国产成人九九综合| 国产亚洲精品免费视频播放 | 色噜噜综合亚洲av中文无码| 亚洲成av人在片观看| 91在线视频免费播放| 久久久久久久岛国免费播放| 免费看一级一级人妻片| 亚洲中文字幕无码mv| 久久亚洲日韩精品一区二区三区| 亚洲人成无码网站久久99热国产| 成在人线AV无码免费| 在免费jizzjizz在线播 | 亚洲综合区小说区激情区| 免费的涩涩视频在线播放| 成人免费大片免费观看网站| 女人体1963午夜免费视频| 九九综合VA免费看| 午夜亚洲国产理论片二级港台二级|