如何优化idea 查看pom依赖关系项

Maven类包冲突终极三大解决技巧 mvn dependency:tree
Maven类包冲突终极三大解决技巧 mvn dependency:tree
Maven对于新手来说是《步步惊心》,因为它包罗万象,博大精深,因为当你初来乍到时,你就像一个进入森林的陌生访客一样迷茫。
Maven对于老手来说是《真爱配方》,因为它无所不能,利如刀锋,使用Maven做开发,如饮美酒如悦美人。
Maven对于新手来说,最痛苦的一件事莫过于包之间的冲突,由于Maven的依赖传递性,当你引入一个依赖类时,其身后的依赖类也一起如过江之鲫纷至沓来了。
A依赖于B及C,而B又依赖于X、Y,而C依赖于X、M,则A除引B及C的依赖包下,还会引入X,Y,M的依赖包(一般情况下了,Maven可通过&scope&等若干种方式控制传递依赖)。
这里有一个需要特别注意的,即B和C同时依赖于X,假设B依赖于X的1.0版本,而C依赖于X的2.0版本,A究竟依赖于X的1.0还是2.0版本呢?
这就看Classloader的加载顺序了,假设Classloader先加载X_1.0,而它就不会再加载X_2.0了,如果A恰恰希望使用X_2.0呢,血案就这样不期而遇了。
第一板斧:找到传递依赖的鬼出在哪里?
dependency:tree是把照妖照,pom.xml用它照照,所有传递性依赖都将无处遁形,并且会以层级树方式展现,非常直观。
以下就是执行dependency:tree后的一个输出:
[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ euler-foundation ---
[INFO] com.hsit:euler-foundation:jar:0.9.0.1-SNAPSHOT
[INFO] +- com.rop:rop:jar:1.0.1:compile
[INFO] |& +- org.slf4j:slf4j-api:jar:1.7.5:compile
[INFO] |& +- org.slf4j:slf4j-log4j12:jar:1.7.5:compile
[INFO] |& +- log4j:log4j:jar:1.2.16:compile
[INFO] |& +- commons-lang:commons-lang:jar:2.6:compile
[INFO] |& +- commons-codec:commons-codec:jar:1.6:compile
[INFO] |& +- javax.validation:validation-api:jar:1.0.0.GA:compile
[INFO] |& +- org.hibernate:hibernate-validator:jar:4.2.0.Final:compile
[INFO] |& +- org.codehaus.jackson:jackson-core-asl:jar:1.9.5:compile
[INFO] |& +- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.5:compile
[INFO] |& +- org.codehaus.jackson:jackson-jaxrs:jar:1.9.5:compile
[INFO] |& +- org.codehaus.jackson:jackson-xc:jar:1.9.5:compile
[INFO] |& \- com.fasterxml.jackson.dataformat:jackson-dataformat-xml:jar:2.2.3:compile
[INFO] |&&&& +- com.fasterxml.jackson.core:jackson-core:jar:2.2.3:compile
[INFO] |&&&& +- com.fasterxml.jackson.core:jackson-annotations:jar:2.2.3:compile
[INFO] |&&&& +- com.fasterxml.jackson.core:jackson-databind:jar:2.2.3:compile
[INFO] |&&&& +- com.fasterxml.jackson.module:jackson-module-jaxb-annotations:jar:2.2.3:compile
[INFO] |&&&& \- org.codehaus.woodstox:stax2-api:jar:3.1.1:compile
[INFO] |&&&&&&& \- javax.xml.stream:stax-api:jar:1.0-2:compile
刚才吹嘘dependency:tree时,我用到了“无处遁形”,其实有时你会发现简单地用dependency:tree往往并不能查看到所有的传递依赖。不过如果你真的想要看所有的,必须得加一个-Dverbose参数,这时就必定是最全的了。
全是全了,但显示出来的东西太多,头晕目眩,有没有好法呢?当然有了,加上Dincludes或者Dexcludes说出你喜欢或讨厌,dependency:tree就会帮你过滤出来:
Dincludes=org.springframework:spring-tx
过滤串使用groupId:artifactId:version的方式进行过滤,可以不写全啦,如:
mvn dependency:tree -Dverbose -Dincludes=asm:asm &
就会出来asm依赖包的分析信息:
[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ ridge-test ---
[INFO] com.ridge:ridge-test:jar:1.0.2-SNAPSHOT
[INFO] +- asm:asm:jar:3.2:compile
[INFO] \- org.unitils:unitils-dbmaintainer:jar:3.3:compile
[INFO]&&& \- org.hibernate:hibernate:jar:3.2.5.ga:compile
[INFO]&&&&&& +- cglib:cglib:jar:2.1_3:compile
[INFO]&&&&&& |& \- (asm:asm:jar:1.5.3:compile - omitted for conflict with 3.2)
[INFO]&&&&&& \- (asm:asm:jar:1.5.3:compile - omitted for conflict with 3.2)
[INFO] ------------------------------------------------------------------------
对asm有依赖有一个直接的依赖(asm:asm:jar:3.2)还有一个传递进入的依赖(asm:asm:jar:1.5.3)
第二板斧:将不想要的传递依赖剪除掉
承上,假设我们不希望asm:asm:jar:1.5.3出现,根据分析,我们知道它是经由org.unitils:unitils-dbmaintainer:jar:3.3引入的,那么在pom.xml中找到这个依赖,做其它的调整:
&&& &dependency& &
&&&&&&& &groupId&org.unitils&/groupId& &
&&&&&&& &artifactId&unitils-dbmaintainer&/artifactId& &
&&&&&&& &version&${unitils.version}&/version& &
&&&&&&& &exclusions& &
&&&&&&&&&&& &exclusion& &
&&&&&&&&&&&&&&& &artifactId&dbunit&/artifactId& &
&&&&&&&&&&&&&&& &groupId&org.dbunit&/groupId& &
&&&&&&&&&&& &/exclusion& &
&&&&&&&&&&& &!-- 这个就是我们要加的片断 --& &
&&&&&&&&&&& &exclusion& &
&&&&&&&&&&&&&&& &artifactId&asm&/artifactId& &
&&&&&&&&&&&&&&& &groupId&asm&/groupId& &
&&&&&&&&&&& &/exclusion& &
&&&&&&& &/exclusions& &
&&& &/dependency& &
再分析一下,你可以看到传递依赖没有了:
&&& [INFO] &
&&& [INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ ridge-test --- &
&&& [INFO] com.ridge:ridge-test:jar:1.0.2-SNAPSHOT &
&&& [INFO] \- asm:asm:jar:3.2:compile &
&&& [INFO] ------------------------------------------------------------------------ &
&&& [INFO] BUILD SUCCESS &
第三板斧:查看运行期类来源的JAR包
有时,你以为解决了,但是偏偏还是报类包冲突(典型症状是java.lang.ClassNotFoundException或Method不兼容等异常),这时你可以设置一个断点,在断点处通过下面这个我做的工具类来查看Class所来源的JAR包:
&&& package com.ridge. &
&&& import java.io.F &
&&& import java.net.MalformedURLE &
&&& import java.net.URL; &
&&& import java.security.CodeS &
&&& import java.security.ProtectionD &
&&&& * @author : chenxh
&&&& * @date: 13-10-31
&&& public class ClassLocationUtils { &
&&&&&&& /**
&&&&&&&& * 获取类所有的路径
&&&&&&&& * @param cls
&&&&&&&& * @return
&&&&&&&& */ &
&&&&&&& public static String where(final Class cls) { &
&&&&&&&&&&& if (cls == null)throw new IllegalArgumentException("null input: cls"); &
&&&&&&&&&&& URL result = &
&&&&&&&&&&& final String clsAsResource = cls.getName().replace('.', '/').concat(".class"); &
&&&&&&&&&&& final ProtectionDomain pd = cls.getProtectionDomain(); &
&&&&&&&&&&& if (pd != null) { &
&&&&&&&&&&&&&&& final CodeSource cs = pd.getCodeSource(); &
&&&&&&&&&&&&&&& if (cs != null) result = cs.getLocation(); &
&&&&&&&&&&&&&&& if (result != null) { &
&&&&&&&&&&&&&&&&&&& if ("file".equals(result.getProtocol())) { &
&&&&&&&&&&&&&&&&&&&&&&& try { &
&&&&&&&&&&&&&&&&&&&&&&&&&&& if (result.toExternalForm().endsWith(".jar") || &
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& result.toExternalForm().endsWith(".zip")) &
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& result = new URL("jar:".concat(result.toExternalForm()) &
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& .concat("!/").concat(clsAsResource)); &
&&&&&&&&&&&&&&&&&&&&&&&&&&& else if (new File(result.getFile()).isDirectory()) &
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& result = new URL(result, clsAsResource); &
&&&&&&&&&&&&&&&&&&&&&&& } &
&&&&&&&&&&&&&&&&&&&&&&& catch (MalformedURLException ignore) {} &
&&&&&&&&&&&&&&&&&&& } &
&&&&&&&&&&&&&&& } &
&&&&&&&&&&& } &
&&&&&&&&&&& if (result == null) { &
&&&&&&&&&&&&&&& final ClassLoader clsLoader = cls.getClassLoader(); &
&&&&&&&&&&&&&&& result = clsLoader != null ? &
&&&&&&&&&&&&&&&&&&&&&&& clsLoader.getResource(clsAsResource) : &
&&&&&&&&&&&&&&&&&&&&&&& ClassLoader.getSystemResource(clsAsResource); &
&&&&&&&&&&& } &
&&&&&&&&&&& return result.toString(); &
&&&&&&& } &
随便写一个测试,设置好断点,在执行到断点处按alt+F8动态执行代码(intelij idea),假设我们输入:
Java代码& 收藏代码
ClassLocationUtils.where(org.objectweb.asm.ClassVisitor.class) &
即可马上查出类对应的JAR了:
这就是org.objectweb.asm.ClassVisitor类在运行期对应的JAR包,如果这个JAR包版本不是你期望你,就说明是你的IDE缓存造成的,这时建议你Reimport一下maven列表就可以了,如下所示(idea):
Reimport一下,IDE会强制根据新的pom.xml设置重新分析并加载依赖类包,以得到和pom.xml设置相同的依赖。(这一步非常重要哦,经常项目组pom.xml是相同的,但是就是有些人可以运行,有些人不能运行,俗称人品问题,其实都是IDE的缓存造成的了
idea清除缓存,为了提高效率不建议采用reimport重新起开启项目的方式,建议采用idea自带的功能,File-&Invalidate Caches 功能直接完成清除idea cacheSponsered by
Maven - 依赖管理
Maven 核心特点之一是依赖管理。一旦我们开始处理多模块工程(包含数百个子模块或者子工程)的时候,模块间的依赖关系就变得非常复杂,管理也变得很困难。针对此种情形,Maven 提供了一种高度控制的方法。
传递依赖发现
这种情形经常可见,当一个库 A 依赖于其他库 B. 另一工程 C 想要使用库 A, 那么该工程同样也需要使用到库 B。
Maven 可以避免去搜索所有需要的库资源的这种需求。通过读取工程文件(pom.xml)中的依赖项,Maven 可以找出工程之间的依赖关系。
我们只需要在每个工程的 pom 文件里去定义直接的依赖关系。Maven 则会自动的来接管后续的工作。
通过传递依赖,所有被包含的库的图形可能会快速的增长。当重复的库存在时,可能出现的情形将会持续上升。Maven 提供一些功能来控制可传递的依赖的程度。
决定当多个手动创建的版本同时出现时,哪个依赖版本将会被使用。 如果两个依赖版本在依赖树里的深度是一样的时候,第一个被声明的依赖将会被使用。
直接的指定手动创建的某个版本被使用。例如当一个工程 C 在自己的以来管理模块包含工程 B,即 B 依赖于 A, 那么 A 即可指定在 B 被引用时所使用的版本。
包含在构建过程每个阶段的依赖。
任何可传递的依赖都可以通过 &exclusion& 元素被排除在外。举例说明,A 依赖 B, B 依赖 C,因此 A 可以标记 C 为 “被排除的”。
任何可传递的依赖可以被标记为可选的,通过使用 &optional& 元素。例如:A 依赖 B, B 依赖 C。因此,B 可以标记 C 为可选的, 这样 A 就可以不再使用 C。
传递依赖发现可以通过使用如下的依赖范围来得到限制:
该范围表明相关依赖是只在工程的类路径下有效。默认取值。
该范围表明相关依赖是由运行时的 JDK 或者 网络服务器提供的。
该范围表明相关依赖在编译阶段不是必须的,但是在执行阶段是必须的。
该范围表明相关依赖只在测试编译阶段和执行阶段。
该范围表明你需要提供一个系统路径。
该范围只在依赖是一个 pom 里定义的依赖时使用。同时,当前工程的POM 文件的
部分定义的依赖关系可以取代某特定的 POM。
通常情况下,在一个共通的工程下,有一系列的工程。在这种情况下,我们可以创建一个公共依赖的 pom 文件,该 pom 包含所有的公共的依赖关系,我们称其为其他子工程 pom 的 pom 父。 接下来的一个例子可以帮助你更好的理解这个概念。
下面是上述依赖图表的细节:
App-UI-WAR 依赖于 App-Core-lib 和 App-Data-lib.
Root 是 App-Core-lib 和 App-Data-lib 的父类。
Root 在其依赖模块里定义了 Lib1,lib2, Lib3 3个依赖关系。
App-UI-WAR 的 POM 文件如下:
&project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd"&
&modelVersion&4.0.0&/modelVersion&
&groupId&panyname.groupname&/groupId&
&artifactId&App-UI-WAR&/artifactId&
&version&1.0&/version&
&packaging&war&/packaging&
&dependencies&
&dependency&
&groupId&panyname.groupname&/groupId&
&artifactId&App-Core-lib&/artifactId&
&version&1.0&/version&
&/dependency&
&/dependencies&
&dependencies&
&dependency&
&groupId&panyname.groupname&/groupId&
&artifactId&App-Data-lib&/artifactId&
&version&1.0&/version&
&/dependency&
&/dependencies&
&/project&
App-Core-lib 的 POM 文件如下:
&project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd"&
&artifactId&Root&/artifactId&
&groupId&panyname.groupname&/groupId&
&version&1.0&/version&
&modelVersion&4.0.0&/modelVersion&
&groupId&panyname.groupname&/groupId&
&artifactId&App-Core-lib&/artifactId&
&version&1.0&/version&
&packaging&jar&/packaging&
&/project&
App-Data-lib 的 POM 文件如下:
&project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd"&
&artifactId&Root&/artifactId&
&groupId&panyname.groupname&/groupId&
&version&1.0&/version&
&modelVersion&4.0.0&/modelVersion&
&groupId&panyname.groupname&/groupId&
&artifactId&App-Data-lib&/artifactId&
&version&1.0&/version&
&packaging&jar&/packaging&
&/project&
Root 的 POM 文件如下:
&project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd"&
&modelVersion&4.0.0&/modelVersion&
&groupId&panyname.groupname&/groupId&
&artifactId&Root&/artifactId&
&version&1.0&/version&
&packaging&pom&/packaging&
&dependencies&
&dependency&
&groupId&panyname.groupname1&/groupId&
&artifactId&Lib1&/artifactId&
&version&1.0&/version&
&/dependency&
&/dependencies&
&dependencies&
&dependency&
&groupId&panyname.groupname2&/groupId&
&artifactId&Lib2&/artifactId&
&version&2.1&/version&
&/dependency&
&/dependencies&
&dependencies&
&dependency&
&groupId&panyname.groupname3&/groupId&
&artifactId&Lib3&/artifactId&
&version&1.1&/version&
&/dependency&
&/dependencies&
&/project&
现在,当我们构建 App-UI-WAR 工程时, Maven 将会通过遍历依赖图找到所有的依赖关系,并且构建该应用程序。
通过上面的例子,我们可以学习到以下关键概念:
公共的依赖可以使用 pom 父的概念被统一放在一起。App-Data-lib 和 App-Core-lib 工程的依赖在Root 工程里列举了出来(参考 Root的包类型,它是一个 POM).
没有必要在 App-UI-W 里声明 Lib1, lib2, Lib3 是它的依赖。 Maven 通过使用可传递的依赖机制来实现该细节。随笔 - 897&
文章 - 0&评论 - 0&trackbacks - 0
我们先看一个简单的例子:
1 &project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"&
&!-- maven model version --&
&modelVersion&4.0.0&/modelVersion&
&!-- project group id & artifact id --&
&groupId&com.freesoft.mvn-webapp&/groupId&
&artifactId&mvnwebapp&/artifactId&
&!-- packing type --&
&packaging&war&/packaging&
<span style="color: #
&!-- version --&
<span style="color: #
&version&1.0-SNAPSHOT&/version&
<span style="color: #
&name&mvnwebapp Maven Webapp&/name&
<span style="color: #
&url&http://maven.apache.org&/url&
<span style="color: #
<span style="color: #
<span style="color: #
&dependencies&
<span style="color: #
<span style="color: #
&!-- JUnit --&
<span style="color: #
&dependency&
<span style="color: #
&groupId&junit&/groupId&
<span style="color: #
&artifactId&junit&/artifactId&
<span style="color: #
&version&4.11&/version&
<span style="color: #
&scope&test&/scope&
<span style="color: #
&/dependency&
<span style="color: #
<span style="color: #
&/dependencies&
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
&finalName&mvnwebapp&/finalName&
<span style="color: #
&pluginManagement&
<span style="color: #
<span style="color: #
<span style="color: #
&groupId&org.apache.tomcat.maven&/groupId&
<span style="color: #
&artifactId&tomcat7-maven-plugin&/artifactId&
<span style="color: #
&version&2.1&/version&
<span style="color: #
&configuration&
<span style="color: #
&tomcat-url&http://localhost:8080/manager/html&/tomcat-url&
<span style="color: #
&server&tomcat_localtest&/server&
<span style="color: #
&/configuration&
<span style="color: #
<span style="color: #
&/plugins&
<span style="color: #
&/pluginManagement&
<span style="color: #
<span style="color: #
<span style="color: #
&properties&
<span style="color: #
&struts.version&2.3.15&/struts.version&
<span style="color: #
&mysql.version&5.1.29&/mysql.version&
<span style="color: #
&hibernate.version&4.3.1.Final&/hibernate.version&
<span style="color: #
&/properties&
<span style="color: # &/project&
下面分段讲解。
1. 基本信息
modelVersion
Maven模块版本,目前我们一般都取值4.0.0
整个系统的名称。
artifactId
子模块名称。
打包类型,可取值:jar,war等等,这个配置用于package的phase,具体可以参见package运行的时候启动的plugin,后面有机会我们会讲述如何配置打包的插件。
2. dependencies
依赖关系。实际上pom之间存在好三种关系:继承、依赖、聚合。我们先讲依赖,这也是最重要的关系。
依赖项的groupId
artifactId
依赖项的artifactId
依赖项的版本
依赖项的适用范围:
compile,缺省值,适用于所有阶段,会随着项目一起发布。
provided,类似compile,期望JDK、容器或使用者会提供这个依赖。如servlet.jar。
runtime,只在运行时使用,如JDBC驱动,适用运行和测试阶段。
test,只在测试时使用,用于编译和运行测试代码。不会随项目发布。
system,类似provided,需要显式提供包含依赖的jar,Maven不会在Repository中查找它。
之前例子里的junit就只用在了test中。
exclusions
排除项目中的依赖冲突时使用。
2.1 关于排除依赖冲突
我们可能经常会遇到这样一个问题:我们的项目有两个依赖项:A & B,而且A和B同时依赖了C,但不是同一个版本。那么我们怎么办呢?
2.1.1 添加检查插件
<span style="color: # &reporting&
<span style="color: #
<span style="color: #
<span style="color: #
&groupId&org.apache.maven.plugins&/groupId&
<span style="color: #
&artifactId&maven-project-info-reports-plugin&/artifactId&
<span style="color: #
<span style="color: #
&/plugins&
<span style="color: #
&/reporting&
然后运行:mvn project-info-reports:dependencies,来查看依赖项报告。
2.1.2 去除依赖项
如果我们需要在某个dependency中去除某个依赖项,直接这样即可:
1 &!-- Struts2 --&
&dependency&
&groupId&org.apache.struts&/groupId&
&artifactId&struts2-core&/artifactId&
&version&${struts.version}&/version&
&exclusions&
&exclusion&
&groupId&org.freemarker&/groupId&
&artifactId&freemarker&/artifactId&
<span style="color: #
&/exclusion&
<span style="color: #
&/exclusions&
<span style="color: #
&/dependency&
我的repository下面有个例子就直接拿来用了:
<span style="color: # &modelVersion&4.0.0&/modelVersion&
<span style="color: #
<span style="color: #
&groupId&com.thoughtworks.xstream&/groupId&
<span style="color: #
&artifactId&xstream-parent&/artifactId&
<span style="color: #
&version&1.4.3&/version&
<span style="color: #
<span style="color: #
&artifactId&xstream&/artifactId&
<span style="color: #
&packaging&jar&/packaging&
<span style="color: #
&name&XStream Core&/name&
其中的parent表示父pom是com.thoughtworks.xstream的xstream-parent的1.4.3版本。继承关系比较简单,这里不做过多介绍。
我们可以通过一个大的项目来整合各个小的模块:
<span style="color: # &modules&
<span style="color: #
&module&my-app&/module&
<span style="color: #
&/modules&
属性表述类似于EL表达式,ANT中也同样有,所以我们的properties字段可以这样使用:
<span style="color: #
&!-- mysql --&
<span style="color: #
&dependency&
<span style="color: #
&groupId&mysql&/groupId&
<span style="color: #
&artifactId&mysql-connector-java&/artifactId&
<span style="color: #
&version&${mysql.version}&/version&
<span style="color: #
&/dependency&
6.1 plugin
Plugin的配置如下:
1 &pluginManagement&
&groupId&org.apache.tomcat.maven&/groupId&
&artifactId&tomcat7-maven-plugin&/artifactId&
&version&2.1&/version&
&configuration&
&tomcat-url&http://localhost:8080/manager/html&/tomcat-url&
&server&tomcat_localtest&/server&
<span style="color: #
&/configuration&
<span style="color: #
<span style="color: #
&/plugins&
<span style="color: #
&/pluginManagement&
我们可以看到同样要哟偶groupId、artifactId、version还有一些配置参数。
6.2 resource
指定你在Build时需要的资源文件:
1 &resources&
&resource&
&targetPath&WEB-INF/resource&/targetPath&
&!-- 不对文件中的表达式进行处理 --&
&filtering&false&/filtering&
&directory&${basedir}/src/test/resources&/directory&
&includes&
&include&include.xml&/include&
&/includes&
<span style="color: #
&excludes&
<span style="color: #
&exclude&exclude.xml&/exclude&
<span style="color: #
&/excludes&
<span style="color: #
&/resource&
<span style="color: #
&/resources&
阅读(...) 评论()解决Maven项目相互依赖/循环依赖/双向依赖的问题 - MOVING的笔记本 - ITeye技术网站
博客分类:
很多时候随着项目的膨胀,模块会越来越多,如果设计上 稍有不慎就会出现模块之间相互依赖的情况。这对于使用Maven的用户是比较痛苦的,因为出现模块之间相互依赖的话在构建的时候就会失败,Maven通常要先编译被依赖的模块,如果出现相互依赖Maven就不知道该怎么办了。下图描述了三个Maven模块相互依赖的场景:&
图 1. A、B、C三个模块相互依赖
图中模块C依赖于模块B,模块B依赖于模块A,而模块A又依赖于模块C,这样就出现了相互依赖情况,如果运行mvn compile会出现如下错误:
[INFO] Scanning for projects... [ERROR] The projects in the reactor contain a cyclic reference: Edge between 'Ve rtex{label='org.kuuyee.sample:module-C:1.0-SNAPSHOT'}' and 'Vertex{label='org.ku uyee.sample:module-B:1.0-SNAPSHOT'}' introduces to cycle in the graph org.kuuyee .sample:module-B:1.0-SNAPSHOT --& org.kuuyee.sample:module-A:1.0-SNAPSHOT --& or g.kuuyee.sample:module-C:1.0-SNAPSHOT --& org.kuuyee.sample:module-B:1.0-SNAPSHO T -& [Help 1][ERROR] [ERROR] To see the full stack trace of the errors, re-run Maven with the -e swit ch.[ERROR] Re-run Maven using the -X switch to enable full debug logging.[ERROR] [ERROR] For more information about the errors and possible solutions, please rea d the following articles: [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/ProjectCycleEx ception
1. 使用build-helper-maven-plugin解决相互依赖的问题我的解决办法就是先把相互依赖的模块整合在一起,相当于把这些模块合并成一个单独的模块统一编译,
如下图:图 2. 合并A、B、C三个模块为D模块
这样就产生了一个合并模块D,我们把它当做一个辅助构建模块,然后让A、B、C模块都依赖于D模块,这样的话就可以成功编译A、B和C模块,
如下图: 图 3. 基于D模块来分别编译A、B、C三个模块
要想把A、B、C三个模块整合在一起编译,需要借助build-helper-maven-plugin插件,这个插件在Maven构建周期提供一些辅助功能,下面列出插件的提供的功能列表: build-helper:add-source:添加更多的构建源码目录 build-helper:add-test-source:添加更多的测试源码目录 build-helper:add-resource:添加更多的资源目录 build-helper:add-test-resource:添加更多的测试资源目录 build-helper:attach-artifact:在安装和部署周期附加artifacts build-helper:maven-version:添加一个指定当前Maven版本的属性 build-helper:parse-version:添加一个指定组件版本的属性 build-helper:released-version:决定当前项目的最终版本 build-helper:remove-project-artifact:从本地资源库中移除项目的artifacts build-helper:reserve-network-port:Reserve a list of random and unused network ports. 在这里我们要用到build-helper:add-source这个功能,将模块A、B、C的源码路径加进来。 我们再添加一个辅助模块D,在辅助模块D中使用build-helper-maven-plugin插件,然后让模块A、B、C都依赖于辅助模块D,模块D的POM模型如下: 例 1. 辅助模块D的POM模型
&project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&
&groupId&org.kuuyee.sample&/groupId&
&artifactId&sample-parent&/artifactId&
&version&1.0-SNAPSHOT&/version&
&relativePath&../../pom.xml&/relativePath&
&modelVersion&4.0.0&/modelVersion&
&groupId&org.kuuyee.sample&/groupId&
&artifactId&module-D&/artifactId&
&version&1.0-SNAPSHOT&/version&
&packaging&jar&/packaging&
&name&module-D&/name&
&url&http://maven.apache.org&/url&
&properties&
&project.build.sourceEncoding&
&/project.build.sourceEncoding&
&module.a.src&../../module/module-A/src/main/java&/module.a.src&
&module.b.src&../../module/module-B/src/main/java&/module.b.src&
&module.c.src&../../module/module-C/src/main/java&/module.c.src&
&/properties&
&plugins&&!-- 解决模块相互依赖,综合所有相互依赖代码统一编译 --&
&groupId&org.codehaus.mojo&/groupId&
&artifactId&build-helper-maven-plugin&/artifactId&
&executions&
&execution&
&id&add-source&/id&
&phase&generate-sources&/phase&
&goal&add-source&/goal&
&configuration&
&source&${module.a.src}&/source&
&source&${module.b.src}&/source&
&source&${module.c.src}&/source&
&/sources&
&/configuration&
&/execution&
&/executions&
&/plugins&
&dependencies&
&dependency&
&groupId&junit&/groupId&
&artifactId&junit&/artifactId&
&version&3.8.1&/version&
&scope&test&/scope&
&/dependency&
&/dependencies&
&/project&
【转载地址】http://www.blogjava.net/kuuyee/archive//353158.html
maven处理循环依赖
 在多maven工程的项目里,如果工程间存在循环依赖,构建就会报错。本文介绍一下循环依赖要怎么处理
  
  1、什么是循环依赖
  
  如果工程A依赖工程B,工程B又依赖工程A,就会形成循环依赖。或者A依赖B,B依赖C,C依赖A,也是循环依赖
  
  总的来说,在画出工程依赖图之后,如果发现工程间的依赖连线形成了一个有向循环图,则说明有循环依赖的现象
  
  如果循环依赖发生在工程之间,则会影响构建,因为maven不知道应该先编译哪个工程。如果循环依赖发生在同一个工程的模块之间,虽然不影响编译,但是也是一种不好的实践,说明模块的设计有问题,应该避免
  
  如果在模块内部,有几个类互相调用的话,我觉得可能是正常的。比如观察者模式里面,Observer和Observable就是互相依赖的
  
  2、怎么解决循环依赖
  
  目前知道有2个办法可以解决
  
  第一个办法是用build-helper-maven-plugin插件来规避。比如A依赖B,B依赖C,C依赖A的情况。这个插件提供了一种规避措施,即临时地将工程A、B、C合并成一个中间工程,编译出临时的模块D。然后A、B、C再分别依赖临时模块D进行编译
  
  这种方法可以解决无法构建的问题,但是只是一个规避措施,工程的依赖关系依然是混乱的
  
  第二个办法是通过重构,从根本上消除循环依赖
  
  3、如何重构
  
  目前也知道2个重构的思路
  
  第一个办法是平移,比如A和B互相依赖,那么可以将B依赖A的那部分代码,移动到工程B中,这样一来,B就不需要继续依赖A,只要A依赖B就可以了,从而消除循环依赖
  
  第二个办法是下移,比如A和B互相依赖,同时它们都依赖C,那么可以将B和A相互依赖的那部分代码,移动到工程C里,这样一来,A和B相互之间都不依赖,只继续依赖C,也可以消除循环依赖
  
  这两种重构方式都是可行的,具体采用哪种方式要根据实际情况来判断。不管采取哪种方式,都需要对代码进行修改,有时候并不是那么容易的
【转载地址】/kaifa_qita/7063.html
浏览 24261
浏览: 448120 次
来自: 南京
你好 XmlOutputFormatter 请问这个类是在什么 ...
总结的好,文章给力。
还是使用ssh得了,window的不稳定~~~
谢谢,需要这篇文章太久了
感谢分享,有没有一种方式可以,即保证模块互相独立,又能解决相互 ...

我要回帖

更多关于 maven 下载pom依赖包 的文章

 

随机推荐