
2006年7月25日
1 基本介紹
可以說(shuō)CSV格式的文件經(jīng)常碰到,何為CSV格式,CVS全稱comma-separated values,就是典型的用逗號(hào)隔開(kāi)的文件,比如下面這種文件格式
Name,company
zhangsan,ibm
lisi,oracle
這種就是典型的CSV格式文件。不過(guò)也可以擴(kuò)展到其它符號(hào)隔開(kāi)的字符,比如
Name#company
Zhangsan#ibm
Lisi#oracle
這種也算CSV格式
Java開(kāi)源框架CVSReader提供了一個(gè)輕量級(jí)、簡(jiǎn)單方便的統(tǒng)一操作接口可用,下面具體講解如何操作CVS格式
2 安裝和使用
2.1下載
目前CSV reader的最新發(fā)布版本是1.8。我們可以從
http://opencsv.sourceforge.net/
上面下載到最新的csvreader包。
2.2安裝
直接把jar包分別存放到開(kāi)發(fā)工程的類路徑下面即可使用。
3 讀取CSV格式文件
3.1基本簡(jiǎn)介
首先,讀取CSV格式的文件需要?jiǎng)?chuàng)建一個(gè)CSVReader,如下
CsvReader reader = new CsvReader(Reader r, char c);
其中第一個(gè)參數(shù)為讀取文件,第二個(gè)參數(shù)為分割符,比如“,”,或者“#”
另外,也有其它幾個(gè)參數(shù),可以查閱API,比如
CsvReader reader = new CsvReader(InputStream r, char c, Charset charset);等等
其次,一般需要讀取頭信息,如下:
reader.readHeaders();
String[] headers = reader.getHeaders();
讀取了后,指針就會(huì)移動(dòng)到下一行,也就是可以開(kāi)始讀取文件內(nèi)容
假如,有多行的話,可以用一個(gè)循環(huán)套入,例如下面:
while (reader.readRecord()) {
for (int i = 0; i < headers.length; i++) {
String value = reader.get(headers[i]);
System.out.print(value+" ");
}
System.out.println("");
}
3.2綜合例子
在C盤下創(chuàng)建一個(gè)測(cè)試文件test.cvs,內(nèi)容如下:
a#b#c
1#2#3
4#5#6
下面是解析代碼:
public static void main(String[] args) throws Exception {
CsvReader reader = new CsvReader(new FileReader("c://csv.txt"), '#');
reader.readHeaders();
String[] headers = reader.getHeaders();
while (reader.readRecord()) {
for (int i = 0; i < headers.length; i++) {
String value = reader.get(headers[i]);
System.out.print(value+" ");
}
System.out.println("");
}
}
運(yùn)行以上程序,可以看到輸出
1 2 3
4 5 6
4 寫CSV格式文件
寫CSV格式文件也比較簡(jiǎn)單,寫每一列只要直接調(diào)用
csvWriter.write()即可
另外,寫完每行結(jié)束后,都要調(diào)用 csvWriter.endRecord();
表示結(jié)束一行
文件寫完畢后,要記得刷新一下并關(guān)掉,如下:
csvWriter.flush();
csvWriter.close();
代碼如下:
publicstaticvoid main(String[] args) throws Exception {
CsvWriter csvWriter = new CsvWriter(new FileWriter("c://test.text"), '#');
csvWriter.write("name");
csvWriter.write("company");
csvWriter.endRecord();
csvWriter.write("11");
csvWriter.write("12");
csvWriter.endRecord();
csvWriter.write("21");
csvWriter.write("22");
csvWriter.flush();
csvWriter.close();
}
}
運(yùn)行以上程序,可以看到C盤下面創(chuàng)建了一個(gè)文件
test.text
內(nèi)容如下:
name#company
11#12
21#22
posted @
2008-10-31 14:42 jspark 閱讀(11817) |
評(píng)論 (3) |
編輯 收藏
摘要: (本文檔的全篇可以到博客下面的文件列表下載,地址下面)
http://www.aygfsteel.com/jspark/admin/Files.aspx
為了讓盡快對(duì)jbossRules有一個(gè)感官的認(rèn)識(shí),下面先開(kāi)發(fā)一個(gè)HelloWorld的程序。
建立一個(gè)java工程,目錄如下:
如上所示,建立一個(gè)com包,然后在下面分別建立一個(gè)Sa...
閱讀全文
posted @
2008-10-28 15:54 jspark 閱讀(1638) |
評(píng)論 (0) |
編輯 收藏
1 Java規(guī)則系統(tǒng)簡(jiǎn)介
在大型商業(yè)系統(tǒng)中,業(yè)務(wù)規(guī)則、商業(yè)邏輯等等都會(huì)比較復(fù)雜。而且在很多大型系統(tǒng)當(dāng)中,很多業(yè)務(wù)規(guī)則、商業(yè)邏輯并不是一成不變的。甚至當(dāng)系統(tǒng)進(jìn)入生產(chǎn)階段時(shí),客戶的業(yè)務(wù)規(guī)則、商業(yè)邏輯也會(huì)改變。某些系統(tǒng)要求甚至更高,要求能24小時(shí)不停機(jī),并且能夠?qū)崟r(shí)修改商業(yè)規(guī)則。這就對(duì)商業(yè)系統(tǒng)提出了較大的挑戰(zhàn)。如果將這些可變的規(guī)則直接編寫到代碼里面的話,業(yè)務(wù)規(guī)則一旦改變,就要修改代碼。并由此帶來(lái)編譯、打包、發(fā)布等等問(wèn)題。這對(duì)于生產(chǎn)系統(tǒng)來(lái)說(shuō)是極不方便的。因此,如何考慮把一些可變的業(yè)務(wù)規(guī)則抽取到外面,使這些業(yè)務(wù)規(guī)則獨(dú)立于程序代碼。并最好是能夠?qū)崟r(shí)的修改業(yè)務(wù)規(guī)則,這樣就可以做到不用打包編譯發(fā)布等等。
值得慶幸的是現(xiàn)在出現(xiàn)了一些Java規(guī)則引擎(Rule Engine),專門解決以上所述的問(wèn)題。利用它,我們就可以在應(yīng)用系統(tǒng)中分離客戶的商業(yè)決策邏輯和應(yīng)用開(kāi)發(fā)者的技術(shù)決策,并把這些商業(yè)規(guī)額則放在中心數(shù)據(jù)庫(kù)或其他統(tǒng)一的地方,讓它們能在運(yùn)行時(shí)可以動(dòng)態(tài)地管理和修改。
JbossRules是一個(gè)優(yōu)秀的JAVA規(guī)則引擎,其前身是Drools3,后來(lái)被Jboss合并并改名為JbossRules
1.1基于規(guī)則的專家系統(tǒng)簡(jiǎn)介
人工智能是一個(gè)新興的學(xué)科,它是想讓計(jì)算機(jī)模擬人腦的思維和推理模式。人工智能分成如下幾個(gè)主要的分學(xué)科:
知識(shí)表示
神經(jīng)網(wǎng)絡(luò)
基因算法
決策樹(shù)
專家系統(tǒng)
等等幾個(gè)學(xué)科
知識(shí)表示是人工智能中的一個(gè)基礎(chǔ)領(lǐng)域,其目的是如何更好的在計(jì)算機(jī)當(dāng)中描述已存在的事實(shí)。專家系統(tǒng)就是使用知識(shí)表示,來(lái)做規(guī)則推理,得出最后的結(jié)論來(lái)。
Java規(guī)則引擎起源于基于規(guī)則的專家系統(tǒng),而基于規(guī)則的專家系統(tǒng)又是專家系統(tǒng)的其中一個(gè)分支。專家系統(tǒng)屬于人工智能的范疇,它模仿人類的推理方式,使用試探性的方法進(jìn)行推理,并使用人類能理解的術(shù)語(yǔ)解釋和證明它的推理結(jié)論。為了更深入地了解Java規(guī)則引擎,下面簡(jiǎn)要地介紹基于規(guī)則的專家系統(tǒng)。RBES包括三部分:Rule Base(knowledge base)、Working Memory(fact base)和Inference Engine。它們的結(jié)構(gòu)如下系統(tǒng)所示:
如上圖所示,推理引擎包括三部分:模式匹配器(Pattern Matcher)、議程(Agenda)和執(zhí)行引擎(Execution Engine)。推理引擎通過(guò)決定哪些規(guī)則滿足事實(shí)或目標(biāo),并授予規(guī)則優(yōu)先級(jí),滿足事實(shí)或目標(biāo)的規(guī)則被加入議程。模式匹配器決定選擇執(zhí)行哪個(gè)規(guī)則,何時(shí)執(zhí)行規(guī)則;議程管理模式匹配器挑選出來(lái)的規(guī)則的執(zhí)行次序;執(zhí)行引擎負(fù)責(zé)執(zhí)行規(guī)則和其他動(dòng)作。
和人類的思維相對(duì)應(yīng),推理引擎存在兩者推理方式:演繹法(Forward-Chaining)和歸納法(Backward-Chaining)。演繹法從一個(gè)初始的事實(shí)出發(fā),不斷地應(yīng)用規(guī)則得出結(jié)論(或執(zhí)行指定的動(dòng)作)。而歸納法則是根據(jù)假設(shè),不斷地尋找符合假設(shè)的事實(shí)。Rete算法是目前效率最高的一個(gè)Forward-Chaining推理算法,許多Java規(guī)則引擎都是基于Rete算法來(lái)進(jìn)行推理計(jì)算的。
l 正向推理:
正向推理圖形如下:
正向推理引擎的推理步驟如下:
n 將初始數(shù)據(jù)(fact)輸入Working Memory。
n 使用Pattern Matcher比較規(guī)則庫(kù)(rule base)中的規(guī)則(rule)和數(shù)據(jù)(fact)。
n 如果執(zhí)行規(guī)則存在沖突(conflict),即同時(shí)激活了多個(gè)規(guī)則,將沖突的規(guī)則放入沖突集合。
n 解決沖突,將激活的規(guī)則按順序放入Agenda。
n 使用執(zhí)行引擎執(zhí)行Agenda中的規(guī)則。重復(fù)步驟2至5,直到執(zhí)行完畢所有Agenda中的規(guī)則。
n 直到得出最終的結(jié)果為止
l 反向推理:
反向推理是目標(biāo)驅(qū)動(dòng)的推理方式。從目標(biāo)出發(fā),找出所有能滿足該目
標(biāo)的子目標(biāo)。這樣一直推導(dǎo)下去,直到所有的子目標(biāo)都已經(jīng)滿足為止。
1.2Java規(guī)則引擎
Java規(guī)則引擎是一種嵌入在Java程序中的組件,它的任務(wù)是把當(dāng)前提交給引擎的Java數(shù)據(jù)對(duì)象與加載在引擎中的業(yè)務(wù)規(guī)則進(jìn)行測(cè)試和比對(duì),激活那些符合當(dāng)前數(shù)據(jù)狀態(tài)下的業(yè)務(wù)規(guī)則,根據(jù)業(yè)務(wù)規(guī)則中聲明的執(zhí)行邏輯,觸發(fā)應(yīng)用程序中對(duì)應(yīng)的操作。
一般來(lái)說(shuō),一條規(guī)則的形式如下:
when
<conditions>
then
<actions>
也就是說(shuō),當(dāng)conditions成立的話,就做下面的actions。其中actions可以為生成新的事實(shí)、或者做其他動(dòng)作,比如,發(fā)送email通知、執(zhí)行一些本地任務(wù)等等。
1.3 JAVA規(guī)則引擎的優(yōu)點(diǎn)
n 聲明式編程
聲明式編程,規(guī)則引擎讓我們直到“做什么”,而不用直到“怎么做”。我們只要把一系列規(guī)則表示出來(lái)后。具體的推理動(dòng)作就交給規(guī)則引擎來(lái)處理。
n 邏輯和數(shù)據(jù)分開(kāi)
將可變的業(yè)務(wù)邏輯和數(shù)據(jù)分開(kāi)。雖然,這違背了面向?qū)ο笤瓌t。面向?qū)ο髲?qiáng)調(diào)數(shù)據(jù)和業(yè)務(wù)邏輯耦合。但是,對(duì)于一些易變而復(fù)雜的業(yè)務(wù)規(guī)則。如果散步在程序的各個(gè)地方、各個(gè)層次。那么一旦業(yè)務(wù)規(guī)則更改的話,就會(huì)出現(xiàn)“牽一發(fā)而動(dòng)全身”的局面。因此,將可變的業(yè)務(wù)邏輯獨(dú)立出來(lái)管理,將有助于后面的業(yè)務(wù)變更。
n 性能
Rete算法的性能比較高。
n 知識(shí)集中表示
通過(guò)使用規(guī)則,我們把規(guī)則集中存放起來(lái),從而使系統(tǒng)知識(shí)能夠集中表示。
n 可讀性
規(guī)則的可讀性比較高。對(duì)于熟悉業(yè)務(wù)規(guī)則。但不會(huì)程序開(kāi)發(fā)的業(yè)務(wù)專家,只要熟悉規(guī)則的標(biāo)示,也可以編寫和修改業(yè)務(wù)規(guī)則。
1.4 使用JAVA規(guī)則系統(tǒng)的場(chǎng)合
那么,在那些場(chǎng)合下適合應(yīng)用JAVA規(guī)則系統(tǒng)呢?總而言之,可以用一句話來(lái)概括:當(dāng)用傳統(tǒng)的程序開(kāi)發(fā),無(wú)法得到一種優(yōu)雅的解決方法的時(shí)候,就可以考慮使用規(guī)則系統(tǒng)。如下的一些場(chǎng)合:
n 用傳統(tǒng)的代碼開(kāi)發(fā)比較復(fù)雜、繁瑣
n 問(wèn)題雖然不復(fù)雜,但是用傳統(tǒng)的代碼開(kāi)發(fā)比較脆弱,也就是經(jīng)常修改
n 沒(méi)有優(yōu)雅的算法
n 業(yè)務(wù)規(guī)則頻繁改變
n 有很多業(yè)務(wù)專家、不懂技術(shù)開(kāi)發(fā)
1.5 不適合使用JAVA規(guī)則系統(tǒng)場(chǎng)合
雖然規(guī)則系統(tǒng)看起來(lái)比較不錯(cuò),但是并不是任何地方都可以使用規(guī)則系統(tǒng)。很多簡(jiǎn)單、固定的業(yè)務(wù)系統(tǒng),可以不用使用規(guī)則系統(tǒng)。規(guī)則系統(tǒng)也不能用來(lái)作為標(biāo)示重要的業(yè)務(wù)流程、不能用來(lái)作為工作流引擎。
有很多程序員把JAVA規(guī)則系統(tǒng)當(dāng)成是一種動(dòng)態(tài)修改配置。也就是把一部分代碼邏輯抽取到外面,統(tǒng)一存放起來(lái)。這樣,當(dāng)一些配置修改的話,通過(guò)修改規(guī)則,就能修改代碼的一部分邏輯。如果把JAVA規(guī)則僅僅用在這個(gè)場(chǎng)合下的話,可以考慮采用腳本引擎。比如BeanShell、JEXL、Groovy等等。
posted @
2008-10-28 12:15 jspark 閱讀(1566) |
評(píng)論 (1) |
編輯 收藏
grant {
permission java.lang.RuntimePermission "loadLibrary.*";
permission java.lang.RuntimePermission "queuePrintJob";
permission java.lang.RuntimePermission "setContextClassLoader";
permission java.lang.RuntimePermission "getProtectionDomain";
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};
grant {
permission java.util.PropertyPermission "*" , " read,write " ;
};
最近一個(gè)項(xiàng)目需要用到SUN ONE APPSERVER8.1,本人在WINDOWS SERVER 2003中安裝,碰到一些問(wèn)題,不過(guò)比較幸運(yùn)的是都解決了,下面大概描述一下個(gè)人碰到的問(wèn)題,期望能給別人帶來(lái)幫助
一、DNS服務(wù)器問(wèn)題
安裝SUN ONE APPSERVER8.1必須要在服務(wù)器上安裝,而且必須要將該服務(wù)器設(shè)置為DNS服務(wù)器。關(guān)于WINDOWS SERVER 2003
如何設(shè)置DNS服務(wù)器,網(wǎng)上很多資料,可以查閱
二、文件系統(tǒng)權(quán)限訪問(wèn)問(wèn)題
也許SUN ONE APPSERVER8.1服務(wù)器在文件訪問(wèn)方面控制比較嚴(yán)格,如果按照默認(rèn)安裝上去的系統(tǒng)。對(duì)于一些文件夾、文件讀取是會(huì)有一些控制的。比如說(shuō),當(dāng)將應(yīng)用部署上去,然后訪問(wèn)應(yīng)用,會(huì)拋出SecurityException。這是因?yàn)樾枰幾gjsp頁(yè)面,生成class文件,由于沒(méi)有寫權(quán)限,所以會(huì)出錯(cuò)。解決的方法是為SUN ONE APPSERVER增加文件訪問(wèn)權(quán)限。修改方法如下:
找到安裝路徑,下面以本人的安裝路徑為例子:
c\sunjes\ApplicationServer\domains\domain1\config
該目錄下面有一個(gè)文件叫server.policy,打開(kāi)該頁(yè)面,可以看到里面是一些關(guān)于文件訪問(wèn)權(quán)限的例子

