我如何检查jar文件依赖项

时间:2014-07-04 16:27:58

标签: java maven

我来自.NET背景,这些天我需要做一些JAVA工作。我不太明白的一件事是JAvA运行时如何解析其jar依赖项。例如,我想使用javax.jcr来做一些节点添加。所以我知道我需要添加这两个依赖项,因为我需要使用javax.jcr.Node和org.apache.jackrabbit.commons.JcrUtils。

      <dependency>
           <groupId>javax.jcr</groupId>
           <artifactId>jcr</artifactId>
           <version>2.0</version>
      </dependency>
      <dependency>
           <groupId>org.apache.jackrabbit</groupId>
           <artifactId>jackrabbit-jcr-commons</artifactId>
           <version>2.8.0</version>
      </dependency>
          </dependency>

现在我通过了编译,但是在运行时遇到异常。然后有人告诉我再添加一个解决问题的依赖项。

         <dependency>
               <groupId>org.apache.jackrabbit</groupId>
               <artifactId>jackrabbit-jcr2dav</artifactId>
               <version>2.6.0</version>
          </dependency>

根据我的理解,jackrabbit-jcr-commons需要使用jackrabbit-jcr2dav才能运行。如果jar错过了依赖,它怎么能通过编译?而且我怎么知道我错过了jcr-common的这种特殊依赖?这是一个普遍的问题,它不一定要特定于java jcr。

4 个答案:

答案 0 :(得分:2)

Java没有任何内置的方法来声明库之间的依赖关系。在运行时,当需要一个类时,Java ClassLoader会尝试从类路径中的所有jar加载它,如果缺少该类,则会出现异常。您需要的所有jar必须在类路径中明确列出。你不能只添加一个jar,并希望Java能够从这个jar依赖项中传递加载类,因为jar依赖是一个Maven概念,而不是Java概念。什么,BTW,禁止一个库编写器一次编译1000个相互依赖的类,但将编译的类放在3个不同的jar中。

剩下的就是Maven。我对JCR一无所知。但是如果在Maven上发布的jar A依赖于在Maven上发布的jar B,那么它应该在其依赖列表中列出B,并且Maven应该在下载A时下载B(并将两个jar放在类路径中)。

但问题是,某些库对其他库的依赖性很大。例如,Spring对Hibernate有本机支持。如果您选择将Spring与Hibernate一起使用,那么您需要在依赖项中显式声明Hibernate。但是你也可以选择在没有Hibernate的情况下使用Spring,在这种情况下你不需要将Hibernate放在依赖项中。 Spring因此选择不将Hibernate声明为它自己的依赖项之一,因为在使用Spring时Hibernate不是总是

最后,归结为阅读您正在使用的库的文档,根据您在这些库中使用的功能,了解需要添加的依赖项。

答案 1 :(得分:1)

Maven在编译时计算传递依赖性,因此编译通过正常。这里的问题是,默认情况下,maven不会构建一个合适的java -cp命令行来启动您的应用程序及其所有应用程序。依赖(直接和传递)。

解决它的两个选项:

  1. 调整您的Maven项目以构建一个&#34;胖罐&#34; - jar将包含所有依赖项中所有需要的类。请参阅使用pom.xml代码段的回答来执行此操作:https://stackoverflow.com/a/16222971/162634。然后,您只需java -cp myfatjar.jar my.app.MainClass
  2. 即可启动
  3. 对于多模块项目,有多个结果工件(通常是不同的java程序),构建自定义assembly.xml是有意义的,它将告诉Maven如何打包工件以及要包含哪些依赖项。您需要在结果包中提供某种类型的脚本,其中包含正确的java -cp ...命令。据我所知,没有#34;官方&#34; Maven插件在编译/打包期间构建这样的脚本。
  4. 免费的Maven book或多或少解释了依赖关系和程序集的工作原理。

答案 2 :(得分:1)

您的问题混合了Maven(一种以Java为中心的依赖解析工具)和Java编译时和运行时类解析。两者都完全不同。

简化来说,Java .jar是Java .class文件的.zip文件。在编译期间,每个Java源文件(例如MyClass.java)都会生成一个具有相同名称的Java字节码文件(MyClass.class)。为了使编译成功,Java文件中提到的所有类必须在编译时在类路径中可用(但请注意,使用反射和运行时类名解析,ala Class.forName("MyOtherClass")可以避免这种情况完全;也可以使用几个类加载器,它们可以相互独立地定义...)。

但是,在编译之后,您不需要将所有.class文件放在同一个Jar中。开发人员可以在罐子之间拆分他们的.class文件,但他们认为合适。只要使用这些jar的程序只编译时引用并且运行时加载具有所有依赖项的编译时和运行时可用的类,您将看不到任何运行时错误。编译使用它们的程序时,.jar文件中的类重新编译;但是,如果它们的任何依赖项在运行时失败,您将获得运行时异常。

使用Maven时,每个maven工件(通常是一个jar文件)都会声明(在其pom.xml清单文件中)它所依赖的工件。如果任何意义上使用my-company:my-library-core而不需要my-company:my-library-random-extension,最佳做法是使-core依赖-random-extension 1}},但通常-random-extension取决于-core。您所依赖的工件的任何依赖关系都将得到解决,并且会被带入&#34;当maven跑。

另外,从您的问题中,提醒一句 - jackrabit-jcr2dav版本2.6.0很可能希望与jackrabbit-jcr-commons版本2.6.0一起运行,而不是{ {1}}。

答案 3 :(得分:0)

如果我不得不猜测(不花太多时间钻研这个特定项目的Maven层次结构),我相信你的问题是由jackrabbit-jcr-commonsjackrabbit-api具有可选依赖性这一事实引起的。这意味着除非您在POM中重新声明它,否则您不会自动获得该依赖关系(以及它的依赖关系)。

一般来说,可选的依赖关系是项目内结构问题的创可贴解决方案。引用关于主题的maven文档(http://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html):

  

当它不可能时使用可选依赖项(for   无论什么原因)将项目拆分为子模块。这个想法是   某些依赖项仅用于某些功能   项目,如果没有使用该功能,则不需要。   理想情况下,这样的特征将被分成依赖的子模块   关于核心功能项目...这个新的子项目将有   只有非可选的依赖项,因为如果您需要它们,那么它们都是必需的   决定使用子项目的功能。

     

然而,由于项目不能分开(再次,无论如何   原因),这些依赖项被声明为可选的。如果用户想要   使用与可选依赖项相关的功能,他们必须这样做   在自己的项目中重新声明可选依赖项。这不是   处理这种情况最明确的方法,但两者都是   可选的依赖项和依赖项排除是止损   的解决方案。

一般来说,探索依赖关系的POM会揭示这种问题,尽管这个过程可能会非常痛苦。