1

我对如何使用 mavenprovided范围和 Java 类加载器有误解。

假设我有一个类 ,MyClass并且这个类有一个serialize()方法,该方法采用一个枚举来描述序列化时要使用的 JSON 库。

其中一个 JSON 库是内部的,包含在我为 MyClass 分发的 JAR 中。简单的。

另一个 JSON 库是我想强制用户提供的第 3 方库。因此,我把它放在<scope>provided</scope>我的 pom.xml 中。

在测试期间一切都对我有用,但是当我尝试从外部使用我自己的库而我的类路径中没有第 3 方 JSON 库时,我得到了ClassNotFoundExceptions,即使我根本没有调用serialize()

我假设类只会“按需”加载,并且由于我没有调用serialize(),所以我不应该有任何运行时问题。我错了吗?有没有办法实现我在这里得到的?

4

4 回答 4

0

提供的范围基本上意味着它在运行时可用。3rd 方库(例如 JSON)通常不是这种情况。由于您要打包自己的 jar,因此您需要在其中包含所有必需的类。通常 Maven 用户使用 Maven Assembly Plugin 之类的东西来让 Maven 将所需的依赖项打包在一起并创建一个 jar。

于 2012-04-24T19:15:30.827 回答
0

'provided' 表示稍后会在运行时提供,因此不要将其包含在依赖项中(例如,将应用程序打包到 WAR 或 JAR 中时)

一个很好的例子——当针对一个 API 进行编译时,比如 Java EE API,你在编译时需要这个 jar,但你不需要将它包含在 WAR 文件中,因为服务器会有这些按定义分类。

您需要 servlet 类进行编译,但您的 WAR 文件将始终在容器已经在类路径中包含它的上下文中使用。

于 2012-04-24T19:57:31.570 回答
0

首先,您关于在需要时加载类的假设通常是正确的,但是它的工作方式与您想象的完全不同。类在需要时由类加载器连同它引用的所有类一起加载。它递归地发生。因此,当您第一次使用时MyClass,类加载器会尝试加载引用的这个第 3 方 JSON 库类。您正在谈论的那种运行时类加载可以通过使用 Java 反射功能来实现。然而,正如您可能已经知道的那样,这是完全不同的事情。

第二件事是providedMaven 中的范围。它的工作原理就像compile,但依赖项不会“去”与工件。这意味着此依赖项在编译时和测试执行时可用(然后由 Maven 提供)。但是,它不会作为工件的传递依赖项可见(通过依赖于这个的工件)。所以它不会被复制到WEB-INF/lib依赖于你的工件的 WAR 目录中,也不会jar-with-dependenciesmaven-assembly-plugin. 这里有一个强有力的假设,即您的工件的用户自己提供了这种依赖关系,因此他的职责是将这些类提供到类路径中。通常,它用于 Java EE 应用程序服务器,其中一些与平台相关的依赖项始终可用,例如 Servlet API、JPA、EJB 或 JMS。provided如果您的应用程序使用这些 API,那么您在范围内依赖它们。

所以最后,在你的情况下,你应该使用默认compile范围,因为确实需要这种依赖关系。

于 2012-04-24T20:18:34.103 回答
0

发现问题。我有一个静态初始化程序正在调用导致问题的第 3 方 JSON 库。

I do expect a class not found, if I'm a user of the api and not providing the 3rd party JAR. However, my concern was that I wasn't making any calls to cause the JAR to be needed. Static initializer threw me off.

于 2012-04-24T23:01:10.893 回答