// Core server classes get all permissions by default
grant codeBase " file:${com.sun.aas.installRoot}/lib/- " {
permission java.security.AllPermission;
};

下面為文件路徑增加訪問(wèn)權(quán)限,個(gè)人把整個(gè)c盤設(shè)置為可讀可寫,如下
grant codeBase " file:c:/- " {
permission java.security.AllPermission;
};
grant {
permission java.io.FilePermission " c:/- " , " read,write,execute,delete " ;
};
編輯完畢,保存,重啟服務(wù)器,OK,該問(wèn)題解決。 :)
三、其他幾個(gè)權(quán)限問(wèn)題:
編輯以上問(wèn)題后,重新自動(dòng),可能還會(huì)發(fā)現(xiàn)以下幾個(gè)異常,比如 permission java.util.PropertyPermission "*" , " read,write " ;
因此,分別加上如下幾個(gè)權(quán)限設(shè)置即可
四、ORACLE10.2.0.1驅(qū)動(dòng)問(wèn)題
本人部署的應(yīng)用是spring+hb架構(gòu),里面用到blog/clob大字段處理,因此驅(qū)動(dòng)程序用最新的驅(qū)動(dòng)程序10g,版本為10.2.0.1。在部署到SUN ONE APPSERVER8.1時(shí),也拋出類訪問(wèn)異常,異常信息是:oracle.sql is sealed。沒(méi)辦法,上網(wǎng)搜索了一下,發(fā)現(xiàn)有很多人也遇過(guò)這個(gè)情況。主要是oracle10g.jar里面的Meta-inf定義,增加了sealed屬性。打開(kāi)該文件MANIFEST.MF,內(nèi)容如下:
Manifest - Version: 1.0
Specification - Title: Oracle JDBC driver classes for use with JDK14
Created - By: 1.4 .2_08 (Sun Microsystems Inc.)
sealed: true
Implementation - Title: ojdbc14.jar
Specification - Vendor: Oracle Corporation
Specification - Version: Oracle JDBC Driver version - " 10.2.0.1.0 "
Implementation - Version: Oracle JDBC Driver version - " 10.2.0.1.0 "
Implementation - Vendor: Oracle Corporation
Implementation - Time: Wed Jun 22 18 : 55 : 48 2005
關(guān)于sealed屬性網(wǎng)上也有
很多資料介紹,有興趣的網(wǎng)友可以參閱一下。網(wǎng)上同行的解決方法是下載10g,低點(diǎn)的版本。本人的解決方法是修改一下里面的MANIFEST.MF文件,把sealed:true去掉即可。
四、包版本不兼容。
解決完以上幾個(gè)問(wèn)題后,重新啟動(dòng),本以為萬(wàn)事大吉,很不幸運(yùn)的是,再次拋出異常:
ClassNotFoundException: org.hibernate.hql.ast.HqlToken。同樣,上網(wǎng)搜索了一下,發(fā)現(xiàn)是hibernate的antlr.jar和SUN ONE APPSERVER的antlr.jar存在沖突。hibernate3.0版本用
的antlr.jar包版本是2.7.5,比SUN ONE APPSERVER的高。以前在weblogic部署應(yīng)用時(shí),也出現(xiàn)過(guò)類似的問(wèn)題。由于這些服務(wù)器會(huì)優(yōu)先裝載自己的類,因此會(huì)出現(xiàn)一些問(wèn)題。解決方法是把hibernate下較高版本的antlr.jar放在classpath的前面。在SUN ONE APPSERVER
下最快捷的方式就是將antlr-2.7.5H3.jar拷貝到ApplicationServer\lib目錄下面即可
解決完以上幾個(gè)問(wèn)題后,再次重啟,訪問(wèn),OK,一切正常!好有成就感 :)
posted @
2006-11-29 14:42 jspark 閱讀(1698) |
評(píng)論 (1) |
編輯 收藏
Sun HotSpot 1.4.1 JVM堆大小的調(diào)整
????
????Sun HotSpot 1.4.1使用分代收集器,它把堆分為三個(gè)主要的域:新域、舊域以及永久域。Jvm生成的所有新對(duì)象放在新域中。一旦對(duì)象經(jīng)歷了一定數(shù)量的垃圾收集循環(huán)后,便獲得使用期并進(jìn)入舊域。在永久域中jvm則存儲(chǔ)class和method對(duì)象。就配置而言,永久域是一個(gè)獨(dú)立域并且不認(rèn)為是堆的一部分。
????下面介紹如何控制這些域的大小。可使用-Xms和-Xmx 控制整個(gè)堆的原始大小或最大值。
????下面的命令是把初始大小設(shè)置為128M:
????
java –Xms128m???? –Xmx256m為控制新域的大小,可使用-XX:NewRatio設(shè)置新域在堆中所占的比例。
?? 下面的命令把整個(gè)堆設(shè)置成128m,新域比率設(shè)置成3,即新域與舊域比例為1:3,新域?yàn)槎训?/4或32M:
??
java –Xms128m –Xmx128m????–XX:NewRatio =3可使用-XX:NewSize和-XX:MaxNewsize設(shè)置新域的初始值和最大值。
?? 下面的命令把新域的初始值和最大值設(shè)置成64m:
????
java –Xms256m –Xmx256m –Xmn64m?? 永久域默認(rèn)大小為4m。運(yùn)行程序時(shí),jvm會(huì)調(diào)整永久域的大小以滿足需要。每次調(diào)整時(shí),jvm會(huì)對(duì)堆進(jìn)行一次完全的垃圾收集。
?? 使用-XX:MaxPerSize標(biāo)志來(lái)增加永久域搭大小。在WebLogic Server應(yīng)用程序加載較多類時(shí),經(jīng)常需要增加永久域的最大值。當(dāng)jvm加載類時(shí),永久域中的對(duì)象急劇增加,從而使jvm不斷調(diào)整永久域大小。為了避免調(diào)整,可使用-XX:PerSize標(biāo)志設(shè)置初始值。
?? 下面把永久域初始值設(shè)置成32m,最大值設(shè)置成64m。
????
java -Xms512m -Xmx512m -Xmn128m -XX:PermSize=32m -XX:MaxPermSize=64m????默認(rèn)狀態(tài)下,HotSpot在新域中使用復(fù)制收集器。該域一般分為三個(gè)部分。第一部分為Eden,用于生成新的對(duì)象。另兩部分稱為救助空間,當(dāng)Eden充滿時(shí),收集器停止應(yīng)用程序,把所有可到達(dá)對(duì)象復(fù)制到當(dāng)前的from救助空間,一旦當(dāng)前的from救助空間充滿,收集器則把可到達(dá)對(duì)象復(fù)制到當(dāng)前的to救助空間。From和to救助空間互換角色。維持活動(dòng)的對(duì)象將在救助空間不斷復(fù)制,直到它們獲得使用期并轉(zhuǎn)入舊域。使用-XX:SurvivorRatio可控制新域子空間的大小。
????同NewRation一樣,SurvivorRation規(guī)定某救助域與Eden空間的比值。比如,以下命令把新域設(shè)置成64m,Eden占32m,每個(gè)救助域各占16m:
????
java -Xms256m -Xmx256m -Xmn64m -XX:SurvivorRation =2????如前所述,默認(rèn)狀態(tài)下HotSpot對(duì)新域使用復(fù)制收集器,對(duì)舊域使用標(biāo)記-清除-壓縮收集器。在新域中使用復(fù)制收集器有很多意義,因?yàn)閼?yīng)用程序生成的大部分對(duì)象是短壽命的。理想狀態(tài)下,所有過(guò)渡對(duì)象在移出Eden空間時(shí)將被收集。如果能夠這樣的話,并且移出Eden空間的對(duì)象是長(zhǎng)壽命的,那么理論上可以立即把它們移進(jìn)舊域,避免在救助空間反復(fù)復(fù)制。但是,應(yīng)用程序不能適合這種理想狀態(tài),因?yàn)樗鼈冇幸恍〔糠种虚L(zhǎng)壽命的對(duì)象。最好是保持這些中長(zhǎng)壽命的對(duì)象并放在新域中,因?yàn)閺?fù)制小部分的對(duì)象總比壓縮舊域廉價(jià)。為控制新域中對(duì)象的復(fù)制,可用-XX:TargetSurvivorRatio控制救助空間的比例(該值是設(shè)置救助空間的使用比例。如救助空間位1M,該值50表示可用500K)。該值是一個(gè)百分比,默認(rèn)值是50。當(dāng)較大的堆棧使用較低的sruvivorratio時(shí),應(yīng)增加該值到80至90,以更好利用救助空間。用-XX:maxtenuring threshold可控制上限。
?? 為放置所有的復(fù)制全部發(fā)生以及希望對(duì)象從eden擴(kuò)展到舊域,可以把MaxTenuring Threshold設(shè)置成0。設(shè)置完成后,實(shí)際上就不再使用救助空間了,因此應(yīng)把SurvivorRatio設(shè)成最大值以最大化Eden空間,設(shè)置如下:
??
java … -XX:MaxTenuringThreshold=0 –XX:SurvivorRatio=50000 …
Assigning the target property requires the name of a window not the window itself.
Wecould try something like
window.opener.name="opener728";
form.target="opener728";
however, I suspect the window.name property is read-only.
Alternatively, if We are certain that the opener already has a name then this might work
form.target=window.opener.name;
It's also possible that browsers assign unique names to otherwise unnamed windows, so the above would always work - I've never checked this.
今天從網(wǎng)上找了一個(gè)讀寫csv格式的開(kāi)源程序,還挺好用的。
下面是一個(gè)讀取例子:
源文件格式:
?ProductID,ProductName,SupplierID,CategoryID,QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,ReorderLevel,Discontinued
?1,Chai,1,1,10 boxes x 20 bags,18,39,0,10,FALSE
?2,Chang,1,1,24 - 12 oz bottles,19,17,40,25,FALSE
?下面讀取程序
?
?CsvReader?reader?
=
?
new
?CsvReader(
"
products.csv
"
);

