java -jar 启动程序 / 设置 classpath

前言

  • 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:

  1. 手动编辑 MANIFEST.MF。参考这里这里
  2. 替换掉 JAR 中的 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 包的东西了.

java -jar 启动程序 / 设置 classpath_java -jar classpath-CSDN 博客

java bootclasspath_xbootclasspath-CSDN 博客

前言

  • jdk1.8

查看 bootclasspath

创建项目 BootstrapClassPath,代码如下:

import java.io.File;

public class Test {
	public static void main(String[] args) {
		printPath("sun.boot.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);
		}
	}
}

执行结果:

sun.boot.class.path:
- C:\Program Files\Java\jdk1.8.0_144\jre\lib\resources.jar
- C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar
- C:\Program Files\Java\jdk1.8.0_144\jre\lib\sunrsasign.jar
- C:\Program Files\Java\jdk1.8.0_144\jre\lib\jsse.jar
- C:\Program Files\Java\jdk1.8.0_144\jre\lib\jce.jar
- C:\Program Files\Java\jdk1.8.0_144\jre\lib\charsets.jar
- C:\Program Files\Java\jdk1.8.0_144\jre\lib\jfr.jar
- C:\Program Files\Java\jdk1.8.0_144\jre\classes

修改 bootclasspath

  • -Xbootclasspath: 完全取代基本核心的 Java class 搜索路径。不常用(慎用), 否则要重新写所有 Java 核心 class
  • -Xbootclasspath/a: 后缀。在 bootclasspath 后面添加。常用!!
  • -Xbootclasspath/p: 前缀。在 bootclasspath 前面添加。不常用,避免引起不必要的冲突。

-Xbootclasspath/a 示例

cmd> java -Xbootclasspath/a:.\lib\xxx.jar;BootstrapClassPath.jar test.Test
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
- ./lib/xxx.jar
- BootstrapClassPath.jar
  • ./lib/xxx.jar;BootstrapClassPath.jar 被添加到了 sun.boot.class.path 后面
  • 前面的源码打包到了 BootstrapClassPath.jar 中

-Xbootclasspath/p 示例

cmd> java -Xbootclasspath/p:.\lib\xxx.jar;BootstrapClassPath.jar test.Test
sun.boot.class.path:
- ./lib/xxx.jar
- BootstrapClassPath.jar
- 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
  • ./lib/xxx.jar;BootstrapClassPath.jar 被添加到了 sun.boot.class.path 前面
  • 前面的源码打包到了 BootstrapClassPath.jar 中

(可以)添加.class 文件目录

cmd> java -Xbootclasspath/a:.\target\classes test.Test
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
- .\target\classes

(可以)添加.yml.xml.properties(或其它配置文件)文件目录

cmd> java -Xbootclasspath/a:.\target\conf test.Test
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
- .\target\conf

(可以)添加.jar 文件

cmd> java -Xbootclasspath/a:.\target\BootstrapClassPath.jar test.Test
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
- .\target\BootstrapClassPath.jar

(不可以)添加.jar 文件所在目录

cmd> java -Xbootclasspath/a:.\target test.Test
错误: 找不到或无法加载主类 test.Test

扩展知识

自 JDK 1.2 以后,JVM 采用了委托 (delegate) 模式来载入 class.
采用这种设计的原因可以参考: http://java.sun.com/docs/books/tutorial/ext/basics/load.html

java extensions JAR files_extension jar-CSDN 博客

前言

  • jdk1.8

java.ext.dirs

在这里插入图片描述

查看 java.ext.dirs

创建 maven 项目 ExtDirs,代码如下:

import java.io.File;

public class Test {
	public static void main(String[] args) {
		printPath("java.home");
		printPath("java.ext.dirs");
	}
	
	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);
		}
	}
}

执行结果:

java.home:
- C:\Program Files\Java\jdk1.8.0_144\jre
java.ext.dirs:
- C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext
- C:\WINDOWS\Sun\Java\lib\ext
  • 注意这里出现的都是目录,且目录下为.jar 文件
  • C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext
    在这里插入图片描述
  • C:\WINDOWS\Sun\Java\lib\ext 我的电脑上没有这个目录

上面的结果是在 eclipse 中运行出来的。在命令行里运行出来的结果有些不一样,如下:

cmd> java -cp target\classes test.Test
java.home:
- C:\Program Files\Java\jre1.8.0_144
java.ext.dirs:
- C:\Program Files\Java\jre1.8.0_144\lib\ext
- C:\WINDOWS\Sun\Java\lib\ext
  • 在 eclipse 中的运行结果与在命令行里的运行结果的差别为 jre 目录的不同。
  • 在 eclipse 中,设置了 jdk,使用的是 jdk 中的 jre
  • 在命令行里,使用的是 jre(不是 jdk 中的 jre)(安装 jdk 时,既安装了 jdk,又安装了 jre。如果不安装 jre,会不会就一样了?)
  • 尽管 jre 的路径不一样,但目录下的.jar 文件是一样的

