Maven基础

官网 https://maven.apache.org/

Maven好处

  • 对项目结构有规定,约定优于配置的概念使得开发人员方便的在项目间切换
  • Maven提供了中央仓库,方便了下载依赖。Maven仓库简化了jar包之间的依赖关系管理与依赖冲突管理
  • Maven的生命周期管理,使得build,deploy很方便优雅
  • Maven项目发布和版本管理设计
  • Maven丰富的插件
  • 自动下载源码

Maven仓库

  • 支持远程仓库和本地仓库,可以使用 Sonatype Nexus 搭建自己的本地仓库,本地仓库可以减小对远程公共仓库的访问压力,可以管理自己的依赖

  • maven中的仓库分为两种,snapshot快照仓库和release发布仓库。snapshot快照仓库用于保存开发过程中的不稳定版本,release正式仓库则是用来保存稳定的发行版本。

  • 仓库配置: C:\Users\xs47604.m2\settings.xml

    1. mirror
      1. 为在pom中指定的Repository提供一个镜像仓库,通过Repository Id = mirrorOf
      2. id : 自定义的镜像库的唯一标识
      3. name : 自定义的可读的镜像库的名字
      4. url : Nexus镜像库的地址
      5. mirrorOf : 镜像库对应的pom中的Repository ID,比如mirrorOf=central的时候,所有对默认中央仓库的请求都会指向到这个mirror地址,当这个镜像出问题也不会再去请求remote仓库
    2. 当有多个mirror的时候,Update Project遵循以下规则
      1. mirrorOf相同,顺序优先,并且找不到不会去请求下一个mirror
      2. Update Project遵循: 先匹配同名的mirrorOf,然后才会匹配其他mirrorOf的条件,比如*
      3. Build遵循: 只匹配同名的mirrorOf,不会匹配其他条件,所以不因该为同一个remote设置多个镜像
    3. servers
      1. 用于deploy时的验证
      2. id需要与pom中的distributionManagement的repository保持一致
  • Nexus仓库Type

    1. group:其他镜像库的组,一般用于mirror的url
    2. hosted:自建仓库
    3. proxy:远程公共仓库的镜像
    4. virtual:本地镜像的虚拟
  • Nexus通过Repository -> 3rd party -> Artifact Upload上传自己的依赖包

  • Nexus通过Repository -> 3rd party -> Browse Storage删除自己的依赖包

  • 当ReUpload同名文件会报错

Maven项目生命周期

  • 相比而言,Ant的每个步骤都要你手工去定义,而Maven由它自己的预定义完成,这样的统一标准使得你不用你去理解每个项目的构建
  • Maven有三套相互独立的生命周期:Clean Lifecycle,Default Lifecycle,Site Lifecycle
  • Default Lifecycle
    1. mvn compile //让当前项目经历生命周期中的1-->7 阶段 :完成编译主源代码编译
    2. mvn package //让当前项目经历生命周期中的1-->17阶段 :完成打包
    3. mvn install //让当前项目经历生命周期中的1-->22阶段 :完成包安装到本地仓库
    4. mvn deploy //让当前生命经历生命周期中的1-->23阶段 :完成包部署到中心库中

pom.xml

基础配置

  • modelVersion:pom模型版本,maven2和3只能为4.0.0
  • groupId:组ID,maven用于定位
  • artifactId:在组中的唯一ID用于定位
  • version:项目版本, 当缺省的情况下,使用parent的version
  • packaging:项目打包方式,有以下值:pom, jar, maven-plugin, ejb, war, ear, rar, par

parent

  • Maven的多模块聚合
  • groupId:父项目的构件标识符
  • artifactId:父项目的唯一标识符
  • relativePath:Maven首先在当前项目找父项目的pom,然后在文件系统的这个位置(relativePath),然后在本地仓库,再在远程仓库找。
  • version:父项目的版本
  • 父项目的packaging必须是pom
  • 能被继承的设置
    1. dependency
    2. properties
    3. plugin
    4. ...

properties

  • project.build.sourceEncoding : UTF-8
  • java.version : 1.8 :
  • 当没有官方parent的时候需要以下properties, 否则update project得不到JaveSE1.8,编译也会失败
    1. maven.compiler.source>:$
    2. maven.compiler.target> :$
  • 自定义参数,引用方式:$

dependencyManagement

  • 用于parent定义多个子项目公共的依赖,从而避免依赖冲突
    1. parent的package需要为pom
    2. 子项目不会引用这些以来,需要在自项目的pom中引入
    3. 子项目的依赖不用写version,而使用父项目中的dependencyManagement的依赖版本
    4. 如果子项目指定了版本,会覆盖父项目的版本,但是不推荐这种做法,避免依赖冲突
  • 用于子项目引入其他项目的pom文件,相当于引入parent的另一种方式,实现多parent
    1. dependency的type是pom
    2. dependency的scope是import

