目录
前言
- jdk 1.8
- 期望在java -jar命令执行java程序时,能够指定classpath
java 类加载器与路径
java 类加载器有三个:
- Bootstrap CLassLoader
- ExtClassLoader
- AppClassLoader
java 类加载器对应的路径:
- bootclasspath:对应 Bootstrap CLassLoader。java虚拟机系统参数
sun.boot.class.path
。 - Extensions JAR files:对应 Extention ClassLoader 。java虚拟机系统参数
java.ext.dirs
。 - classpath:对应 AppClassLoader。java虚拟机系统参数
java.class.path
。
java 设置路径的方法
设置 bootclasspath
参考这里
设置 Extensions JAR files
参考这里
设置 classpath
参考这里
测试程序
创建maven项目PrintPath,代码如下:
import java.io.File;
public class Test {
public static void main(String[] args) {
printPath("java.home");
printPath("sun.boot.class.path");
printPath("java.ext.dirs");
printPath("java.class.path");
}
public static void printPath(String name) {
System.out.println(name + ":");
String[] paths = System.getProperty(name).split(File.pathSeparator);
for(String path : paths) {
System.out.println("- " + path);
}
}
}
运行结果
cmd> java -jar target\PrintPath.jar
java.home:
- C:\Program Files\Java\jre1.8.0_144
sun.boot.class.path:
- C:\Program Files\Java\jre1.8.0_144\lib\resources.jar
- C:\Program Files\Java\jre1.8.0_144\lib\rt.jar
- C:\Program Files\Java\jre1.8.0_144\lib\sunrsasign.jar
- C:\Program Files\Java\jre1.8.0_144\lib\jsse.jar
- C:\Program Files\Java\jre1.8.0_144\lib\jce.jar
- C:\Program Files\Java\jre1.8.0_144\lib\charsets.jar
- C:\Program Files\Java\jre1.8.0_144\lib\jfr.jar
- C:\Program Files\Java\jre1.8.0_144\classes
java.ext.dirs:
- C:\Program Files\Java\jre1.8.0_144\lib\ext
- C:\WINDOWS\Sun\Java\lib\ext
java.class.path:
- target\PrintPath.jar
java -jar 启动时,-cp
参数无效
使用-jar
选项(形如:java -jar xxx.jar )来运行一个可执行的jar包时,-jar
会覆-cp
的值。
cmd> java -cp D:\java_ext\sunec.jar -jar target\PrintPath.jar
java.home:
- C:\Program Files\Java\jre1.8.0_144
sun.boot.class.path:
- C:\Program Files\Java\jre1.8.0_144\lib\resources.jar
- C:\Program Files\Java\jre1.8.0_144\lib\rt.jar
- C:\Program Files\Java\jre1.8.0_144\lib\sunrsasign.jar
- C:\Program Files\Java\jre1.8.0_144\lib\jsse.jar
- C:\Program Files\Java\jre1.8.0_144\lib\jce.jar
- C:\Program Files\Java\jre1.8.0_144\lib\charsets.jar
- C:\Program Files\Java\jre1.8.0_144\lib\jfr.jar
- C:\Program Files\Java\jre1.8.0_144\classes
java.ext.dirs:
- C:\Program Files\Java\jre1.8.0_144\lib\ext
- C:\WINDOWS\Sun\Java\lib\ext
java.class.path:
- target\PrintPath.jar
-cp
参数无效
jar 文件的 Class-Path
在jar中存在一个名为META-INF\MANIFEST.MF
的文件,该文件中有个名为Class-Path
的属性。Class-Path
的属性中的jar会被加载。
java -jar 启动程序时,设置classpath的方法
方法1:修改 bootclasspath
此种方法可以添加少量的jar文件。当jar文件很多时,应该也可以。
cmd> java -Xbootclasspath/a:.\lib2\xx1.jar;.\lib2\xx2.jar;. -jar target\PrintPath.jar
java.home:
- C:\Program Files\Java\jre1.8.0_144
sun.boot.class.path:
- C:\Program Files\Java\jre1.8.0_144\lib\resources.jar
- C:\Program Files\Java\jre1.8.0_144\lib\rt.jar
- C:\Program Files\Java\jre1.8.0_144\lib\sunrsasign.jar
- C:\Program Files\Java\jre1.8.0_144\lib\jsse.jar
- C:\Program Files\Java\jre1.8.0_144\lib\jce.jar
- C:\Program Files\Java\jre1.8.0_144\lib\charsets.jar
- C:\Program Files\Java\jre1.8.0_144\lib\jfr.jar
- C:\Program Files\Java\jre1.8.0_144\classes
- .\lib2\xx1.jar
- .\lib2\xx2.jar
- .
java.ext.dirs:
- C:\Program Files\Java\jre1.8.0_144\lib\ext
- C:\WINDOWS\Sun\Java\lib\ext
java.class.path:
- target\PrintPath.jar
- 添加jar文件
- 添加配置文件目录
- 添加class文件目录
方法2:修改 Extensions JAR files
此种方法可以添加jar所在的目录。当jar文件很多时,比较友好。但是,需要注意:尽量将java自带的lib\ext目录带上
。
cmd> java -Djava.ext.dirs="%JAVA_HOME%jre\lib\ext;.\lib" -jar target\PrintPath.jar
java.home:
- C:\Program Files\Java\jre1.8.0_144
sun.boot.class.path:
- C:\Program Files\Java\jre1.8.0_144\lib\resources.jar
- C:\Program Files\Java\jre1.8.0_144\lib\rt.jar
- C:\Program Files\Java\jre1.8.0_144\lib\sunrsasign.jar
- C:\Program Files\Java\jre1.8.0_144\lib\jsse.jar
- C:\Program Files\Java\jre1.8.0_144\lib\jce.jar
- C:\Program Files\Java\jre1.8.0_144\lib\charsets.jar
- C:\Program Files\Java\jre1.8.0_144\lib\jfr.jar
- C:\Program Files\Java\jre1.8.0_144\classes
java.ext.dirs:
- C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext
- .\lib2
java.class.path:
- target\PrintPath.jar
方法3:修改classpath
java -jar方式启动程序时,-cp参数是无效的,则不能通过-cp参数设置classpath。其替代方法是,在JAR中的META-INF\MANIFEST.MF
文件里设置Class-Path
。
推荐此法:在JAR中的META-INF\MANIFEST.MF
文件里设置Class-Path
。
springboot项目怎么做?
springboot项目时不需要处理。确实需要处理时,参考这里。
PS:确保springboot项目的POM.xml中包含了spring-boot-maven-plugin
插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
maven项目打包时,由maven生成META-INF\MANIFEST.MF
文件且设置Class-Path
修改POM.xml
<?xml version="1.0" encoding="UTF-8"?>
<project ...>
...
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<!-- 生成manifest,假定依赖的jar都在与本程序同目录的lib目录下 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib</classpathPrefix>
<mainClass>test.Test</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<!-- 将依赖的jar拷贝到target/lib目录下 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.directory}/lib
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
无法重新打包时,修改META-INF\MANIFEST.MF
文件且设置Class-Path
尝试手动编辑MANIFEST.MF:
尽量选择个靠谱的压缩包操作软件,比如winrar。
扩展知识(转)
自JDK 1.2以后,JVM采用了委托(delegate)模式来载入class.采用这种设计的原因可以参考http://java.sun.com/docs/books/tutorial/ext/basics/load.html
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包的东西了.