maven在平常工作中使用很多,但大多数时候都是copy and change pom.xml,内部的配置理解不够,再遇到打包,依赖问题每次都很头疼,本文就陆续的整理工作中遇到常见的问题,希望能够避免重复采坑,并能沉淀对maven打包工具的理解

maven 命令


  1. mvn dependency:tree 查看maven依赖树
  2. mvn dependency:resolve 查看最终maven依赖的jar包,但是这个不会考虑例如shade插件的黑白名单排掉的包
  3. # 命令行跳过常规的检查,也可以通过profile管理,打包时指定profile,profile中指定pluginManagement,参照flink父pom指定的
  4. maven clean package -Denforcer.skip=true -Dmaven.test.skip=true -DskipTests -Drat.skip=true -Dcheckstyle.skip=true -Dscalastyle.skip=true
  5. # 查看某个子module最终的打包pom
  6. mvn help:effective-pom
  1. <profile>
  2. <id>fast</id>
  3. <activation>
  4. <property>
  5. <name>fast</name>
  6. </property>
  7. </activation>
  8. <build>
  9. <pluginManagement>
  10. <plugins>
  11. <plugin>
  12. <groupId>org.apache.rat</groupId>
  13. <artifactId>apache-rat-plugin</artifactId>
  14. <configuration>
  15. <skip>true</skip>
  16. </configuration>
  17. </plugin>
  18. <plugin>
  19. <groupId>org.apache.maven.plugins</groupId>
  20. <artifactId>maven-checkstyle-plugin</artifactId>
  21. <configuration>
  22. <skip>true</skip>
  23. </configuration>
  24. </plugin>
  25. <plugin>
  26. <groupId>org.scalastyle</groupId>
  27. <artifactId>scalastyle-maven-plugin</artifactId>
  28. <configuration>
  29. <skip>true</skip>
  30. </configuration>
  31. </plugin>
  32. <plugin>
  33. <groupId>org.apache.maven.plugins</groupId>
  34. <artifactId>maven-enforcer-plugin</artifactId>
  35. <configuration>
  36. <skip>true</skip>
  37. </configuration>
  38. </plugin>
  39. <plugin>
  40. <groupId>org.apache.maven.plugins</groupId>
  41. <artifactId>maven-javadoc-plugin</artifactId>
  42. <configuration>
  43. <skip>true</skip>
  44. </configuration>
  45. </plugin>
  46. <plugin>
  47. <groupId>com.github.siom79.japicmp</groupId>
  48. <artifactId>japicmp-maven-plugin</artifactId>
  49. <configuration>
  50. <skip>true</skip>
  51. </configuration>
  52. </plugin>
  53. </plugins>
  54. </pluginManagement>
  55. </build>
  56. </profile>

然后在打包时指定profile

  1. mvn clean package -DskipTests -Dfast
  2. # 也可以通过
  3. mvn clean package -DskipTests -Pfast

一种是直接通过-P指定profile,一种是通过环境变量等于specific value时激活。具体可以参看:profile指定策略:https://maven.apache.org/guides/introduction/introduction-to-profiles.html

maven shade plugin

maven shade build插件通常用来管理冲突,目前用的比较多的功能是黑名单和白名单,以及relocation功能

黑白名单机制

artifactSet标签 可以通过include和exclude来进行白名单和黑名单的控制,artifact级别的(maven包级别);顺序是白名单先生效,黑名单再生效,如果没有白名单,默认包括全部。如果设置了白名单的话,那么只有白名单中指定的jar才会保留。filters标签可以进行更细粒度的控制,可以再单个artifact内,进行include和exclude的控制,是文件级别的黑名单和白名单,artifact可以使用通配符号。生效顺序是artifactSet和filter的白名单,再进行黑名单排除,但是通过filter指定的文件,是不受影响的,始终保留。可以在mvn打包命令执行时查看最终include和exclude的类有哪些。

参考:
https://maven.apache.org/plugins/maven-shade-plugin/examples/includes-excludes.html
https://shalk.xyz/post/maven-shade-plugin-usage/
mvn依赖传递性:https://blog.csdn.net/tojohnonly/article/details/79101841

注意:
在代码中引入一个第三方依赖的时候最好通过mvn dependency:tree 查看下会引入哪些具体的三方依赖, 常见的三方框架包为了避免冲突,要趁早relocation掉

plugin配置和父pom中配置项merge策略

假设父亲的plugin有如下的配置项

  1. <configuration>
  2. <items>
  3. <item>parent-1</item>
  4. <item>parent-2</item>
  5. </items>
  6. <properties>
  7. <parentKey>parent</parentKey>
  8. </properties>
  9. </configuration>

而子module对同一个插件有如下的配置项

  1. <configuration>
  2. <items>
  3. <item>child-1</item>
  4. </items>
  5. <properties>
  6. <childKey>child</childKey>
  7. </properties>
  8. </configuration>

通过以下命令,查看最终的有效pom如下

  1. mvn help:effective-pom
  1. <configuration>
  2. <items>
  3. <item>child-1</item>
  4. </items>
  5. <properties>
  6. <childKey>child</childKey>
  7. <parentKey>parent</parentKey>
  8. </properties>
  9. </configuration>

可以看到默认的merge策略是遍历element name,父module中的元素只有在子module中没有的时候才会被append到子module中,merge的过程只是根据element name来进行。

如果子module指定成如下的形式

  1. <configuration>
  2. <items combine.children="append">
  3. <!-- combine.children="merge" is the default -->
  4. <item>child-1</item>
  5. </items>
  6. <properties combine.self="override">
  7. <!-- combine.self="merge" is the default -->
  8. <childKey>child</childKey>
  9. </properties>
  10. </configuration>

生成的有效文件如下

  1. <configuration>
  2. <items combine.children="append">
  3. <item>parent-1</item>
  4. <item>parent-2</item>
  5. <item>child-1</item>
  6. </items>
  7. <properties combine.self="override">
  8. <childKey>child</childKey>
  9. </properties>
  10. </configuration>

可以注意到和默认行为(merge)不同,append会将父module的element都追加上来,不管子module中是否存在,override则忽略父module的相应element的配置项。

使用是还需要注意以下几点

  1. 这个属性只针对声明的element生效,如上面xml中只会对items和properties下的第一层元素生效,如果item还有下集元素,将应用默认的merge策略
  2. combine.* 这些属性也会集成,如果在父module中添加此属性,子module都会直接继承,除非子module单独指定这个属性
  3. 以上的config merge策略,只是针对plugin的配置项,对pom中的其他元素并没有效果

参考: https://blog.sonatype.com/2011/01/maven-how-to-merging-plugin-configuration-in-complex-projects/

maven bom

https://stackoverflow.com/questions/41816411/why-the-maven-child-referencing-versions-from-bom-does-not-work
http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
https://blog.csdn.net/lonelymanontheway/article/details/80623408

maven的生命周期

http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Built-in_Lifecycle_Bindings

maven goal可以不和build phase绑定,单独执行 http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Built-in_Lifecycle_Bindings
一个build phase可以有一个或多个goal,依次执行,一个goal可以属于多个phase,那么会被执行多次

  1. mvn clean dependency:copy-dependencies package

clean 和 package都是一个phase,而dependency:copy-dependencies是某个插件的goal,这样的执行顺序就是clean-> dependency:copy-dependencies -> package


常见避坑做法


Maven仓库配置说明