java -jar命令运行 jar包时如何运行外部依赖jar包

java -jar命令运行 jar包时如何运行外部依赖jar包

场景:

打包发不完,运行时。发现一个问题,

java java.lang.NoClassDefFoundError: org/apache/commons/lang3/ArrayUtils

显示此,基本表明,没有这个依赖,如果在开发中,在maven的pom.xml 中引入即可;

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version> <!-- 使用最新版本或适合你项目的版本 -->
</dependency>

但是;此时只有jar包,无法修改代码。如何解决呢?

解决:

直接在java -jar test.jar 时,添加参数。

方法一、启动参数添加: -Xbootclasspath/a

java -Xbootclasspath/a:custom-rt.jar -jar test.jar

方法二、使用Extension Classloader来加载

要让Extension Classloader加载你的类,需要:

  1. 将你的JAR文件放入:

    • <JAVA_HOME>/jre/lib/ext目录(JDK 8及之前)
    • 或由java.ext.dirs系统属性指定的目录
  2. 或者运行时指定扩展目录:

    java -Djava.ext.dirs=/path/to/your/extensions -jar test.jar
    

此时此景,只能采用2;值的注意的注意⚠️的是;

使用java.ext.dirs,需要同时添加 <JAVA_HOME>/jre/lib/ext 和你自己的目录,不然只能使用你自己的目录。

