十分钟解惑,让你真正用好MAVEN

我们日常工作中经常使用到maven,基本操作大家都会,但是涉及到父子pom继承和多模块的时候,很多时候使用的就会很混乱。

本篇文章主要针对maven的父子pom继承和多模块展开一些讨论,默认读者以使用过maven(可参考:https://www.ibofine.com/mavenbook/index.html )

1 MAVEN的关于依赖的基本配置

1.1 坐标(定位三要素)


    xxx.xxxxx.xxxx 
    xxx-xxxx 
    1.0.0 

    

1.2 定义属性


    
        hello 
        1.18.10 
    

1.3 申明依赖


    
        
            
            
                org.projectlombok
                lombok
                ${lombok-version} 
            
        
            
        
    

1.4 使用依赖


    
        
        
            org.projectlombok
            lombok
        
    
        
    

1.5 排除依赖


    
        hello 
        1.18.10 
        5.2.4.RELEASE 
    

    
        
            org.springframework
            spring-context
            ${spring.version}
            
                 
                    commons-logging
                    commons-logging
                
            
        
    

注意: 排除依赖存在一些未知的风险。比如 A-->B, B-->C, 当B的某个实现需要C, 而B的这实现会在A中运行的时候,排除了C就可能出错。

2 MAVEN依赖特性

2.1 maven的依赖存在传递性

如下:

A --> B , B-->C 则 A -- > B --> C

A 依赖了B包 , B中依赖C包 ,则 A如果自动会导入C ( 这个原因也是为什会有 排除依赖的存在,有时候A只想依赖B,而不想要C的时候。)

2.2 依赖顺序原则

依赖的顺序决定了最终使用的是哪个jar包,maven在解析依赖的时候的顺序是。先按最短路径,再按申明顺序

  • 最短路径优先
    如 a--> b --> c1.1.0 , a-->d --> e -->c1.2.0 则最终a中用的 c1.1.0

  • 申明顺序优先
    当路径相同的时候,不能判断使用哪个,这时候就是按照申明的顺序 ,如 a-->b-->c1.1.0 a-->d-->c1.2.0 此时,如果路径c是一样的,如果b的申明在d的前面,
    在使用的是 c1.1.0, 反之则为 c1.2.0

3 MAVEN继承特性(父子pom)

在pom文件中定义parent节点之后,子pom就可以继承父pom中的依赖和属性。

通常使用这个特性,在父pom中统一一些公共的东西,如jar版本,定义的一些属性等。主要就是抽离,统一管理。


    
        org.springframework.boot
        spring-boot-starter-parent
        2.2.2.RELEASE
         
    

    com.fun
    learn
    0.0.1-SNAPSHOT
    learn
    Demo project for Spring Boot

4 MAVEN聚合特性(module)

module可以看做是项目结构的描述,通过... 来定义,可以一起来打包的一个整体。


    com.fun
    learn
    0.0.1-SNAPSHOT
    learn
    Demo project for Spring Boot
    
    
        learn-api
        learn-server
    



5 MAVEN继承与聚合的区别

继承和聚合没有绝对要求的对应关系,他们目的上是不同。

  • 继承 讲究的是提炼统一公共的部分,子项目都使用,统一管理公共部分。(使用时候,可以单独定义一个父pom给所有的项目使用,统一项目中的jar包)

  • 聚合 更像是定义项目的结构,哪些作为一个整理。

6 MAVEN最佳实践

6.1 实践场景

假设有下面一个实例,一个系统(fun-mall)有 用户服务(user)、订单服务(order)、支付服务(pay)、商品服务(product), 他们之间通过dubbo调用。那么我们的使用maven可以统一成如下结构

xxx-api 提供dubbo调用的一些接口定义,**建议尽量少的依赖第三方的包。理论上他只是定义接口的和数据模型的。不然,当别人引用你的时候,可能出现第三方包的冲突,需要排除依赖**
xxx-server 启动jvm的进程

fun-mall
    |-- user
        |-- user-api
        |-- user-server
    |-- order
        |-- order-api
        |-- order-server
    |-- pay
        |-- pay-api
        |-- pay-server
    |-- product
        |-- product-api
        |-- product-server

针对上面的接口,我们创建项目的时候有两种比较合理的方式

6.2 实现方式1

  1. 创建一个项目 fun-mall 一个git仓库地址,fun-mall下面包含四个module, 每个module下面有包含xxx-api,xxx-server 两个module, 所有模块的父pom都使用fun-mall(继承和聚合的区别)
fun-mall
    |-- user
        |-- user-api
            |-- pom.xml
        |-- user-server
            |-- pom.xml
        |-- pom.xml
    |-- order
        |-- order-api
            |-- pom.xml
        |-- order-server
            |-- pom.xml
        |-- pom.xml
    |-- pay
        |-- pay-api
            |-- pom.xml
        |-- pay-server
            |-- pom.xml
        |-- pom.xml
    |-- product
        |-- product-api
        |-- product-server
        |-- pom.xml
    |-- pom.xml

具体配置

fun-mall的 pom.xml


    com.fun
    fun-mall
    0.0.1-SNAPSHOT
    fun-mall
    fun mall
    pom 
    
    
        user
        order
        pay
        product
    

    
        
    
    
    
        
            
        
    
    
    

user 的pom.xml


    
        com.fun
        fun-mall
        0.0.1-SNAPSHOT
    

    user
    user module
    pom 
    
    
        user-api
        order-server
    

    
        
            
        
    
    
    

user-api 的pom.xml


    
        com.fun
        fun-mall
        0.0.1-SNAPSHOT
    

    user-api
    user server api define 
    jar 

    
        
            
        
    
    
    

user-server的pom.xml


    
        com.fun
        fun-mall
        0.0.1-SNAPSHOT
    

    user-server
    user server impl
    jar 

    
        
            
        
    
    
    

    

order、pay、product的配置,同user模块类似即可。

6.3 实现方式2

  1. 创建一个fun-mall 做个父项目,没有模块。 然后分别创建四个 项目 user、order、pay、product 继承这个fun-mall 拱为5个git地址,所有项目的parent都是 fun-mall(继承和聚合的区别)
fun-mall
    |-- pom.xml

--------

|-- user
    |-- user-api
        |-- pom.xml
    |-- user-server
        |-- pom.xml
    |-- pom.xml

--------

|-- order
    |-- order-api
        |-- pom.xml
    |-- order-server
        |-- pom.xml
    |-- pom.xml

--------

|-- pay
    |-- pay-api
        |-- pom.xml
    |-- pay-server
        |-- pom.xml
    |-- pom.xml

--------

|-- product
    |-- product-api
    |-- product-server
    |-- pom.xml

这种方式的pom和上面在一个工程里面的方式是没有区别的,只是代码放在不同的仓库地址里面而已。

考虑到不同模块迭代速度不同,每个服务有自己的代码和分支进行开发,相比上面在整个一个git而言,更加灵活,不用对其他的服务产生分支。

其次,如果涉及到不同服务给不同团队开发,或者不同服务不需要看别人的实现的。只关心自己,则分开仓库很好的满足了

7 MAVEN deploy时父pom的问题

我们在deploy jar的时候,经常遇到一些因为父pom没有推导致推包失败的情况。所有一般推包看分为两种情况来处理

7.1 子pom未使用父pom的变量

这种情况下

  • 方式1:因为子pom没有使用父pom的变量,可能考虑单独deploy, 注释掉, 然后确保自己有artfactId和version ,直接deploy.

  • 方式2:先推一下父pom,在推子模块。如果pom有很多子模块(fun-mall的第一种),可考虑只推父pom(mvn clean deploy -N),
    不要推子模块(所有的模块都推,连实现server可能都推了,没必要),然后再推需要的jar(如,user-spi,)

7.2 子pom有使用父pom的变量

这种情况下, 因为使用父模块的变量,不能使用注释parent(不然不识别),所有只能先推一下父pom, 再推当前jar, 如上面的方式二

7.3 记录

  • 跳过Assembly:clean deploy -DskipAssembly=true
  • 只推父pom: mvn clean package deploy -Dmaven.test.skip=true -Drepository:snapshots -N
  • 分析maven的依赖树: mvn dependency:tree >text.txt

你可能感兴趣的:(十分钟解惑,让你真正用好MAVEN)