Maven提供了范围和Java类加载器

时间:2012-04-24 19:09:48

标签: maven classpath classloader

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

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

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

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

在测试期间,一切都适合我,但是当我尝试在我的类路径中没有第三方JSON库时从外部使用我自己的库时,我得到ClassNotFoundException s,即使我不是打电话给serialize()

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

4 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

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

使用它时的一个很好的例子 - 当编译API时,比如Java EE API,你需要在编译时使用jar,但是你不需要将它包含在WAR文件中,因为服务器将按照定义包含这些类。

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

答案 2 :(得分:0)

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

第二件事是Maven的provided范围。它的工作方式与compile类似,但依赖关系不会与工件“一起”。这意味着这种依赖关系在编译时可用,也可用于测试执行(然后由Maven提供)。但是,它不会作为工件的传递依赖性(通过依赖于此工件的工件)可见。因此它不会被复制到依赖于工件的WAR的WEB-INF/lib目录,也不会被jar-with-dependencies的{​​{1}}描述符汇编。这里有一个强烈的假设,即你的工件的用户自己提供这种依赖,因此他的业务就是将这些类提供给classpath。通常,它在Java EE应用程序服务器上使用,其中一些与平台相关的依赖项始终可用,如Servlet API,JPA,EJB或JMS。如果您的应用程序使用这些API,那么您将使用maven-assembly-plugin范围依赖它们。

所以最后,在你的情况下,你应该使用defaut,provided范围,因为真的需要这种依赖。

答案 3 :(得分:0)

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

如果我是api的用户且未提供第三方JAR,我确实期望找不到课程。但是,我担心的是我没有打电话导致需要JAR。静态初始化程序让我失望。