dependencies

  • 无论scope和optional是什么,parent里面的依赖会被下载
  • 传递性:指A项目依赖B项目,B项目里依赖会被传递到该A项目,如何项目有相同依赖,层级最短的,最先被依赖的会被传递
  • scope
    1. compile : 默认,编译,测试依赖,会打包,有传递性
    2. provided : 编译,测试依赖,不会被打包,由其他方提供,比如servlet容器提供的servlet api,有传递性
    3. runtime : 运行,测试依赖,而编译时不需要,会被打包,有传递性,比如JDBC API编译需要而运行时才需要JDBC实现
    4. test : 只在测试时才依赖,没有传递性
    5. system : 跟provided 相似,但是在系统中要以外部JAR包的形式提供,maven不会在repository查找它,没有传递性
    6. import : 它只使用在dependencyManagement中,表示从其他项目的pom中导入依赖到当前项目
  • type : 默认为jar,可以指定其他格式的依赖,比如tar.gz
  • optional
    1. true表示这个依赖不会被传递
    2. 当你的项目依赖是不必要的并且你想节省下游项目的开销时考虑使用
    3. 当你的项目依赖可能会造成与其他项目依赖冲突时考虑使用

modules

  • 可以将另一个项目p2作为此项目的一个模块引入
    1. ../flow
    2. 此项目作为parent,他的packaging必须为pom,表示可以被继承
    3. 将p2作为,效果等于eclipse的build path里的projects
  • 可以在一个项目里创建多个module,各自有自己的pom

repositories

  • 当不指定的时候,默认的repositoriy id是central中央仓库repo.maven.org
  • 通常将central中央仓库在setting.xml中进行镜像,从而缓解中央仓库的压力,mirrorOf=central
  • 当指定的远程repositories的时候,会首先去指定的repositoriy寻找依赖,然后去指定的repositoriy的remote寻找,最后去中央仓库寻找
  • snapshots:enabled:true
    1. 默认false,表示sanpshots的版本不会被下载

distributionManagement

  • snapshotRepository
    1. snapshot快照仓库,版本号中带有 -SNAPSHOT的回deploy到这里
    2. 即使本地有这个版本,在打包时Maven还是会去镜像服务器下载最新版本
    3. url指向Polixy为Snapshot的Nexus仓库
  • repository
    1. release发布仓库,用于发布稳定的版本
    2. 如果本地仓库找到了这个版本的依赖,不会再去下载
    3. url指向Polixy为Release的Nexus仓库
  • repository的id必须与setting.xml中server的id对应

profiles切面

  • id : 比如id是release,用mvn deploy -P release,那么会用release切面的参数覆盖原来的参数
  • 与properties,distributionManagement合用,可以灵活切换发布的颁布

