2

在我的 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!/”,但这对我不起作用。

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

亲切的问候,马蒂亚斯

4

1 回答 1

2

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

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

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

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


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

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

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

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

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

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

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

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

于 2012-05-10T21:07:24.030 回答