修改 java.ext.dirs

  • java -Djava.ext.dirs=...

(不可以)添加.class 文件目录

cmd> java -Djava.ext.dirs=.\target\ExtDirs.jar test.Test
错误: 找不到或无法加载主类 test.Test
cmd> java -cp ./target/ExtDirs.jar test.Test
java.home:
- C:\Program Files\Java\jre1.8.0_144
java.ext.dirs:
- C:\Program Files\Java\jre1.8.0_144\lib\ext
- C:\WINDOWS\Sun\Java\lib\ext
  • 不能加载.class 文件

(不可以)添加.jar 文件

cmd> java -Djava.ext.dirs=.\target\classes test.Test
错误: 找不到或无法加载主类 test.Test
cmd> java -cp .\target\classes test.Test
java.home:
- C:\Program Files\Java\jre1.8.0_144
java.ext.dirs:
- C:\Program Files\Java\jre1.8.0_144\lib\ext
- C:\WINDOWS\Sun\Java\lib\ext
  • 不能加载.jar 文件

(可以)添加.jar 文件所在目录

cmd> java -Djava.ext.dirs=.\target test.Test
java.home:
- C:\Program Files\Java\jre1.8.0_144
java.ext.dirs:
- ./target
cmd> java -cp .\target\* test.Test
java.home:
- C:\Program Files\Java\jre1.8.0_144
java.ext.dirs:
- C:\Program Files\Java\jre1.8.0_144\lib\ext
- C:\WINDOWS\Sun\Java\lib\ext
  • 在 ./target 目录下包含 ExtDirs.jarExtDirs.jar 中的入口程序为 test.Test

尽量将 java 自带的 lib\ext 目录带上

cmd> java -Djava.ext.dirs="%JAVA_HOME%jre\lib\ext;.\target" -cp target\classes test.Test
java.home:
- C:\Program Files\Java\jre1.8.0_144
java.ext.dirs:
- C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext
- .\target
  • -Djava.ext.dirs="%JAVA_HOME%jre\lib\ext;D:\java_ext" 加引号是因为 %JAVA_HOME% 包含空格。
  • 尽量将 java 自带的 lib\ext 目录带上。否则,在用其下.jar 时,会发生错误。如果确定不需要其下.jar 时,则不用加上 java 自带的 lib\ext 目录。
  • 缺少 java 自带的 lib\ext 目录时,java.security 包不能使用(NoSuchAlgorithmException)。

扩展知识

自 JDK 1.2 以后,JVM 采用了委托 (delegate) 模式来载入 class.
采用这种设计的原因可以参考: http://java.sun.com/docs/books/tutorial/ext/basics/load.html

参考

https://blog.csdn.net/scugxl/article/details/43240991
https://docs.oracle.com/javase/tutorial/ext/basics/install.html

java classpath-CSDN 博客

查看 classpath

创建 maven 项目 ClassPath,代码如下:

import java.io.File;

public class Test {
	public static void main(String[] args) {
		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);
		}
	}
}

执行结果:

java.class.path:
- D:\sde\git-workspace\JavaSamples\java-samples-ClassPath\ClassPath\target\classes
  • D:\sde\git-workspace\JavaSamples\java-samples-ClassPath\ClassPath 是项目目录
  • 项目为 maven 项目

修改 classpath

  • java -classpath ...
  • java -cp ... 是 java -classpath ... 的简写

(可以)添加.class 文件目录

cmd> java -cp target\classes test.Test
java.class.path:
- target\classes

(可以)添加.jar 文件

cmd> java -cp target\ClassPath.jar test.Test
java.class.path:
- target\ClassPath.jar

(不可以)添加.jar 文件所在目录

cmd> java -cp target test.Test
错误: 找不到或无法加载主类 test.Test
cmd> java -cp target\ test.Test
错误: 找不到或无法加载主类 test.Test
cmd> java -cp target\*.jar test.Test
错误: 找不到或无法加载主类 test.Test
  • java -cp 无法自动查找 target 目录下的.jar 文件,并加载。

(可以)通配符 *

cmd> java -cp target\* test.Test
java.class.path:
- target\ClassPath.jar
cmd> java -cp target\classes\* test.Test
错误: 找不到或无法加载主类 test.Test
  • target\* 是个特例,可以让 java 自动搜索其下的.jar 文件,并加载。

【springboot】启动时指定 lib 目录_-dloader.path=.,lib-CSDN 博客

java -jar -Dloader.path=lib xxxApp.jar

java -jar -Dloader.path=lib,templates,static xxxApp.jar

 

posted @ 2024-06-27 10:09  CharyGao  阅读(240)  评论(0)    收藏  举报