首页 > 代码库 > java和jar命令

java和jar命令

-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 programs

Basic 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 WindowsLinux
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 WindowsLinux
 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命令