?reader.readHeaders();

?
while
?(reader.readRecord())

?
{
??String?productID?
=
?reader.get(
"
ProductID
"
);
??String?productName?
=
?reader.get(
"
ProductName
"
);
??String?supplierID?
=
?reader.get(
"
SupplierID
"
);
??String?categoryID?
=
?reader.get(
"
CategoryID
"
);
??String?quantityPerUnit?
=
?reader.get(
"
QuantityPerUnit
"
);
??String?unitPrice?
=
?reader.get(
"
UnitPrice
"
);
??String?unitsInStock?
=
?reader.get(
"
UnitsInStock
"
);
??String?unitsOnOrder?
=
?reader.get(
"
UnitsOnOrder
"
);
??String?reorderLevel?
=
?reader.get(
"
ReorderLevel
"
);
??String?discontinued?
=
?reader.get(
"
Discontinued
"
);
??
??
//
?perform?program?logic?here
?}
?reader.close();
寫CSV例子:
?CsvWriter writer = new CsvWriter(new FileWriter(new File("c:\\1.csv")),',');
??writer.write("aa");
??writer.write("bb");
??writer.write("cc");
??writer.endRecord();
??writer.write("1");
??writer.write("2");
??writer.write("3");
??writer.close();
posted @
2006-11-07 12:05 jspark 閱讀(6569) |
評(píng)論 (0) |
編輯 收藏
在spring中如何處理oracle大字段
在spring中采用OracleLobHandler來(lái)處理oracle大字段(包括clob和blob),則在程序中不需要引用oracle的特殊類,從而能夠保證支持我們的代碼支持多數(shù)據(jù)庫(kù)。
1、首先數(shù)據(jù)表中的clob類型對(duì)應(yīng)java持久化類的String類型;而blob類型對(duì)應(yīng)byte[]類型 2、定義hibernate標(biāo)簽時(shí),持久化類中對(duì)應(yīng)clob類型的屬性的hibernate type應(yīng)為org.springframework.orm.hibernate.support.ClobStringType;而對(duì)應(yīng)blob類型的屬性的hibernate type應(yīng)為org.springframework.orm.hibernate.support.BlobByteArrayType。 3、以后訪問(wèn)這些對(duì)應(yīng)clob和blob類型的屬性時(shí),按普通屬性處理,不需要特別編碼。
java代碼:?
|
<
bean?
id
="mySessionFactory2"
?class
="org.springframework.orm.hibernate.LocalSessionFactoryBean"
>
?
????????
<
property?
name
="dataSource"
>
?
????????????????
<
ref?
bean
="myDataSource2"
/>
?
?????????
</
property
>
?
?????????
<
property?
name
="lobHandler"
>
?
????????
<
ref?
bean
="oracleLobHandle"
/>
?
?????????
</
property
>
??
</
bean
>
?
<
bean?
id
="nativeJdbcExtractor"
?class
="org.springframework.jdbc.support.nativejdbc.SimpleNativeJdbcExtractor"
/>
?

