如何访问位于源文件夹中的 Jar 文件?

Posted

技术标签:

【中文标题】如何访问位于源文件夹中的 Jar 文件?【英文标题】:How to access Jar file located within source folders? 【发布时间】:2012-05-10 20:37:15 【问题描述】:

在我的 Java 项目中,我使用的是 H2 内存数据库,当我初始化我的应用程序时,我必须为此加载 JDBC 驱动程序。我想要/需要动态加载 H2 .jar 文件,所以我执行以下操作:

String classname = "org.h2.Driver";
URL u = new URL("jar:file:libs/h2.jar!/");
URLClassLoader ucl = new URLClassLoader(new URL[]  u );
Driver d = (Driver) Class.forName(classname, true, ucl).newInstance();
DriverManager.registerDriver(new DriverShim(d));

当我将 H2 .jar 文件放入我的 Java 源代码文件夹之外的“libs”文件夹中时(即,在 Eclipse 中,这个“libs”目录与“src”文件夹处于同一级别),然后这个方法工作正常。但是,不幸的是,我必须将此 H2 .jar 文件放入源代码文件夹树内的文件夹中,但位于主类文件夹下方。

例如,我的 Java 包结构在 Eclipse 中是这样的:

<project>/src/my/app/MyApp.java              // main class of my application
<project>/src/my/app/sub/package/h2.jar      // how to access this?
<project>/libs/h2.jar                        // loading from here works

我知道这很愚蠢,但不幸的是我不得不使用这种奇怪的设置。但我不知道的是:如何编辑我的 Java 代码(如上所列)以使用此设置?

编辑:这也必须在 Eclipse 之外工作,因此将 JAR 文件添加到 Eclipse 中的 Java 构建路径对我来说不是选项。

EDIT2:我已经尝试加载“jar:file:my/app/sub/package/h2.jar!/”,但这对我不起作用。

提前感谢所有有用的想法!

亲切的问候,马蒂亚斯

【问题讨论】:

你试过 jar:file:my/app/sub/package/h2.jar 了吗? 您描述的“奇怪的设置”是一个非常正常的目录结构。没有理由将 JAR 文件放在您的 src 文件夹中。听起来您的类路径中根本没有 h2.jar @thinksteep:是的,试过了,但没用。 @matt b:我知道没有理由将 JAR 文件放入 src 文件夹中——但正如我所说,我必须忍受它,我无法改变这个要求。 现在这是一个奇怪的构建系统 - 不必要地使开发人员的生活复杂化。你是说这是商业作品?将您的故事提交给thedailywtf.com 怎么样?) 【参考方案1】:

在某些框架中,引用 JAR 中的文件可以使用 classpath: 前缀来完成。 我怀疑 URLClassLoader 本身是否支持它,但值得一试(例如classpath:/my/app/sub/package/h2.jar)。但由于这不适用于 URLClassLoader,这里有其他方法:

一种方法是编写您自己的 ClassLoader,它从类路径读取 JAR 文件(使用 getResourceAsStream),将其解压缩(使用 ZipInputStream)到内存(例如字节数组的映射)并从那里加载类。

另一种稍微简单的方法是从类路径中读取 JAR 文件并将其写入临时文件。然后,您可以使用普通的 URLClassLoader 从中加载类。这样做的缺点是必须将文件写入文件,并且在 JVM 退出(unless using Java 7 或更高版本)之前可能无法删除该文件。

我正在使用第二种方法(复制到临时文件)in one project,尽管我将它用于launch an external process。我很想知道你为什么有这样的要求。如果只是将整个应用程序放在一个 JAR 中,那么有许多更简单的方法可以实现这一点(Maven Assembly Plugin、Maven Shade Plugin、Jar Jar Links、One-JAR 等等)。


不,这不是作业,而是一个在线构建系统,它使用我在 my/app/* 下的类和其他几个类(不是我的)来自动构建整个解决方案。无论如何,我无法向您提供有关该系统内部结构的更多详细信息,因为我不了解它们。如前所述,我只需要忍受它,这就是我在这里问的原因......

听起来你是在 WTF 环境中工作(它有名字吗?),所以这里有一些方法可以开始破解它:

详细了解您的环境,尤其是以下绝对文件路径:保存源文件的目录、保存生成的 .class 文件的目录以及程序运行时的当前工作目录。

如果您可以获得程序在运行时打印的任何类型的输出,您可以将一些调试代码放入您的应用程序中,您可以在其中使用File.listFiles() 来抓取机器的目录树。如果您只能从编译时发生的事情中获得输出,则可以通过创建自己的annotation processor(apt 是 javac 自 Java 6 以来的一部分)在编译期间执行您自己的代码,尽管我不确定注释是否处理器必须先单独编译。

可以从user.dir 系统属性读取工作目录,并且可以从java.class.path 系统属性获取类文件的位置(除非使用自定义类加载器)。无法保证源目录中的 JAR 文件会被复制到类路径中,因此您可能需要四处查看。

然后,当您知道 JAR 文件的文件路径后,您可以使用 new File("path/to/h2.jar").toURI().toURL() 获取指向它的 URL,然后您可以将其传递给 URLClassLoader。

如果没有其他方法,请上传库的源代码并将它们与您的项目一起编译。

从长远来看,尝试将 WTF 构建环境替换为使用标准构建工具(如 Maven)和通用 CI 服务器(如 Jenkins)的构建环境。项目有很多库依赖项是正常的,因此您不需要绕过构建环境来使用它们。

【讨论】:

不幸的是,使用“类路径:”不起作用。我必须使用这个环境,因为它是一种自动的在线构建系统,我只能在 my/app/* 下上传文件和文件夹 我已经更新了我的答案。您可以使用这些提示了解更多关于环境的信息吗?环境是否公开,以便我们查看? 我猜你是对的,这真的是一个 WTF 环境。我将尝试与它的所有者取得联系,并找出所有类文件最终所在的目录。另外,也许他可以手动将 .jar 文件复制到适当的目录中...

以上是关于如何访问位于源文件夹中的 Jar 文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何在导出的 jar 文件中播放 .wav 文件?

Tomcat下webapps夹中root文件夹作用及如何发布项目至root文件夹中

在与位于项目目录中的 .jar 文件相同的文件夹中创建一个文件

使用idea写ssm的时候提示源文件夹中的文件找不到

如何从 netbeans 中的 .jar 文件访问 javadoc

如何使用 AngularJS 访问位于不同 js 文件中的变量数据