Maven不能不关注啦
项目依赖
<scope>test<scope>
模拟版本冲突
除了compile其他scope不会传递
继承
导入
聚合
项目依赖
项目B引用项目A,如果项目A没有在本地仓库(自己建立的项目,先不说远程仓库)则项目B执行 mvn package报错。
需要项目A先执行 mvn install,成功后本地仓库会出现mavenA的坐标
此时mavenB再次执行 mvn package则会成功。
<scope>test<scope>
jar包的范围如果是test,只能在测试程序中使用,在主程序使用会报错。
模拟版本冲突
版本冲突简单说就是你的项目引入了相同的jar的不同版本,如果仅仅是代码版本不同也没事,问题是可能出现不同版本的方法不一样。
mavenA中依赖的是mavenS version1,mavenB中依赖的是mavenS version2,mavenC中依赖了mavenA,mavenB。
此时mavenC中就出现了两个mavenS的依赖,一个是version1,一个是version2。
在version1中Common只有一个静态方法demo1,而version2中的Common中新增了静态方法demo2。
在mavenA中调用了version1的demo1,mavenB中调用了version2的demo2。将mavenA,mavenB,mavenC依次执行 mvn install
此时在mavenC中调用mavenA,mavenB中的方法并不会出现编译错误。
mavenC使用 mvn package都不会报错,但是在运行时就会报错。
实际的开发过程中版本冲突远远比这种情况复杂需要我们根据报错信息判断是哪个jar冲突,然后再查询都哪里依赖了。将冲突的包排除掉。
补充一句,maven依赖传递的原则是 一:路径最近者优先;二:第一声明优先。
A->B->C->G21(guava 21.0)
E->F->G20(guava 20.0)
这样两条路径最终使用的是G20(原则一)
A->B->G21(guava 21.0)
E->F->G20(guava 20.0)
这样两条路径最终使用的是G21(原则二)
除了compile其他scope不会传递
在mavenB中添加Junit包,scope设置为compile,在mavenC中可以看到Junit这个包被传递了过来。
修改为test或者provided后Junit包则没有传递到mavenC中。
继承
父工程的packaging必须是pom,否则子工程无法继承。
在子工程中使用parent继承父工程
父pom中引用jar包后,子工程也会继承过来。
如果父项目引用的jar需要子项目按需加载则父项目可以将jar包的引入方式修改为放入dependencyManagement
子项目可以根据需要引入jar包,不需要指定版本号。
如果父项目既有dependencies也有dependencyManagement则类似于抽象类的样子。子类可以直接继承dependencies但是需要实现dependencyManagement。
导入
和java一样maven也遇到了多继承的瓶颈。在java中有一个类只能有一个父类,但是可以实现多个接口。在maven也有类似的做法。
在parentB中有两个jar,common3和common4。其中3是正常的引入,4是dependencyManagement引入。
在childA中使用pom+import的方式导入parentB,但是这种做法并不会将parentB中正常引入的common3继承过来,同样也不会将在dependencyManagement中的common4继承过来。
可以像common2一样在子项目中通过实现的方式导入common4。
但common3则无法这么使用。也就是说对于导入的方式,父工程的dependencies无论如何也无法继承过来。
dependencyManagement会被子类继承,下边这个例子,parentA中dependencies引入的common和dependencyManagement引入的common2。parentB通过import+pom实现了parentA但里边没有任何jar的引用。childB则继承了parentB,但是childB中没有common的jar但是可以通过不指定版本号的方式使用common2。
聚合
在子父工程里,想要打包子项目需要先安装父项目,如果子项目多了,则需要挨个执行命令。maven提供了一种聚合的方式,无论是执行 mvn clean 还是 mvn package 还是 mvn install都在父工程执行,无须在子工程单独执行。
但是聚合也不是外能的,如果子项目中除了使用了继承还是用了实现(import+pom)则父工程无法对实现工程做操作。