<
bean?
id
="oracleLobHandle"
?class
="org.springframework.jdbc.support.lob.OracleLobHandler"
?Lazy-init
="true"
>
?
<
property?
name
="nativeJdbcExtractor"
>
?
????
<
ref?
local
="nativejdbcExtractor"
/>
?
</
property
>
?
</
bean
>
|
Spring為處理數(shù)據(jù)庫(kù)Lob字段,特別提供了LobHandler接口。在操作Oracle RDBMS過(guò)程中,由于Oracle JDBC Driver實(shí)現(xiàn)的問(wèn)題,應(yīng)用必須采用Oracle原生的數(shù)據(jù)庫(kù)連接(比如,oracle.jdbc.OracleConnection)、LOB原生實(shí)現(xiàn)(比如,oracle.sql.BLOB、oracle.sql.CLOB)。因此,LobHandler接口存在上述兩種實(shí)現(xiàn)。簡(jiǎn)而言之,為操作Oracle數(shù)據(jù)庫(kù),必須使用OracleLobHandler實(shí)現(xiàn)。如果操作其他RDBMS類型,則使用DefaultLobHandler。NativeJdbcExtractor是個(gè)接口,通過(guò)它能夠抽象各種連接池。另外Spring還提供兩個(gè)接口存取Blob,LobCreator及LobHandler
?? jdk提供的正則表達(dá)式是非常強(qiáng)大的,只要用過(guò)正則表達(dá)式的程序員應(yīng)該是為其功能嘆為觀止。不過(guò),正則表達(dá)式中的一個(gè)group概念相信應(yīng)該不多人熟悉。
??? 正則表達(dá)式中的group,主要是用來(lái)區(qū)分子序列的,所謂子序列是用()之內(nèi)的表達(dá)式。下面以一段程序?yàn)槔?br />
????????String?regex?=?"\\$\\{(I)(love)(java)\\}";
????????System.out.println(Pattern.compile(regex).matcher("${Ilovejava}P)").groupCount());
?運(yùn)行上面的代碼段,結(jié)果為:3
?其中(I)為一個(gè)組, (love)為一個(gè)組,(java)為一個(gè)組。
??
? 也許有人覺(jué)得這只是一個(gè)小功能,但是正則表達(dá)式的group,還有一個(gè)更加強(qiáng)大的地方就是在String.replaceAll方法中。
? public
StringreplaceAll(
String?regex,
????????????????????????
String?replacement)
?其中第一個(gè)參數(shù)當(dāng)然是政則表達(dá)式,第二個(gè)一般是普通的文本;但是第二個(gè)參數(shù)可以應(yīng)用group的地方,這個(gè)功能用在一些場(chǎng)合是非常方便的。
??????比如,下面這個(gè)例子? <driverClass>${driverClass}</driverClass>,要將${}去掉,即將這個(gè)例子替換成<driverClass>driverClass</driverClass>,可以用下面的代碼來(lái)替換。例如
????????String?text?=?"<driverClass>${driverClass}</driverClass>";
????????String?result?=?replaceStr(text,"\\$\\{(driverClass)\\}","$1");
????????System.out.println("result?is:"+result);?? 運(yùn)行結(jié)果:result is:<driverClass>driverClass</driverClass>
? 從上面可以看出,$1就是正則表達(dá)式中匹配的第一個(gè)序列,同樣$2...表示第幾個(gè)序列。如果$index中的index超出了表達(dá)式中子序列的個(gè)數(shù)的話,將拋出異常信息。 $0表示整個(gè)正則表達(dá)式。
在tomcat5.5版本以前,可以說(shuō)jndi配置相對(duì)是比較復(fù)雜的,而且據(jù)網(wǎng)友說(shuō)用tomcat5.0的控制臺(tái)配置數(shù)據(jù)庫(kù)連接池經(jīng)常有問(wèn)題,而且文檔寫得又不詳細(xì)。
tomcat5.5出來(lái)后,jndi的配置方法是大大地節(jié)省,而且很簡(jiǎn)潔,個(gè)人覺(jué)得比以前的版本好很多。這里大概給出一個(gè)配置例子。tomcat數(shù)據(jù)庫(kù)連接池jndi配置有兩種,一種是全局的,一種是context的,下面主要是講全局的,并且以一個(gè)實(shí)例jdbc/byisdb為例子
???
一、tomcat5.0配置方法
1、首先在server.xml里面配置,找到下面的配置
? <!-- Global JNDI resources -->
? <GlobalNamingResources>
?</GlobalNamingResources>
2、在里面增加一個(gè)Resource
??????<Resource?name="jdbc/byisdb"
???????????????auth="Container"
???????????????type="javax.sql.DataSource"/>3、在下面增加屬性
??<ResourceParams?name="jdbc/byisdb">
????<parameter>
??????<name>factory</name>
??????<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
????</parameter>

