云自無(wú)心水自閑

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

          日歷

          <2014年11月>
          2627282930311
          2345678
          9101112131415
          16171819202122
          23242526272829
          30123456

          隨筆檔案

          積分與排名

          • 積分 - 1127647
          • 排名 - 27

          最新評(píng)論

          2014年11月27日

          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)閉輸出流。
          解決方法:
          將原來(lái)的程序:
                      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 云自無(wú)心水自閑 閱讀(442) | 評(píng)論 (0)編輯 收藏

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

          posted @ 2017-06-26 09:33 云自無(wú)心水自閑 閱讀(411) | 評(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 云自無(wú)心水自閑 閱讀(330) | 評(píng)論 (0)編輯 收藏

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

          posted @ 2017-05-24 07:13 云自無(wú)心水自閑 閱讀(18338) | 評(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 云自無(wú)心水自閑 閱讀(378) | 評(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 云自無(wú)心水自閑 閱讀(413) | 評(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 云自無(wú)心水自閑 閱讀(1634) | 評(píng)論 (0)編輯 收藏

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

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

          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、以管理員身份打開(kāi)命令行窗口,運(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ù)庫(kù),需要重啟mysql數(shù)據(jù)庫(kù)

          posted @ 2016-12-21 07:12 云自無(wú)心水自閑 閱讀(382) | 評(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 云自無(wú)心水自閑 閱讀(1324) | 評(píng)論 (0)編輯 收藏

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

          我的做法是使用pdfclown來(lái)進(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

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

          posted @ 2016-11-28 11:03 云自無(wú)心水自閑 閱讀(401) | 評(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 云自無(wú)心水自閑 閱讀(223) | 評(píng)論 (0)編輯 收藏

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

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

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


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

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

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


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

          posted @ 2016-09-16 13:13 云自無(wú)心水自閑 閱讀(2110) | 評(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 云自無(wú)心水自閑 閱讀(159) | 評(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 云自無(wú)心水自閑 閱讀(1057) | 評(píng)論 (0)編輯 收藏

           
          使用的工具

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

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

          posted @ 2016-06-05 19:00 云自無(wú)心水自閑 閱讀(204) | 評(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 云自無(wú)心水自閑 閱讀(389) | 評(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)檢測(cè)和為使?jié)L動(dòng)更平滑的視圖緩存等等。

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

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

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

          5. 簡(jiǎn)便的開(kāi)發(fā)。支持各種開(kāi)發(fā)語(yǔ)言,ES5, TypeScript, Dart

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

          7. 依賴注入。

          8. 舊瀏覽器的良好支持

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

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

          posted @ 2016-04-18 20:09 云自無(wú)心水自閑 閱讀(270) | 評(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 云自無(wú)心水自閑 閱讀(177) | 評(píng)論 (0)編輯 收藏

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

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

          今天把commons dbcp 和 pool都升級(jí)到2.x, 結(jié)果發(fā)現(xiàn)不能正常的工作,卡在new BasicDataSource()上了.
          后來(lái)才發(fā)現(xiàn)原因是因?yàn)闆](méi)有加入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 云自無(wú)心水自閑 閱讀(618) | 評(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 云自無(wú)心水自閑 閱讀(275) | 評(píng)論 (0)編輯 收藏


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

          我發(fā)現(xiàn)了一個(gè)簡(jiǎn)單的方法。
          直接使用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 云自無(wú)心水自閑 閱讀(477) | 評(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 云自無(wú)心水自閑 閱讀(1280) | 評(píng)論 (0)編輯 收藏

          Java程序中訪問(wèn)擁有全部讀寫權(quán)限的目錄相對(duì)比較簡(jiǎn)單,和普通的目錄沒(méi)有什么差別。
          但是要訪問(wèn)一個(gè)需要用戶和密碼驗(yàn)證的目錄就需要一點(diǎn)點(diǎn)小技巧了。
          這里介紹一個(gè)開(kāi)源的庫(kù)能夠比較容易的實(shí)現(xiàn)這一需求。
          1。 下載庫(kù)文件:
           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 !");
          說(shuō)明: 如果有一個(gè)共享目錄,比如: \\192.168.1.2\testdir\
          那么smb的路徑就是:smb://192.168.1.2/testdir/
          NtlmPasswordAuthentication需要三個(gè)參數(shù), 第一個(gè)是名,沒(méi)有的話,填null, 第二個(gè)是用戶名,第三個(gè)是密碼

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

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

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

          安裝服務(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 云自無(wú)心水自閑 閱讀(738) | 評(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 云自無(wú)心水自閑 閱讀(1226) | 評(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 云自無(wú)心水自閑 閱讀(373) | 評(píng)論 (0)編輯 收藏

           
          ipconfig /flushdns
          ipconfig /registerdns
          netsh winsock reset

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

          posted @ 2015-10-13 16:31 云自無(wú)心水自閑 閱讀(1793) | 評(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

          然后測(cè)試發(fā)送郵件,客戶端顯示發(fā)送成功,但是james服務(wù)器報(bào)錯(cuò),找不到MimeConfig的無(wú)參數(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 云自無(wú)心水自閑 閱讀(3283) | 評(píng)論 (0)編輯 收藏

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

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

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

          posted @ 2015-08-03 18:56 云自無(wú)心水自閑 閱讀(6259) | 評(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 云自無(wú)心水自閑 閱讀(419) | 評(píng)論 (0)編輯 收藏

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

          一點(diǎn)簡(jiǎn)要說(shuō)明:Mockito其實(shí)已經(jīng)可以滿足大部分的需求,但是它的實(shí)現(xiàn)機(jī)制是使用cglib來(lái)動(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ù), 如果有代碼沒(méi)有使用DI注入依賴實(shí)例,在單元測(cè)試中可以使用PowerMock來(lái)模擬創(chuàng)建對(duì)象。
          注意的開(kāi)始兩行的2個(gè)注解 @RunWith 和 @PrepareForTest
          @RunWith比較簡(jiǎn)單,后面始終是PowerMockRunner.class
          @PrepareForText后面需要加的是調(diào)用構(gòu)造函數(shù)的類名,而不是有構(gòu)造函數(shù)的類本身。
          在下面的例子中,我們要測(cè)試的類是:Helper, 在Helper類中調(diào)用了Somthing類的構(gòu)造函數(shù)來(lái)創(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)用需要測(cè)試方法
                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è)方便的方法來(lái)實(shí)現(xiàn)這個(gè)需要,在這之前可以使用一個(gè)匿名函數(shù)來(lái)返回一個(gè)answer來(lái)實(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出來(lái)的方法中,改變方法參數(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 云自無(wú)心水自閑 閱讀(18471) | 評(píng)論 (0)編輯 收藏

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

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

          2. 修改tomcat的應(yīng)用,禁止tomcat自己的熱加載,方法是在META-INF目錄下創(chuàng)建context.xml文件,里面包含如下語(yǔ)句,關(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 云自無(wú)心水自閑 閱讀(7723) | 評(píng)論 (0)編輯 收藏

          java wrapper是一個(gè)可以用于將java應(yīng)用程序包裝成windows服務(wù)的工具。
          并且可以通過(guò)簡(jiǎn)單的配置來(lái)允許使用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ù)。

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

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

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

          在一些歷史遺留代碼中,會(huì)用到j(luò)ava.util.logging. 如果在新的項(xiàng)目中引用了這些代碼,而又不希望去一個(gè)一個(gè)的修改原來(lái)的代碼。
          可以使用slf4j提供的類來(lái)轉(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ì)造成性能問(wèn)題。
          和其他的橋接實(shí)現(xiàn)(比如:log4j, commons logging)不同,這個(gè)模塊并不真正的完全替代java.util.logging類,因?yàn)檫@個(gè)java.util.logging是java自帶的。
          所以只是把原來(lái)的日志對(duì)象進(jìn)行了轉(zhuǎn)換,簡(jiǎn)單的說(shuō),這個(gè)轉(zhuǎn)換過(guò)程是有開(kāi)銷的。
          關(guān)鍵在于,不管日志語(yǔ)句有沒(méi)有根據(jù)日志級(jí)別被關(guān)閉,這個(gè)轉(zhuǎn)換無(wú)法避免。

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

          posted @ 2015-04-27 15:31 云自無(wú)心水自閑 閱讀(1557) | 評(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 云自無(wú)心水自閑 閱讀(730) | 評(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 云自無(wú)心水自閑 閱讀(3709) | 評(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。異步性
          從定義的語(yǔ)法上看,操作似乎是同步的,但是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ù)串連起來(lái)成為一個(gè)函數(shù)鏈
          -成功處理函數(shù)和失敗處理函數(shù)的返回值可以被傳遞到函數(shù)鏈下一個(gè)的函數(shù)中
          -如果在成功(或者失敗)處理函數(shù)中,又開(kāi)始了一個(gè)異步調(diào)用,那么函數(shù)鏈中的函數(shù)將會(huì)在這個(gè)異步調(diào)用結(jié)束后才開(kāi)始

          二。異步鏈?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ù)呢?
          比如說(shuō),在s1處理過(guò)程中,發(fā)生問(wèn)題,于是我們觸發(fā)了e2, 但是在e2處理完后,我們又想觸發(fā)s3.
          AnguarJS提供了$q來(lái)滿足這樣的需求。
          如果我們想觸發(fā)函數(shù)鏈中下一個(gè)函數(shù)的成功處理,我們只需要最后給出一個(gè)返回值,有了返回值,AngularJS會(huì)認(rèn)為函數(shù)執(zhí)行正確,自動(dòng)調(diào)用下一個(gè)函數(shù)中的成功處理
          如果想觸發(fā)失敗處理,那么可以簡(jiǎn)單地返回$q.reject(data),這樣就會(huì)觸發(fā)下一個(gè)函數(shù)的失敗處理

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



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

          先給一個(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)我們通過(guò)字符串聲明了這一個(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ù)組中通過(guò)名稱聲明后,會(huì)被注入到函數(shù)的兩個(gè)參數(shù)中。
          比較常用的AngularJS自帶的服務(wù)有:$window, $location, $http等

          從上面的例子中可以看出,AngularJS的設(shè)計(jì)思想就是不要在函數(shù)中自己去實(shí)例化或者通過(guò)其它途徑來(lái)獲取服務(wù)的實(shí)例,而是聲明需要的對(duì)象,由AngularJS來(lái)注入具體的實(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。和頁(yè)面顯示無(wú)關(guān)
          4。需要和第三方服務(wù)整合
          5。緩存

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

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

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

          posted @ 2015-02-07 09:16 云自無(wú)心水自閑 閱讀(11122) | 評(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í)不要使用$$開(kāi)頭。
          09. 可以使用track-by表達(dá)式來(lái)優(yōu)化對(duì)DOM的操作,對(duì)DOM對(duì)象使用從數(shù)據(jù)庫(kù)取得的ID來(lái)進(jìn)行標(biāo)記,這樣的話,當(dāng)我們重復(fù)多次從數(shù)據(jù)庫(kù)中取出相同的數(shù)據(jù)的時(shí)候,DOM對(duì)象就能夠被重用。
          10. 數(shù)據(jù)雙向綁定的好處
          a. 如果我們想改變頁(yè)面Form中的數(shù)值,我們不需要在Javascript中,根據(jù)ID或者名稱來(lái)查找相應(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ì)象和鍵值。在剛才的例子中,一旦用戶開(kāi)始在輸入域中鍵入第一個(gè)字母,用戶user就會(huì)被自動(dòng)創(chuàng)建。
          13. 推薦使用將相關(guān)數(shù)據(jù)集中到一個(gè)對(duì)象的方式來(lái)進(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 云自無(wú)心水自閑 閱讀(2644) | 評(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ù)來(lái)定義一個(gè)控制器(controller), 用ng-controller將控制器綁定到具體的HTML組件上。定義控制器的controller函數(shù)也需要2個(gè)參數(shù),第一個(gè)是控制器名稱,第二個(gè)參數(shù)同樣也是一個(gè)數(shù)組,數(shù)組的最后一個(gè)元素就是controller本身的函數(shù),前面的元素用字符串的形式指定其需要的依賴項(xiàng)。如果沒(méi)有依賴項(xiàng),那就只需要定義函數(shù)。比如:
          angular.module('app1', [])
          .controller('mainControl', [function() {
          console.log('controller created.');
          }]);
          3. 在controller函數(shù)中用var定義的局部變量,在HTML中是不可見(jiàn)的。
          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和{{}}可以說(shuō)基本上是可以互相替換的,但是也有區(qū)別。區(qū)別在于:AngularJS在啟動(dòng)的時(shí)候就會(huì)執(zhí)行ng-bind, 而{{}}的替換時(shí)間會(huì)稍晚一些。有可能發(fā)現(xiàn)頁(yè)面在加載的時(shí)候,雙括號(hào)被一閃而過(guò)地替換掉(只在頁(yè)面初次加載的時(shí)候發(fā)生)。但是ng-bind就沒(méi)有這個(gè)問(wèn)題。
          6. ng-cloak可以用于解決雙括號(hào)閃現(xiàn)的問(wèn)題。

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

          1. HTML頁(yè)面的加載,這會(huì)觸發(fā)加載頁(yè)面包含的所有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ù)、變量的訪問(wèn)權(quán)。
          6. AngularJS然后會(huì)添加對(duì)變量的監(jiān)聽(tīng)器,并監(jiān)控每個(gè)變量的當(dāng)前值。一旦值發(fā)生變化,AngularJS會(huì)更新其在頁(yè)面上的顯示。
          7. AngularJS優(yōu)化了檢查變量的算法,它只會(huì)在某些特殊的事件觸發(fā)時(shí),才會(huì)去檢查數(shù)據(jù)的更新,而不是簡(jiǎn)單地在后臺(tái)不停地輪詢。

          posted @ 2015-01-31 20:36 云自無(wú)心水自閑 閱讀(4783) | 評(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ò)誤,接下來(lái)我們就分開(kāi)來(lái)討論一下。 

          棧溢出(StackOverflowError) 

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

          出現(xiàn)這種情況,一般情況下是程序錯(cuò)誤所致的,比如寫了一個(gè)死遞歸,就有可能造成此種情況。 下面我們通過(guò)一段代碼來(lái)模擬一下此種情況的內(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文件來(lái)具體分析(需要增加-XX:+HeapDumpOnOutOfMemoryErrorjvm啟動(dòng)參數(shù))。出現(xiàn)此種問(wèn)題的時(shí)候有可能是內(nèi)存泄露,也有可能是內(nèi)存溢出了。 
          如果內(nèi)存泄露,我們要找出泄露的對(duì)象是怎么被GC ROOT引用起來(lái),然后通過(guò)引用鏈來(lái)具體分析泄露的原因。 
          如果出現(xiàn)了內(nèi)存溢出問(wèn)題,這往往是程序本生需要的內(nèi)存大于了我們給虛擬機(jī)配置的內(nèi)存,這種情況下,我們可以采用調(diào)大-Xmx來(lái)解決這種問(wèn)題。 

          下面我們通過(guò)如下的代碼來(lái)演示一下此種情況的溢出: 
          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. }  

          我們通過(guò)如下的命令運(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,加起來(lái)大于了old generation的空間,所以拋出了異常,如果調(diào)整-Xms21M,-Xmx21M,那么就不會(huì)觸發(fā)gc操作也不會(huì)出現(xiàn)異常了。 

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

          持久帶溢出(OutOfMemoryError: PermGen space) 

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

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

          我們通過(guò)如下的命令運(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) 

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

          OutOfMemoryError:unable to create native thread 

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

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

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

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

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

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

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

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

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

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

          問(wèn):那到底 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 觀感依然是高清無(wú)像素點(diǎn),必然比 8K 和 4K 清楚的多。

          posted @ 2015-01-15 07:17 云自無(wú)心水自閑 閱讀(654) | 評(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 云自無(wú)心水自閑 閱讀(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 云自無(wú)心水自閑 閱讀(669) | 評(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 云自無(wú)心水自閑 閱讀(7374) | 評(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的庫(kù)來(lái)完成這個(gè)功能,參照了其提供的示例程序,進(jìn)行了部分改動(dòng) ( Bouncy Castle 是一種用于 Java 平臺(tái)的開(kā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)遍歷來(lái)查找第一個(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缺省的庫(kù)支持的key長(zhǎng)度比較短,需要到oracle的網(wǎng)站上去下載一個(gè)支持更長(zhǎng)key的庫(kù)覆蓋原有的庫(kù)文件
          <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 云自無(wú)心水自閑 閱讀(11817) | 評(píng)論 (5)編輯 收藏

           Netty作為一個(gè)異步非阻塞式的框架,是不允許在ChannelHandler中長(zhǎng)時(shí)間處理事務(wù)(比如數(shù)據(jù)庫(kù)的操作),阻塞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ǔ)充說(shuō)明一下,上面的示例程序似乎有點(diǎn)問(wèn)題。使用上述方法添加ChannelHandler到pipeline中以后,channelHandler的所有方法確實(shí)什么在一個(gè)單獨(dú)的線程中被處理。
          但是,每次DefaultEventExcutorGroup線程池中的線程不能被重用,每次都會(huì)生成一個(gè)新的線程,然后在新的線程中調(diào)用ChannelHandler, 在visualvm可以看到線程數(shù)量直線增長(zhǎng)。

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

          我分析原因可能是:在新的連接到來(lái),創(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
          說(shuō)明是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 云自無(wú)心水自閑 閱讀(9869) | 評(píng)論 (0)編輯 收藏

          主站蜘蛛池模板: 英超| 松原市| 道孚县| 隆德县| 威宁| 稻城县| 锡林浩特市| 聊城市| 乌拉特前旗| 苍山县| 阿图什市| 昭通市| 台安县| 綦江县| 贵州省| 肃宁县| 永春县| 丰县| 上犹县| 定远县| 嘉兴市| 苏州市| 承德县| 墨竹工卡县| 林芝县| 永登县| 鲁山县| 博爱县| 北票市| 瑞丽市| 贵溪市| 岫岩| 浙江省| 镇巴县| 辽阳县| 曲阜市| 彭山县| 朝阳区| 佳木斯市| 武隆县| 措勤县|