build

  • defaultGoal : 执行构建时默认的goal或phase,如jar:jar或者package等

  • directory : 构建的结果所在的路径,默认为${basedir}/target目录

  • finalName : 构建的最终打包文件名字,不带后缀和路径,该名字可能在其他plugin中被改变

  • resource : 设置classpath资源文件目录,不设置的时候默认${basedir}/src/main/resources

    1. directory:资源文件目录,update project的时候会添加到build path里的Source目录
    2. include/exclude: ds/,**/*.sh :不影响build path的添加,但是影响package打包任务
    3. targetPath : 目标目录地址,package的时候会将资源打包置目标目录,如果不指定,默认打包置jar包的classes下面
    4. filtering : true开启对资源文件内容的变量过滤,与filters合用
    5. 只有设置了resource,默认的resource : ${basedir}/src/main/resources就没有了,需要显示的添加默认的resource
  • filters : 通过 key-value.properties的value替换资源文件里的key

  • plugins 给出构建过程中所用到的插件

    1. id,唯一标识
    2. goals,要执行的插件的goal(可以有多个)
    3. phase,插件的goal要嵌入到Maven的phase中执行,如package
    4. inherited,该execution是否可被子项目继承
    5. configuration,该插件的自定义配置参数,需要从镜像库下载插件才能提示标签

Maven插件

spring-boot-maven-plugin

  • spring-boot:repackage : 默认的gole,在mvn package之后,再次打包可执行的jar/war,同时保留mvn package生成的jar/war为.origin
    1. configuration.mainClass : 入口函数名,默认找到的第一个main
    2. configuration.layout : 可以改变MANIFEST.MF文件的Main-Class属性值,默认使用项目packaging
      1. JAR : Main-Class: org.springframework.boot.loader.JarLauncher :可执行jar
      2. WAR : Main-Class: org.springframework.boot.loader.warLauncher : 可执行war
      3. ZIP/DIR : Main-Class: org.springframework.boot.loader.PropertiesLauncher : 类似于JAR
      4. NONE: Main-Class等于mainClass,不可执行
    3. executable : 默认false, 为*nix打包一个可执行的文件
      1. 当你打算直接执行它的时候使用
      2. java -jar或者放到servlet容器时不推荐使用
      3. 添加软链接,使其成为系统服务 : ln -s appname.jar /etc/init.d/appname
      4. 使用service appname start/stop/status/restart
      5. 自定义参数 : 在jar包相同路径下创建一个appname.conf文件
        • JAVA_HOME=/usr/local/jdk
        • JAVA_OPTS=-Xmx1024M
        • LOG_FOLDER=/custom/log
      6. 设置开机自启动
  • spring-boot:run : 启动app

Maven 源码插件

<plugin>  
     <artifactId>maven-source-plugin</artifactId>  
     <configuration>  
         <attach>true</attach>  
     </configuration>  
     <executions>  
         <execution>  
             <phase>compile</phase>  
             <goals>  
                 <goal>jar</goal>  
             </goals>  
         </execution>  
     </executions>  
 </plugin>  

Takari Maven Wrapper

  • https://github.com/takari/takari-maven-plugin/blob/master/README.md
  • 第三方Maven Wrapper插件,灵感来源于Gradle,用于统一maven版本,使得项目的使用者使用开发时的maven版本
  • 在项目根目录下执行任意以下命令
    1. mvn -N io.takari:maven:wrapper
    2. mvn -N io.takari:maven:wrapper -Dmaven=3.3.9 : 指定Maven的release版本
    3. mvn -N io.takari:maven:wrapper -DdistributionUrl=http://repo.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip : 指定repository和Maven版本
  • 以上命名会在项目中生成mvnw,mvnw.cmd,.mvn文件/夹
  • 通过mvnw来代替mvn的任何命令,第一次使用命令会下载相应版本的maven到.m2/wrapper目录中,作为mvnw的M2_HOME

Maven标准打包插件 Assembly,用于拷贝资源文件和依赖到指定目录然后打包

  • org.apache.maven.plugins[Default,No need to add this groupId]/maven-assembly-plugin
  • pom.xml
    1. < phase>package< /phase>
    2. < goal>single< /goal>
    3. configuration:
      1. < descriptor>assembly.xml< /descriptor>
      2. < attach>false< /attach>: deploy的时候不会上传zip到Maven镜像仓库
      3. < tarLongFileMode>posix< /tarLongFileMode>

        修复Exception:Failed to execute goal org.apache.maven.plugins:maven-assembly-plugin:3.0.0:single (assembly-tar-gz) on project datasource: Execution assembly-tar-gz of goal org.apache.maven.plugins:maven-assembly-plugin:3.0.0:single failed: group id '2000056500' is too big ( > 2097151 ). Use STAR or POSIX extensions to overcome this limit

  • assembly.xml
    1. format : zip/tar.gz/tar.bz2/jar/dir/war/others

    2. fileSet :

       <fileSet>  
           <directory>${basedir}/ds/ratesds</directory>   
           <outputDirectory>\ds</outputDirectory>  
       </fileSet>
      
    3. dependencySets:将scope为runtime的依赖打包到lib目录下

       <dependencySet>  
           <useProjectArtifact>true</useProjectArtifact>  
           <outputDirectory>resource/lib</outputDirectory>
           <scope>runtime</scope>  
       </dependencySet> 
      

构建项目

Maven Archetypes

  • maven-archetype-quickstart : 一般项目
  • maven-archetype-webapp : Web项目
  • maven-archetype-plugin : Maven插件

Maven项目A引入Maven项目B

  • 将B发布到本地仓库:mvn install
  • 将B作为依赖引入到A

Maven Modules

  • 创建父项目时把pom以外的文件删除,父项目只有pom文件有用,父项目的packaging方式为pom
  • 每个module都是一个独立的项目,在创建module的时候eclipse会同时创建项目
  • install父项目会install所有子项目

注意事项

  • pom.xml报错: 删除.m2的依赖

      Multiple annotations found at this line:
      Failure to transfer org.springframework.cloud:spring-cloud-starter-netflix-archaius:jar:2.0.0.RELEASE 
      from http://sd-5f33-c5d5.nam.nsroot.net:8081/nexus/content/repositories/public was cached in the local repository
    
  • 本地项目依赖

    1. package的时候可能找不到依赖,需要将本地项目依赖install或者删除.m2里的相关依赖