实际语句:
java -Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:/tmp/lib/  -jar test.jar
<think> 我们之前讨论的是在Maven项目中如何引入本地JAR(通过pom.xml)。现在用户的问题转向了另一个场景:在命令运行一个已经打好的JAR(可能是可执行JAR,如何添加额外的外部JAR依赖。 用户需求:在运行一个JAR(比如使用`java -jar`命令,如何添加不在该JAR内的外部JAR依赖? 解决方案: 1. 使用`-classpath`(或`-cp`)参数指定额外的JAR路径,但是注意:当使用`-jar`选项,`-cp`参数会被忽略。 2. 替代方案:不使用`-jar`,而是通过指定主类的方式运行,同使用`-cp`来指定类路径(括主JAR和所有依赖JAR)。 具体步骤: 步骤1:将主JAR和所有外部JAR放在同一个目录下(比如`libs`目录),或者知道它们的路径。 步骤2:使用以下命令格式运行java -cp "主JAR路径:外部JAR1路径:外部JAR2路径:..." 主类全限定名 (在Windows中使用分号`;`分隔,Linux/macOS中使用冒号`:`分隔) 示例(Linux/macOS): java -cp "myapp.jar:libs/dependency1.jar:libs/dependency2.jar" com.example.Main 示例(Windows): java -cp "myapp.jar;libs\dependency1.jar;libs\dependency2.jar" com.example.Main 步骤3:如果外部JAR有很多,可以使用通配符(Java 6及以上支持)来指定一个目录下的所有JARjava -cp "myapp.jar:libs/*" com.example.Main # Linux/macOS java -cp "myapp.jar;libs\*" com.example.Main # Windows 注意:使用通配符,目录后面的`*`(在Windows中是`\*`)表示该目录下所有的JAR文件(不会递归子目录)。 为什么不能同使用`-jar`和`-cp`? 因为根据Java规范,当使用`-jar`JAR文件的类路径由JAR文件中的`Class-Path`清单属性决定,而忽略命令行中的`-cp`设置。 如果一定要使用`java -jar`,则需要在打修改MANIFEST.MF文件,在`Class-Path`中指定所有依赖JAR。但用户的情况是已经打好了,可能无法修改清单文件。 因此,推荐使用上述的`-cp`方式并指定主类来运行。 特殊情况:如果主JAR是一个可执行JAR(即有MANIFEST.MF中指定了Main-Class),那么也可以在不使用`-jar`的情况下通过指定主类来运行,因为主类信息在清单中,但我们需要通过`-cp`来指定类路径,然后显式指定主类。 如何获取主类? 如果用户知道主类的全限定名,可以直接使用。如果不知道,可以查看JAR的清单文件(使用命令:`jar tf myapp.jar | grep 'META-INF/MANIFEST.MF'`,然后解压查看,或者用`jar xf myapp.jar META-INF/MANIFEST.MF`提取清单),在清单中找到`Main-Class`属性。 因此,总结两种方式: 方式一:使用`-cp`并显式指定主类(推荐,灵活) 方式二:修改原有JAR的清单文件,添加`Class-Path`属性,然后使用`java -jar`运行(需要重新打,不推荐) 对于方式一,我们不需要修改原有的JAR文件,只需要知道主类即可。 示例步骤(假设不知道主类,需要提取主类信息): 1. 查看可执行JAR的主类: - 使用命令:`unzip -p myapp.jar META-INF/MANIFEST.MF | grep 'Main-Class'` - 或者:`jar xf myapp.jar META-INF/MANIFEST.MF`,然后查看META-INF/MANIFEST.MF文件中的`Main-Class`属性。 2. 假设主类为`com.example.Main`,然后运行- Linux/macOS: `java -cp "myapp.jar:libs/*" com.example.Main` - Windows: `java -cp "myapp.jar;libs\*" com.example.Main` 注意事项: - 如果外部依赖非常多,建议使用一个目录(如`libs`)来存放所有依赖JAR,然后使用通配符。 - 确保Java版本支持通配符(Java 6及以上)。 - 路径要正确,特别是相对路径和绝对路径。 另外,如果用户不想每次运行都输入长命令,可以编写一个简单的shell脚本(Linux/macOS)或批处理脚本(Windows)来简化。 例如,在Linux下创建一个`run.sh`: ```bash #!/bin/bash java -cp "myapp.jar:libs/*" com.example.Main ``` 在Windows下创建一个`run.bat`: ```batch @echo off java -cp "myapp.jar;libs\*" com.example.Main ``` 这样,用户只需运行脚本即可。 引用: [1] Java官方文档关于命令行类路径的说明:https://docs.oracle.com/javase/8/docs/technotes/tools/windows/classpath.html 相关问题: 1. 如何在命令行中运行一个含多个JARJava程序? 2. 使用`java -jar`如何添加外部依赖? 3. 如何查看一个可执行JAR的主类? </think> ### Java 运行 JAR 添加外部 JAR 依赖的方法 在 Java 命令运行 JAR 添加外部 JAR 依赖,主要有以下三种方法: --- #### **方法 1:使用 `-classpath` 参数(推荐)** **原理**:通过 `-cp` 或 `-classpath` 显式指定所有依赖路径 **命令格式**: ```bash java -cp "主JAR路径:依赖JAR1路径:依赖JAR2路径:..." 主类全限定名 ``` **关键要点**: 1. **路径分隔符**: - Linux/macOS:使用冒号 `:` ```bash java -cp "app.jar:lib/dep1.jar:lib/dep2.jar" com.example.Main ``` - Windows:使用分号 `;` ```cmd java -cp "app.jar;lib\dep1.jar;lib\dep2.jar" com.example.Main ``` 2. **通配符支持**(Java 6+): ```bash # 加载 lib 目录下所有 JAR java -cp "app.jar:lib/*" com.example.Main ``` 3. **路径规则**: - 使用绝对路径更可靠(如 `/home/user/lib/*`) - 相对路径基于当前工作目录解析 --- #### **方法 2:修改 MANIFEST.MF 文件(需重新打)** **原理**:在 JAR 的清单文件中预设 `Class-Path` 属性 **操作步骤**: 1. 解压 JAR 文件: ```bash jar xf app.jar ``` 2. 修改 `META-INF/MANIFEST.MF`,添加: ```manifest Class-Path: lib/dep1.jar lib/dep2.jar ``` 3. 重新打: ```bash jar cfm app.jar META-INF/MANIFEST.MF -C extracted/ . ``` **运行命令**: ```bash java -jar app.jar # 外部 JAR 需在指定路径下 ``` **限制**: - 依赖路径必须相对于主 JAR 的位置[^1] - 不支持通配符,需显式列出每个 JAR --- #### **方法 3:自定义类加载器(高级场景)** **原理**:通过程序动态加载外部 JAR **示例代码**: ```java URLClassLoader loader = new URLClassLoader( new URL[]{ new File("lib/dep1.jar").toURI().toURL(), new File("lib/dep2.jar").toURI().toURL() }, Main.class.getClassLoader() ); Class<?> mainClass = loader.loadClass("com.example.Main"); Method mainMethod = mainClass.getMethod("main", String[].class); mainMethod.invoke(null, (Object) args); ``` **适用场景**: - 需动态加载不同版本的依赖 - 插件化架构设计 - **注意**:需处理类加载器隔离问题 --- ### 方法对比与建议 | **方法** | 适用场景 | 优势 | 缺点 | |------------------|----------------------------------|--------------------------|--------------------------| | `-classpath`参数 | 快速运行、临测试 | 无需修改 JAR,灵活 | 命令较长 | | 修改 MANIFEST.MF | 正式部署、路径固定 | 支持 `java -jar` 简洁调用| 需重新打,路径限制[^1] | | 自定义类加载器 | 动态加载、插件系统 | 高度灵活 | 编码复杂,易出现类冲突 | > **最佳实践建议**: > 1. **简单场景** → 优先使用 `-cp "app.jar:lib/*"` > 2. **分发部署** → 修改 `MANIFEST.MF` 并约定 `lib/` 目录结构 > 3. **路径含空格** → 用引号裹路径:`-cp "app.jar:/path/with space/lib/*"` > 4. **调试技巧** → 使用 `-verbose:class` 验证类加载: > ```bash > java -cp "app.jar:lib/*" -verbose:class com.example.Main > ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值