我正在使用 Gradle 构建项目。这是我的 build.gradle
:
plugins { id 'application' }
group 'my.group'
version '1.0'
sourceCompatibility = 1.11
repositories { mavenCentral() }
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
implementation group: 'org.xerial', name: 'sqlite-jdbc', version: '3.7.2'
}
mainClassName = 'my.group.App'
jar {
manifest {
attributes(
'Main-Class': mainClassName,
'Class-Path': configurations.runtimeClasspath.files.collect { it.name }.join(' ')
)
}
from configurations.runtimeClasspath
into ''
}
这会正确生成一个包含以下 META-INF/MANIFEST.MF 的 jar 文件:
Manifest-Version: 1.0
Main-Class: my.group.App
Class-Path: sqlite-jdbc-3.7.2.jar
[newline]
并且在这个jar文件的根目录中,确实存在 list 中引用的sqlite-jdbc-3.7.2.jar
文件;我手动验证了此 jar 文件内有一个名为 org.sqlite.JDBC 的类。
但是,使用 java -jar jarfile.jar
运行生成的 jar 会导致:
Exception in thread "main" java.lang.ExceptionInInitializerError
at my.group.LEManagerSqlite.<init>(LEManagerSqlite.java:64)
at my.group.LEManager.createLEManager(LEManager.java:80)
at my.group.GuiFrame.<init>(GuiFrame.java:60)
at my.group.App.openFromFile(App.java:23)
at my.group.App.main(App.java:19)
Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: org.sqlite.JDBC
at my.group.SqliteConnectionManager.<clinit>(SqliteConnectionManager.java:17)
... 5 more
Caused by: java.lang.ClassNotFoundException: org.sqlite.JDBC
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:315)
at my.group.SqliteConnectionManager.<clinit>(SqliteConnectionManager.java:14)
... 5 more
作为引用,SqliteConnectionManager
有一个加载 org.sqlite.JDBC
的静态初始化程序,这就是 SqliteConnectionManager.java:14
引用的内容> 在堆栈跟踪中:
Class.forName("org.sqlite.JDBC");
我使用 OpenJDK 11 和 OpenJ9 11 对此进行了测试,结果相同。我得出结论,我做错了什么,但我不明白是什么。
最佳答案
我发现我做错了什么:文档清楚地表明(doh!)Class-Path
指令在本地文件系统或网络中查找其他类路径资源。
JVM 不支持从主 jar 文件中包含的 jar 文件加载其他类,因此需要自定义加载代码。一个更简单的替代方法是从 jar 文件中解压附加类并直接包含它们。以这种方式构建的 jar 文件称为“fat jar”(或“uber jar”)。
有一个名为 Shadow 的 Gradle 插件,无需任何进一步配置即可构建此类 jar。
关于Java 不从 list 定义的类路径加载类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59715583/