ZealLi 2005-04-28 10:20 于 JAVA/C++ , 3314 字 |
+ 1
- 0
English
你是否在使用java -jar參數(shù)運(yùn)行打包好的jar應(yīng)用程序的時候發(fā)現(xiàn)應(yīng)用程序無法找到classpath下設(shè)置好的第三方類庫的內(nèi)容?無論怎么設(shè)置classpath參數(shù)都無濟(jì)于事,總是會報ClassNotFound的錯誤?那么本篇帖子可以幫助你擺脫煩惱 :)
當(dāng)用java -jar yourJarExe.jar來運(yùn)行一個經(jīng)過打包的應(yīng)用程序的時候,你會發(fā)現(xiàn)如何設(shè)置-classpath參數(shù)應(yīng)用程序都找不到相應(yīng)的第三方類,報ClassNotFound錯誤。實(shí)際上這是由于當(dāng)使用-jar參數(shù)運(yùn)行的時候,java VM會屏蔽所有的外部classpath,而只以本身yourJarExe.jar的內(nèi)部class作為類的尋找范圍。
**解決方案**
一 BootStrap class擴(kuò)展方案
Java 命令行提供了如何擴(kuò)展bootStrap 級別class的簡單方法.
-Xbootclasspath: 完全取代基本核心的Java class 搜索路徑.
不常用,否則要重新寫所有Java 核心class
-Xbootclasspath/a: 后綴在核心class搜索路徑后面.常用!!
-Xbootclasspath/p: 前綴在核心class搜索路徑前面.不常用,避免
引起不必要的沖突.
語法如下:
(分隔符與classpath參數(shù)類似,unix使用:號,windows使用;號,這里以unix為例)
java -Xbootclasspath/a:/usrhome/thirdlib.jar: -jar yourJarExe.jar
二 extend class 擴(kuò)展方案
Java exten class 存放在{Java_home}\jre\lib\ext目錄下.當(dāng)調(diào)用Java時,對擴(kuò)展class路徑的搜索是自動的.總會搜索的.這樣,解決的方案就很簡單了,將所有要使用的第三方的jar包都復(fù)制到ext 目錄下.
三 User class擴(kuò)展方案
當(dāng)使用-jar執(zhí)行可執(zhí)行Jar包時,JVM將Jar包所在目錄設(shè)置為codebase目錄,所有的class搜索都在這個目錄下開始.所以如果使用了其他第三方的jar包,一個比較可以接受的可配置方案,就是利用jar包的Manifest擴(kuò)展機(jī)制.
步驟如下:
1.將需要的第三方的jar包,復(fù)制在同可執(zhí)行jar所在的目錄或某個子目錄下. 比如:jar 包在 /usrhome/yourJarExe.jar 那么你可以把所有jar包復(fù)制到/usrhome目錄下或/usrhome/lib 等類似的子目錄下.
2.修改Manifest 文件
在Manifest.mf文件里加入如下行
Class-Path:classes12.jar lib/thirdlib.jar
Class-Path 是可執(zhí)行jar包運(yùn)行依賴的關(guān)鍵詞.詳細(xì)內(nèi)容可以參考 http://java.sun.com/docs/books/tutorial/ext/index.html
以上三種方法推薦第一種,擴(kuò)展性好,操作起來也最方便.
另外編寫自己的ClassLoader,來動態(tài)載入class,是更加復(fù)雜和高級技術(shù).限于篇幅,不贅述.有興趣了解可以去google一下custom classloader
Java的安全機(jī)制隨不同的JDK版本有不同的變化,會影響很多核心CLASS,比如Thread,所以很多大型商業(yè)軟件,要求JDK的版本很嚴(yán)格.部分原因也在此.這也要求在發(fā)布自己編寫的應(yīng)用時候,不管大小,都要說明開發(fā)和測試的JDK版本.
本文所述方法測試基于j2sdk 1.4.2_04-b05
----------------------------------------------------------------------------------------------
附:背景知識
自JDK 1.2以后,JVM采用了委托(delegate)模式來載入class.采用這種設(shè)計的原因可以參考http://java.sun.com/docs/books/tutorial/ext/basics/load.html
歸納來講:是基于JVM sandbox(沙盒)安裝模型上提供應(yīng)用層的可定制的安全機(jī)制.
Java虛擬機(jī)(JVM)尋找Class的順序
1. Bootstrap classes
屬于Java 平臺核心的class,比如java.lang.String等.及rt.jar等重要的核心級別的class.這是由JVM Bootstrap class loader來載入的.一般是放置在{java_home}\jre\lib目錄下
2. Extension classes
基于Java擴(kuò)展機(jī)制,用來擴(kuò)展Java核心功能模塊.比如Java串口通訊模塊comm.jar.一般放置在{Java_home}\jre\lib\ext目錄下
3. User classes
開發(fā)人員或其他第三方開發(fā)的Java程序包.通過命令行的-classpath或-cp,或者通過設(shè)置CLASSPATH環(huán)境變量來引用.JVM通過放置在{java_home}\lib\tools.jar來尋找和調(diào)用用戶級的class.常用的javac也是通過調(diào)用tools.jar來尋找用戶指定的路徑來編譯Java源程序.這樣就引出了User class路徑搜索的順序或優(yōu)先級別的問題.
3.1 缺省值:調(diào)用Java或javawa的當(dāng)前路徑(.),是開發(fā)的class所存在的當(dāng)前目錄
3.2 CLASSPATH環(huán)境變量設(shè)置的路徑.如果設(shè)置了CLASSPATH,則CLASSPATH的值會覆蓋缺省值
3.3 執(zhí)行Java的命令行-classpath或-cp的值,如果制定了這兩個命令行參數(shù)之一,它的值會覆蓋環(huán)境變量CLASSPATH的值
3.4 -jar 選項(xiàng):如果通過java -jar 來運(yùn)行一個可執(zhí)行的jar包,這當(dāng)前jar包會覆蓋上面所有的值.換句話說,-jar 后面所跟的jar包的優(yōu)先級別最高,如果指定了-jar選項(xiàng),所有環(huán)境變量和命令行制定的搜索路徑都將被忽略.JVM APPClassloader將只會以jar包為搜索范圍.
有關(guān)可執(zhí)行jar有許多相關(guān)的安全方面的描述,可以參考http://java.sun.com/docs/books/tutorial/jar/ 來全面了解.
這也是為什么應(yīng)用程序打包成可執(zhí)行的jar包后,不管你怎么設(shè)置classpath都不能引用到第三方j(luò)ar包的東西了.