????<!--?Maximum?number?of?dB?connections?in?pool.?Make?sure?you
?????????configure?your?mysqld?max_connections?large?enough?to?handle
?????????all?of?your?db?connections.?Set?to?0?for?no?limit.
?????????-->
????<parameter>
??????<name>maxActive</name>
??????<value>100</value>
????</parameter>

????<!--?Maximum?number?of?idle?dB?connections?to?retain?in?pool.
?????????Set?to?-1?for?no?limit.??See?also?the?DBCP?documentation?on?this
?????????and?the?minEvictableIdleTimeMillis?configuration?parameter.
?????????-->
????<parameter>
??????<name>maxIdle</name>
??????<value>30</value>
????</parameter>

????<!--?Maximum?time?to?wait?for?a?dB?connection?to?become?available
?????????in?ms,?in?this?example?10?seconds.?An?Exception?is?thrown?if
?????????this?timeout?is?exceeded.??Set?to?-1?to?wait?indefinitely.
?????????-->
????<parameter>
??????<name>maxWait</name>
??????<value>10000</value>
????</parameter>

????<!--?MySQL?dB?username?and?password?for?dB?connections??-->
????<parameter>
?????<name>username</name>
?????<value>una_oa</value>
????</parameter>
????<parameter>
?????<name>password</name>
?????<value>una_oa</value>
????</parameter>

