標籤:核心 turn not 工具 大型 physical head UI running
-jar參數運行應用時classpath的設定方法 你是否在使用java -jar參數運行打包好的jar應用程式的時候發現應用程式無法找到classpath下設定好的第三方類庫的內容?無論怎麼設定classpath參數都無濟於事,總是會報ClassNotFound的錯誤?
當用java -jar yourJarExe.jar來運行一個經過打包的應用程式的時候,你會發現如何設定-classpath參數應用程式都找不到相應的第三方類,報ClassNotFound錯誤。實際上這是由於當使用-jar參數啟動並執行時候,java VM會屏蔽所有的外部classpath,而只以本身yourJarExe.jar的內部class作為類的尋找範圍。
**解決方案**
一 BootStrap class擴充方案
Java 命令列提供了如何擴充bootStrap 層級class的簡單方法.
-Xbootclasspath: 完全取代基本核心的Java class 搜尋路徑.
不常用,否則要重新寫所有Java 核心class
-Xbootclasspath/a: 尾碼在核心class搜尋路徑後面.常用!!
-Xbootclasspath/p: 首碼在核心class搜尋路徑前面.不常用,避免
引起不必要的衝突.
文法如下:
(分隔字元與classpath參數類似,unix使用:號,windows使用;號,這裡以unix為例)
java -Xbootclasspath/a:/usrhome/thirdlib.jar: -jar yourJarExe.jar
二 extend class 擴充方案
Java exten class 存放在{Java_home}/jre/lib/ext目錄下.當調用Java時,對擴充class路徑的搜尋是自動的.總會搜尋的.這樣,解決的方案就很簡單了,將所有要使用的第三方的jar包都複製到ext 目錄下.
三 User class擴充方案
當使用-jar執行可執行Jar包時,JVM將Jar包所在目錄設定為codebase目錄,所有的class搜尋都在這個目錄下開始.所以如果使用了其他第三方的jar包,一個比較可以接受的可配置方案,就是利用jar包的Manifest擴充機制.
步驟如下:
1.將需要的第三方的jar包,複製在同可執行jar所在的目錄或某個子目錄下. 比如:jar 包在 /usrhome/yourJarExe.jar 那麼你可以把所有jar包複製到/usrhome目錄下或/usrhome/lib 等類似的子目錄下.
2.修改Manifest 檔案
在Manifest.mf檔案裡加入如下行
Class-Path:classes12.jar lib/thirdlib.jar
Class-Path 是可執行jar包運行依賴的關鍵詞.詳細內容可以參考 http://java.sun.com/docs/books/tutorial/deployment/jar/downman.html 。要注意的是 Class-Path 只是作為你本地機器的CLASSPATH環境變數的一個縮寫,也就是說用這個首碼表示在你的jar包執行機器上所有的CLASSPATH目錄下尋找相應的第三方類/類庫。你並不能通過 Class-Path 來載入位於你本身的jar包裡面(或者網路上)的jar檔案。因為從理論上來講,你的jar發布包不應該再去包含其他的第三方類庫(而應該通過使用說明來提醒使用者去擷取相應的支援類庫)。如果由於特殊需要必須把其他的第三方類庫(jar, zip, class等)直接打包在你自己的jar包裡面一起發布,你就必須通過實現自訂的ClassLoader來按照自己的意圖載入這些第三方類庫。
以上三種方法推薦第一種,擴充性好,操作起來也最方便.
另外編寫自己的ClassLoader,來動態載入class,是更加複雜和進階技術.限於篇幅,不贅述.有興趣瞭解可以去google一下custom classloader,或者參考我的另一篇日誌:讓classpath參數走開。
Java的安全機制隨不同的JDK版本有不同的變化,會影響很多核心CLASS,比如Thread,所以很多大型商業軟體,要求JDK的版本很嚴格.部分原因也在此.這也要求在發布自己編寫的應用時候,不管大小,都要說明開發與測試的JDK版本.
本文所述方法測試基於j2sdk 1.4.2_04-b05
----------------------------------------------------------------------------------------------
附:背景知識
自JDK 1.2以後,JVM採用了委託(delegate)模式來載入class.採用這種設計的原因可以參考http://java.sun.com/docs/books/tutorial/ext/basics/load.html
歸納來講:是基於JVM sandbox(沙箱)安裝模型上提供應用程式層的可定製的安全機制.
Java虛擬機器(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擴充機制,用來擴充Java核心功能模組.比如Java串口通訊模組comm.jar.一般放置在{Java_home}/jre/lib/ext目錄下
3. User classes
開發人員或其他第三方開發的Java程式包.通過命令列的-classpath或-cp,或者通過設定CLASSPATH環境變數來引用.JVM通過放置在{java_home}/lib/tools.jar來尋找和調用使用者級的class.常用的javac也是通過調用tools.jar來尋找使用者指定的路徑來編譯Java來源程式.這樣就引出了User class路徑搜尋的順序或優先順序別的問題.
3.1 預設值:調用Java或javawa的當前路徑(.),是開發的class所存在的目前的目錄
3.2 CLASSPATH環境變數設定的路徑.如果設定了CLASSPATH,則CLASSPATH的值會覆蓋預設值
3.3 執行Java的命令列-classpath或-cp的值,如果制定了這兩個命令列參數之一,它的值會覆蓋環境變數CLASSPATH的值
3.4 -jar 選項:如果通過java -jar 來運行一個可執行檔jar包,這當前jar包會覆蓋上面所有的值.換句話說,-jar 後面所跟的jar包的優先順序別最高,如果指定了-jar選項,所有環境變數和命令列制定的搜尋路徑都將被忽略.JVM APPClassloader將只會以jar包為搜尋範圍.
有關可執行jar有許多相關的安全方面的描述,可以參考http://java.sun.com/docs/books/tutorial/jar/ 來全面瞭解.
這也是為什麼應用程式打包成可執行檔jar包後,不管你怎麼設定classpath都不能引用到第三方jar包的東西了
注意
有時候我們需要從classpath中讀取properties檔案,對於單獨啟動並執行jar包,需要在jar/META-INF/MANIFEST.MF檔案裡設定classpath,這樣程式才能從classpath中負載檔案:
Manifest-Version: 1.0
Implementation-Title:
Implementation-Version: 1.0-SNAPSHOT
Implementation-Vendor-Id:
Built-By: test
Build-Jdk: 1.7.0_75
Class-Path: classes/ lib/core-renderer-R8.jar
Created-By: Apache Maven
Main-Class: batch.BatchMain
Archiver-Version: Plexus Archiver
對於運行jar包,在環境變數裡設定的classpath是無效的
以往基於構建工具和IDE工作,很少使用命令列執行程式,但偶爾使用命令列的時候關於類路徑的設定都要查閱一下說明文檔,這裡找到一個詳盡清晰的說明,以備自查.特別指明的是:classpath最好使用""(window系統下)或‘‘(linux系統下)括起來,否則可能會因為包含的jar路徑上含有空格一類的特殊字元導致出現奇怪的錯誤提示.,本文轉自wikipedia,地址:http://en.wikipedia.org/wiki/Classpath_%28Java%29
Setting the path to execute Java programsBasic usage
Suppose we have a package called org.mypackage containing the classes:
- HelloWorld (main class)
- SupportClass
- UtilClass
and the files defining this package are stored physically under the directory D:\myprogram (on Windows) or/home/user/myprogram (on Linux).
The file structure will look like this:
| Microsoft Windows |
Linux |
D:\myprogram | ---> org\ | ---> mypackage | ---> HelloWorld.class ---> SupportClass.class ---> UtilClass.class |
/home/user/myprogram/ | ---> org/ | ---> mypackage/ | ---> HelloWorld.class ---> SupportClass.class ---> UtilClass.class |
When we invoke Java, we specify the name of the application to run: org.mypackage.HelloWorld. However we must also tell Java where to look for the files and directories defining our package. So to launch the program, we use the following command:
| Microsoft Windows |
Linux |
java -classpath D:\myprogram org.mypackage.HelloWorld |
java -classpath /home/user/myprogram org.mypackage.HelloWorld |
where:
- -classpath D:\myprogram sets the path to the packages used in the program (on Linux, -classpath /home/user/myprogram)
- org.mypackage.HelloWorld is the name of the main class
Note that if we ran Java in D:\myprogram\ (on Linux, /home/user/myprogram/) then we would not need to specify the classpath since Java implicitly looks in the current working directory for files containing classes.
Adding all JAR files in a directory
In Java 6 and higher, one can add all jar-files in a specific directory to the classpath using wildcard notation.
Windows example:
java -classpath ".;c:\mylib\*" MyApp
Linux example:
java -classpath ‘.:/mylib/*‘ MyApp
Setting the path through an environment variable
The environment variable named CLASSPATH may be alternatively used to set the classpath. For the above example, we could also use on Windows:
Sometimes you have to check the JAVA_HOME also, if it is pointing towards the right JDK version
set CLASSPATH=D:\myprogramjava org.mypackage.HelloWorld
Setting the path of a Jar file
Now, suppose the program uses a supporting library enclosed in a Jar file called supportLib.jar, physically in the directoryD:\myprogram\lib\.
The corresponding physical file structure is :
D:\myprogram | ---> lib | ---> supportLib.jar | ---> org | --> mypackage | ---> HelloWorld.class ---> SupportClass.class ---> UtilClass.class
We should use the following command-line option:
java -classpath D:\myprogram;D:\myprogram\lib\supportLib.jar org.mypackage.HelloWorld
or alternatively:
set CLASSPATH=D:\myprogram;D:\myprogram\lib\supportLib.jarjava org.mypackage.HelloWorld
Setting the path in a Manifest file
Suppose that our program has been enclosed in a Jar file called helloWorld.jar, put directly in the D:\myprogram directory. We have the following file structure:
D:\myprogram | ---> helloWorld.jar | ---> lib\ | ---> supportLib.jar
The manifest file defined in this Jar file has this definition:
Main-Class: org.mypackage.HelloWorldClass-Path: lib/supportLib.jar
Note: It‘s important that the manifest file ends with either a new line or carriage return.
Also, note that the classpath string in this case describes the location of the supportLib.jar file relative to the location of the helloWorld.jar file, and not as an absolute file path (as it might be when setting the -classpath parameter on the command line, for example). Thus, the actual locations of the jar file and its support library are irrelevant so long as the relative directory structure between the two is preserved.
To launch the program, we can use the following command:
java -jar D:\myprogram\helloWorld.jar
It is not necessary to define the Classpath to the program classes, or the support library classes, because it is already defined in themanifest file.
Caution, it is useless to define the Main class at launch, the manifest of the JAR file must contain a line of the form
Main-Class: classname
in order for the -jar option to work JavaDoc.
The syntax for specifying multiple library JAR files in the manifest file is to separate the entries with a space:
Class-Path: lib/supportLib.jar lib/supportLib2.jar
OS specific notes
Being closely associated with the file system, the command-line Classpath syntax depends on the operating system. For example:
- on all Unix-like operating systems (such as Linux and Mac OS X), the directory structure has a Unix syntax, with separate file paths separated by a colon (":").
- on Windows, the directory structure has a Windows syntax, and each file path must be separated by a semicolon (";").
This does not apply when the Classpath is defined in manifest files, where each file path must be separated by a space (" "), regardless of the operating system.
Diagnose
Application programmers may want to find out/debug the current settings under which the application is running:
System.getProperty("java.class.path")
方法一
按照developrworks上說的:
http://www.ibm.com/developerworks/cn/java/j-jar/index.html
建立可執行 JAR
建立一個可執行 JAR 很容易。首先將所有應用程式代碼放到一個目錄中。假設應用程式中的主類是 com.mycompany.myapp.Sample。您要建立一個包含應用程式代碼的 JAR 檔案並標識出主類。為此,在某個位置 ( 不是在應用程式目錄中 ) 建立一個名為 manifest的檔案,並在其中加入以下一行:
Main-Class: com.mycompany.myapp.Sample |
然後,像這樣建立 JAR 檔案:
jar cmf manifest ExecutableJar.jar application-dir |
所要做的就是這些了 -- 現在可以用 java -jar執行這個 JAR 檔案 ExecutableJar.jar。
一個可執行檔 JAR 必須通過 menifest 檔案的頭引用它所需要的所有其他從屬 JAR。如果使用了 -jar選項,那麼環境變數 CLASSPATH 和在命令列中指定的所有類路徑都被 JVM 所忽略。
方法二:
來個簡單的:
java -Djava.ext.dirs=m:\test -jar test.jar
相關的jar(依賴的jar)目錄均在m:\test下,test.jar就是需要啟動並執行jar
java和jar命令