????<!--?Class?name?for?the?old?mm.mysql?JDBC?driver?-?uncomment?this?entry?and?comment?next
?????????if?you?want?to?use?this?driver?-?we?recommend?using?Connector/J?though
????<parameter>
???????<name>driverClassName</name>
???????<value>org.gjt.mm.mysql.Driver</value>
????</parameter>
?????-->
????
????<!--?Class?name?for?the?official?MySQL?Connector/J?driver?-->
????<parameter>
???????<name>driverClassName</name>
???????<value>oracle.jdbc.driver.OracleDriver</value>
????</parameter>
????
????<!--?The?JDBC?connection?url?for?connecting?to?your?MySQL?dB.
?????????The?autoReconnect=true?argument?to?the?url?makes?sure?that?the
?????????mm.mysql?JDBC?Driver?will?automatically?reconnect?if?mysqld?closed?the
?????????connection.??mysqld?by?default?closes?idle?connections?after?8?hours.
?????????-->
????<parameter>
??????<name>url</name>
??????<value>jdbc:oracle:thin:@192.168.1.210:1521:byisdb</value>
????</parameter>
??</ResourceParams>4、在你的應(yīng)用的web.xml里面增加
<resource-ref>
?<description>postgreSQL?Datasource?example</description>
?<res-ref-name>jdbc/byisdb</res-ref-name>
?<res-type>javax.sql.DataSource</res-type>
?<res-auth>Container</res-auth>
</resource-ref>OK,到此配置完畢,可以用下面的幾段代碼進(jìn)行測(cè)試
Context?initContext?=?new?InitialContext();
Context?envContext??=?(Context)initContext.lookup("java:/comp/env");
DataSource?ds?=?(DataSource)envContext.lookup("jdbc/byisdb");
Connection?conn?=?ds.getConnection();
out.println("conn?is:"+conn);二、tomcat5.5配置
1、打開(kāi)conf/context.xml里面
? 添加下面的配置
????<Resource?name="jdbc/byisdb"?auth="Container"?type="javax.sql.DataSource"?driverClassName="oracle.jdbc.driver.OracleDriver"?url="jdbc:oracle:thin:@192.168.1.210:1521:byisdb"?username="una_oa"?password="una_oa"?maxActive="20"?maxIdle="10"?maxWait="10000"/>?
2在你的應(yīng)用的web.xml里面增加
<resource-ref>
?<description>postgreSQL?Datasource?example</description>
?<res-ref-name>jdbc/byisdb</res-ref-name>
?<res-type>javax.sql.DataSource</res-type>
?<res-auth>Container</res-auth>
</resource-ref>同樣,可以用上面的代碼進(jìn)行測(cè)試。
posted @
2006-08-11 14:03 jspark 閱讀(2954) |
評(píng)論 (1) |
編輯 收藏
?最近由于需要用到ThreadLocal,在網(wǎng)上搜索了一些相關(guān)資料,發(fā)現(xiàn)對(duì)ThreadLocal經(jīng)常會(huì)有下面幾種誤解
?一、ThreadLocal是java線程的一個(gè)實(shí)現(xiàn)
????? ThreadLocal的確是和java線程有關(guān),不過(guò)它并不是java線程的一個(gè)實(shí)現(xiàn),它只是用來(lái)維護(hù)本地變量。針對(duì)每個(gè)線程,提供自己的變量版本,主要是為了避免線程沖突,每個(gè)線程維護(hù)自己的版本。彼此獨(dú)立,修改不會(huì)影響到對(duì)方。
?二、ThreadLocal是相對(duì)于每個(gè)session的
??????? ThreadLocal顧名思義,是針對(duì)線程。在java web編程上,每個(gè)用戶從開(kāi)始到會(huì)話結(jié)束,都有自己的一個(gè)session標(biāo)識(shí)。但是ThreadLocal并不是在會(huì)話層上。其實(shí),Threadlocal是獨(dú)立于用戶session的。它是一種服務(wù)器端行為,當(dāng)服務(wù)器每生成一個(gè)新的線程時(shí),就會(huì)維護(hù)自己的ThreadLocal。對(duì)于這個(gè)誤解,個(gè)人認(rèn)為應(yīng)該是開(kāi)發(fā)人員在本地基于一些應(yīng)用服務(wù)器測(cè)試的結(jié)果。眾所周知,一般的應(yīng)用服務(wù)器都會(huì)維護(hù)一套線程池,也就是說(shuō),對(duì)于每次訪問(wèn),并不一定就新生成一個(gè)線程。而是自己有一個(gè)線程緩存池。對(duì)于訪問(wèn),先從緩存池里面找到已有的線程,如果已經(jīng)用光,才去新生成新的線程。所以,由于開(kāi)發(fā)人員自己在測(cè)試時(shí),一般只有他自己在測(cè),這樣服務(wù)器的負(fù)擔(dān)很小,這樣導(dǎo)致每次訪問(wèn)可能是共用同樣一個(gè)線程,導(dǎo)致會(huì)有這樣的誤解:每個(gè)session有一個(gè)ThreadLocal
?三、ThreadLocal是相對(duì)于每個(gè)線程的,用戶每次訪問(wèn)會(huì)有新的ThreadLocal
??理論上來(lái)說(shuō),ThreadLocal是的確是相對(duì)于每個(gè)線程,每個(gè)線程會(huì)有自己的ThreadLocal。但是上面已經(jīng)講到,一般的應(yīng)用服務(wù)器都會(huì)維護(hù)一套線程池。因此,不同用戶訪問(wèn),可能會(huì)接受到同樣的線程。因此,在做基于TheadLocal時(shí),需要謹(jǐn)慎,避免出現(xiàn)ThreadLocal變量的緩存,導(dǎo)致其他線程訪問(wèn)到本線程變量
?四、對(duì)每個(gè)用戶訪問(wèn),ThreadLocal可以多用
??????? 可以說(shuō),ThreadLocal是一把雙刃劍,用得來(lái)的話可以起到非常好的效果。但是,ThreadLocal如果用得不好,就會(huì)跟全局變量一樣。代碼不能重用,不能獨(dú)立測(cè)試。因?yàn)椋恍┍緛?lái)可以重用的類,現(xiàn)在依賴于ThreadLocal變量。如果在其他沒(méi)有ThreadLocal場(chǎng)合,這些類就變得不可用了。個(gè)人覺(jué)得ThreadLocal用得很好的幾個(gè)應(yīng)用場(chǎng)合,值得參考
??1、存放當(dāng)前session用戶:quake want的jert
??2、存放一些context變量,比如webwork的ActionContext
??3、存放session,比如Spring hibernate orm的session
posted @
2006-08-01 12:09 jspark 閱讀(30763) |
評(píng)論 (12) |
編輯 收藏
?????? 說(shuō)真的,對(duì)于spring提供AOP的功能,個(gè)人實(shí)在不敢太過(guò)于恭維。主要是Spring的AOP功能沒(méi)那么強(qiáng)大,而且必須是對(duì)于spring容器管理的bean才能實(shí)施AOP功能,對(duì)于容器外的bean就無(wú)能為力了。而且spring沒(méi)有提供屬性的AOP功能。在這些方面,spring AOP真的不能和Aspectj相比。Aspectj的AOP功能才真的是真正意義的AOP框架,提供的功能非常強(qiáng)大,幾乎可以實(shí)現(xiàn)任何類型的AOP。不過(guò)Aspectj的學(xué)習(xí)曲線相對(duì)要比spring AOP稍微陡峭一點(diǎn),主要是spring AOP可以當(dāng)成普通javabean來(lái)處理,而Aspectj還要另外做編譯器,比較麻煩。不過(guò),慶幸的是,eclipse下面有Aspectj插件,開(kāi)發(fā)起來(lái)也是很方便。所以一般,復(fù)雜的AOP功能,還是推薦用Aspectj
???? 對(duì)于一般的J2EE開(kāi)發(fā)來(lái)說(shuō),要實(shí)現(xiàn)一些比較常用的AOP,Spring 還是能滿足的。比如事務(wù)、異常、日志、權(quán)限等等,在這些方面,spring AOP還是比較方便的,特別是事務(wù)處理,spring提供了相當(dāng)好的集成。如果事務(wù)處理用Aspectj來(lái)實(shí)現(xiàn),不見(jiàn)得好多少。
??? 一直以來(lái),覺(jué)得spring AOP最好用的一個(gè)地方就是提供了BeanNameAutoProxyCreator,這個(gè)類真的非常方便,以至于個(gè)人一旦遇到要實(shí)現(xiàn)AOP,首先就是求組于BeanNameAutoProxyCreator,如果BeanNameAutoProxyCreator實(shí)現(xiàn)不了,再考慮別的。不過(guò),一般情況來(lái)說(shuō),BeanNameAutoProxyCreator的確能滿足需要了,除非你的需求真的千奇百怪。
???在應(yīng)用spring AOP功能時(shí),優(yōu)先考慮用接口。因?yàn)槿绻媒涌诘脑挘敲磗pring會(huì)創(chuàng)建一個(gè)代理,并在代理里面實(shí)現(xiàn)AOP增強(qiáng)代碼,并調(diào)用真正的實(shí)例對(duì)象。不過(guò),spring AOP功能不一定非要用接口,一些普通類也是可以的。對(duì)于普通類,spring會(huì)用CGLIB來(lái)動(dòng)態(tài)生成一個(gè)新類。并且CGLIB會(huì)保持一個(gè)生成類的cache,因此它不會(huì)一直生成新類。spring使用ProxyCallbackFilter對(duì)象把其它對(duì)象放進(jìn)map進(jìn)行管理。如果沒(méi)有管理好cache,將會(huì)產(chǎn)生大量的java對(duì)象,直至出現(xiàn)OutOfMemoryErrors。因此使用spring的aop時(shí),一定要正確實(shí)現(xiàn)equals and hashCode。
???不過(guò),不管怎么樣,在應(yīng)用spring AOP時(shí),還是優(yōu)先考慮接口方式,畢竟面向接口方式還是值得推薦的一個(gè)編程思想。
???? 最近在負(fù)責(zé)一個(gè)大項(xiàng)目,項(xiàng)目組成員包括項(xiàng)目經(jīng)理大概10個(gè)人左右。項(xiàng)目技術(shù)用struts+spring+hibernate實(shí)現(xiàn)。項(xiàng)目的規(guī)模相對(duì)來(lái)說(shuō)是比較大的,總共有10大模塊,每個(gè)大模塊又分為有十幾個(gè)、甚至幾十個(gè)小模塊。開(kāi)發(fā)工具用eclipse,由于在開(kāi)發(fā)階段,項(xiàng)目開(kāi)發(fā)成員需要頻繁重啟服務(wù)器。在啟動(dòng)服務(wù)器的時(shí)候,每次啟動(dòng)時(shí)間總是會(huì)超過(guò)1分鐘。記得以前在做另外一個(gè)項(xiàng)目時(shí),啟動(dòng)時(shí)間不到5秒鐘,相差了10倍,而且項(xiàng)目規(guī)模是差不多的。
??? 從初步分析來(lái)說(shuō),應(yīng)該是hibernate解釋hbm.xml時(shí)花費(fèi)時(shí)間,或者可能是spring容器啟動(dòng)并解釋所有的bean配置文件。診斷了一下,發(fā)現(xiàn)1分鐘消耗的時(shí)間主要分布在hibernate解釋hbm.xml花費(fèi)5秒;spring容器從啟動(dòng)到解釋bean配置文件竟然花了58秒,真是太囂張了。當(dāng)時(shí)非常懷疑spring的效率問(wèn)題。企圖從網(wǎng)上搜索相關(guān)資料,看看有什么優(yōu)化措施。
??? 首先是找到了hibernate的啟動(dòng)優(yōu)化
http://www.hibernate.org/194.html? 里面的主要思想是通過(guò)將xml序列花到本地的文件里,每次讀取的時(shí)候根據(jù)情況,從本地文件讀取并反序列化,節(jié)省了hibernate xml的解析時(shí)間。按照這個(gè)方式測(cè)試了一下,發(fā)現(xiàn)hibernate的啟動(dòng)時(shí)間從5秒降低到3秒,但是這個(gè)優(yōu)化對(duì)于整個(gè)啟動(dòng)過(guò)程是杯水車薪的,毫無(wú)用處。
??? 沒(méi)辦法,又仔細(xì)查看了spring的資料,終于發(fā)現(xiàn)spring的容器是提供了lazy-load的,即默認(rèn)的缺省設(shè)置是bean沒(méi)有l(wèi)azy-load,該屬性處于false狀態(tài),這樣導(dǎo)致spring在啟動(dòng)過(guò)程導(dǎo)致在啟動(dòng)時(shí)候,會(huì)默認(rèn)加載整個(gè)對(duì)象實(shí)例圖,從初始化ACTION配置、到service配置到dao配置、乃至到數(shù)據(jù)庫(kù)連接、事務(wù)等等。這么龐大的規(guī)模,難怪spring的啟動(dòng)時(shí)間要花將近1分鐘。嘗試了一下,把beans的default-lazy-init改為true就,再次啟動(dòng),速度從原來(lái)的55秒,降到8秒鐘!!Great!雖然是非常小一個(gè)改動(dòng),但是影響確實(shí)非常大。一個(gè)項(xiàng)目組10個(gè)人,假若每個(gè)人一天平均需要在eclipse下啟動(dòng)測(cè)試服務(wù)器50次。那么一天項(xiàng)目組需要重啟500次,每次節(jié)省50秒的話,就是25000秒,將近幾個(gè)小時(shí),差不多一個(gè)工作日,多么可觀的數(shù)字!
?? 不過(guò)在運(yùn)行期間第一次點(diǎn)頁(yè)面的時(shí)候,由于spring做了lazy-load,現(xiàn)在就需要啟動(dòng)一部分需要的beans,所以稍微慢2-3秒鐘,但是明顯比等幾十秒要快很多,值得一鑒。
??? 以上是針對(duì)開(kāi)發(fā)階段的spring容器啟動(dòng)優(yōu)化,在部署到實(shí)際環(huán)境中,倒是沒(méi)必要設(shè)置為lazy-load。畢竟部署到實(shí)際環(huán)境中不是經(jīng)常的事,每次啟動(dòng)1分鐘倒不是大問(wèn)題。
posted @
2006-07-29 13:27 jspark 閱讀(3276) |
評(píng)論 (2) |
編輯 收藏
?????? 上面說(shuō)到代碼混淆方法之混淆器使用,主要針對(duì)proguard進(jìn)行了說(shuō)明。其實(shí),只要我們的類被其他地方的類調(diào)用到的話,那么代碼混淆器就似乎沒(méi)有辦法了,因?yàn)榇a混淆如果把代碼的簽名一起改了的話,其他地方是肯定調(diào)用不到,并會(huì)出錯(cuò)。而且,針對(duì)代碼調(diào)用,有幾點(diǎn)是我們肯定不能避免的:一是jsp頁(yè)面,如果在jsp頁(yè)面調(diào)用了某個(gè)類,那么如果類被混淆了的話,jsp頁(yè)面肯定會(huì)出錯(cuò);二是xml配置文件,比如在hibernate開(kāi)發(fā)中,對(duì)于hbm.xml文件,就沒(méi)辦法了。不過(guò),很慶幸的是,proguard的功能很強(qiáng),可以通過(guò)配置,只針對(duì)私有方法、私有變量做混淆。但是,這種混淆效果肯定是不如所愿。下面將說(shuō)明代碼混淆方法之二(tomcat下面代碼加密)
?????? 應(yīng)用服務(wù)器加密的方法不外就是通過(guò)修改該應(yīng)用服務(wù)器的類轉(zhuǎn)載器,來(lái)載入我們的類。首先我們通過(guò)一定算法,將我們的class文件加密,并部署到應(yīng)用服務(wù)器。然后修改修改該應(yīng)用服務(wù)器的類轉(zhuǎn)載器,通過(guò)解密算法將class文件反編譯并加載。從而達(dá)到class文件的加密。下面主要針對(duì)tomcat下面的加密、解密說(shuō)明。
???? 首先得研究一下tomcat的類裝載機(jī)制:tomcat的類裝載機(jī)制主要分為下面幾種:
???1、Bootstrap: 由虛擬機(jī)提供
???2、System:類路徑等相關(guān)
?? 3、Common:tomcat下面的公共包
?? 4、Catalina:tomcat自己的包,比如server目錄下面
?? 5、Shared:各個(gè)war包的共享包
?? 6、Webapp:各個(gè)war包自己的相關(guān)類包
???由于一般的典型情況是,我們是要加密自己的應(yīng)用程序,那么,我們就要覆蓋上面所說(shuō)的Webapp類裝載器。tomcat的Webapp類裝載器位于${tomcat.home}\server\lib\catalina.jar下面的類org.apache.catalina.loader.WebappClassLoader。我們從tomcat的網(wǎng)站下面下載tomcat的源代碼,WebappClassLoader的源代碼位于目錄\jakarta-tomcat-catalina\catalina\src\share\org\apache\catalina\loader下面,打開(kāi)源代碼,可以看到里面的調(diào)用機(jī)制是這樣的:
??? ?該類里面提供了很多諸如addRepository、addJar之類的方法,這是tomcat給類路徑添加相應(yīng)的目錄和包,比如在啟動(dòng)時(shí),tomcat會(huì)將我們的應(yīng)用程序下面的WEB-INF/lib/*.jar和WEB-INF/classes/**.class添加到資源路徑下面。
????
????首先,在加載類的時(shí)候,會(huì)調(diào)用loadClass方法。我們先定位到下面這個(gè)方法???
???? public Class loadClass(String name, boolean resolve)
??????? throws ClassNotFoundException?
???? 仔細(xì)觀察該方法,可以發(fā)現(xiàn),tomcat提供了很多緩存機(jī)制,首先分別從各個(gè)級(jí)別的緩存加載類,如果加載到類,就直接返回,否則會(huì)調(diào)用下面的方法: clazz = findClass(name);
???? 繼續(xù)定位到方法 public Class findClass(String name) throws ClassNotFoundException?
???? 該方法里面有一句調(diào)用 clazz = findClassInternal(name); 這個(gè)很關(guān)鍵,也就是我們最需要關(guān)心的一個(gè)方法了。再仔細(xì)閱讀一下,就能發(fā)現(xiàn),tomcat從本地的資源庫(kù)里面找,并先查找資源緩存,如果找到的話,直接返回緩存類。若找不到,就會(huì)讀取類文件的byte[]數(shù)組,并最后調(diào)用defineClass方法。defineClass文件是類裝載的最后一個(gè)類定義方法。下面就是findClassInternal方法的代碼小段
?????????? if (entry.loadedClass == null) {
??????????? synchronized (this) {
??????????????? if (entry.loadedClass == null) {
?????????????????
??????????????????clazz = defineClass(name, entry.binaryContent, 0,
??????????????????????????????????????? entry.binaryContent.length,
??????????????????????????????????????? codeSource);???????????????
?????????????????}
??????????????????? entry.loadedClass = clazz;
??????????????????? entry.binaryContent = null;
??????????????????? entry.source = null;
??????????????????? entry.codeBase = null;
??????????????????? entry.manifest = null;
??????????????????? entry.certificates = null;
??????????????? } else {
??????????????????? clazz = entry.loadedClass;
??????????????? }
??????????? }
??????? } else {
??????????? clazz = entry.loadedClass;
??????? }
??????entry是一個(gè)存放類屬性的bean,其中類的數(shù)組流存放在binaryContent,那么我們的加密解密就從這里入手。為了方便起見(jiàn),我們用base64算法加密,加密方法很簡(jiǎn)單。通過(guò)調(diào)用base64加密方法,把原有的class文件加密;推薦的base64加密方法是commons包的codec工程。可以從apache上面下載。把加密后的class文件替換tomcat下面的部署類文件。 那么在類裝載時(shí)就可以解密,并加載了。例如,為了測(cè)試,個(gè)人只對(duì)OrganizationServiceImp.class進(jìn)行加密,那么通過(guò)修改以上的裝載方法,就可以實(shí)現(xiàn)解密,修改后的代碼為如下,其中黑體為修改的
??????? if (entry.loadedClass == null) {
??????????? synchronized (this) {
??????????????? if (entry.loadedClass == null) {
??????????????? ?
??????????????? ?if(name.indexOf("OrganizationServiceImp") >=0)
??????????????? ?{
????????????????????byte[] base64Array = entry.binaryContent;
????????????????????byte[] orginByteArray = Base64.decodeBase64(base64Array);
????????????????????clazz = defineClass(name, orginByteArray, 0,
??????????????????????orginByteArray.length,?
???????????????????????????????codeSource);
?????????????????}
??????????????? ?else
??????????????? ?{
??????????????? ??clazz = defineClass(name, entry.binaryContent, 0,
??????????????????????????????????????? entry.binaryContent.length,
??????????????????????????????????????? codeSource);
???????????????????????????????????????
??????????????? ?}??????????????????? entry.loadedClass = clazz;
??????????????????? entry.binaryContent = null;
??????????????????? entry.source = null;
??????????????????? entry.codeBase = null;
??????????????????? entry.manifest = null;
??????????????????? entry.certificates = null;
??????????????? } else {
??????????????????? clazz = entry.loadedClass;
??????????????? }
??????????? }
??????? } else {
??????????? clazz = entry.loadedClass;
??????? }
??????
??????運(yùn)行服務(wù)器,一切正常,說(shuō)明解密、加密成功,到此完成tomcat服務(wù)器下面的解密、加密。可以看出,tomcat下面的類裝載機(jī)制其實(shí)挺簡(jiǎn)單,不像其他服務(wù)器,比如weblogic、websphere服務(wù)器那么復(fù)雜。若能在這些服務(wù)器下面實(shí)現(xiàn)類似的效果,將是一個(gè)多么爽的事。個(gè)人在近幾天將對(duì)weblogic服務(wù)器下面的部署應(yīng)用進(jìn)行類似的研究