预期读者

对 maven 有一定基础的同学,想对 maven 有系统了解的同学

文章思路

本文先会说下 maven 的几个基本概念:依赖,仓库,生命周期和插件、
然后是maven 的聚合和继承、
然后再说 settings 文件和 pom 文件的相关配置、
最后再列出常用插件及使用 maven 遇到的一些问题及解决办法

第一部分-依赖

传递依赖

A–>B–>C 当前项目为A,A依赖于B,B依赖于C,那么 A 依赖于 C

依赖范围

如果 A-> B ,B 依赖于 junit 包,但 B 的 junit 包配置的 <scope>test</scope>,则 junit 不会被 A 依赖。

常用的依赖范围有

  • compile (默认)

表示被依赖项目需要参与当前项目的编译,还有后续的测试,运行周期也参与其中,是一个比较强的依赖。打包的时候通常需要包含进去

  • test

不会有传递依赖,也不会打包,依赖项目仅仅参与测试相关的工作,包括测试代码的编译和执行,例如:junit

  • provided

参与编译,测试,运行,但打包的时候不会打进去,如 servlet-api

  • runtime

表示被依赖项目无需参与项目的编译,不过后期的测试和运行周期需要其参与。与compile相比,跳过了编译而已。例如JDBC驱动,适用运行和测试阶段

  • system

从参与度来说,和provided相同,不过被依赖项不会从maven仓库下载,而是从本地文件系统拿。需要添加systemPath的属性来定义路径

依赖仲裁

最短路径原则

A->B->C->common1.1.jar
A->common1.0.jar

那么A最终会依赖common1.0.jar

加载先后原则

A->B
A->C
B->common1.0.jar
C->common1.1.jar

A同时依赖B和C,那么B和C谁先加载,就依赖谁的common.jar

排除依赖传递

一般用于去除一些无用的依赖,或使用最新的依赖包;如 spring 和 hibernate 都会使用 slf4j ,可以自行决定是用 spring 依赖的,还是用 hibernate 依赖的,或者两者都不用,使用最新的。

比如spring-core排除commons-loggoing

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>${spring.version}</version>
  <exclusions>
    <exclusion>
      <artifactId>commons-logging</artifactId>
      <groupId>commons-logging</groupId>
    </exclusion>
  </exclusions>
</dependency>

第二部分-仓库

maven 的仓库分为本地仓库、私服、和远程仓库,仓库中放置的是 jar 包和 插件。

查找方式:本地->私服->远程

私服对于个人开发是不需要的,但对于团队开发是必须的;因为项目肯定会分为各个模块,每个人开发的模块需要部署到私服上去,对方才能访问到。

pom 中配置仓库(个人用或开源项目)

<repositories>
    <!--配置阿里云的仓库,用于下载常用 jar 包-->
    <repository>
          <id>public</id>
        <name>aliyun nexus</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
        <releases><enabled>true</enabled></releases>
    </repository>
    <!--配置公司仓库,用于下载其它模块包-->
    <repository>
          <id>company</id>
        <name>company nexus</name>
        <url>http://company/nexus/content/groups/public/</url>
        <releases><enabled>true</enabled></releases>
        <snapshots><enabled>true</enabled></snapshots>    <!--这个默认是 false 需要自己打开 -->
    </repository>
</repository>

<!--配置插件仓库-->
<pluginRepositories>
    <pluginRepository>
        <id>public</id>
        <name>aliyun nexus</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
        <releases><enabled>true</enabled></releases>
        <snapshots><enabled>false</enabled></snapshots>
    </pluginRepository>
</pluginRepositories>

将仓库配置到 settings 文件中(公司用项目)

<profiles>
    <profile>
        <id>repo</id>
         <repositories>
           <repository>
             <id>public</id>
             <name>aliyun nexus</name>
             <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
             <releases><enabled>true</enabled></releases>
           </repository>
         </repositories>
   </profile>
   
    <profile>
      <id>env-dev</id>

      <activation>
        <property>
          <name>target-env</name>
          <value>dev</value>
        </property>
      </activation>

      <properties>
        <tomcatPath>/path/to/tomcat/instance</tomcatPath>
      </properties>
    </profile>
</profiles>

<!--激活属性配置,可以激活多个-->
<activeProfiles>
    <activeProfile>repo</activeProfile>
    <activeProfile>env-dev</activeProfile>
</activeProfiles>

将开发的模块布置到私服

在 pom 中配置发布的地址,在 settings 中配置发布的用户名和密码。
pom 配置发布地址

<distributionManagement>
   <repository>
       <id>server-rel-id</id>    <!--这个 id 需要和 servers 中的 id 一致-->
       <name>release-publish</name>
       <url>http://company/public</url>
   </repository>
   <snapshotRepository>
       <id>server-rel-id-snapshot</id>
       <name>release-publish</name>
       <url>http://company/public</url>
   </snapshotRepository>
</distributionManagement>

settings 中配置用户名密码

<servers>
    <server>
      <id>server-rel-id</id>
      <username>repouser</username>
      <password>repopwd</password>
    </server>
    <server>
      <id>server-rel-id-snapshot</id>
      <username>repouser</username>
      <password>repopwd</password>
    </server>
</servers>

常用仓库

  • 阿里云仓库
<repository>
      <id>public</id>
    <name>aliyun nexus</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
    <releases><enabled>true</enabled></releases>
</repository>

第三部分-生命周期和插件

maven 的生命周期是抽象的,具体的实现由插件完成。

Maven定义了三套生命周期:clean、default、site,每个生命周期都包含了一些阶段(phase)插件的目标 绑定到生命周期的阶段来完成任务。三套生命周期相互独立,但各个生命周期中的phase却是有顺序的,且后面的 phase 依赖于前面的 phase。执行某个phase时,其前面的phase会依顺序执行,但不会触发另外两套生命周期中的任何phase。
比如执行package,前面的test、comiple等会运行。
在这里插入图片描述

clean生命周期

  • pre-clean :执行清理前的工作;
  • clean :清理上一次构建生成的所有文件(target);
  • post-clean :执行清理后的工作

default生命周期

default生命周期是最核心的,它包含了构建项目时真正需要执行的所有步骤。

  • process-resources :复制和处理资源文件到target目录,准备打包;
  • compile :编译项目的源代码;
  • test-compile :编译测试源代码;
  • test :运行测试代码;
  • package :打包成jar或者war或者其他格式的分发包;
  • install :将打好的包安装到本地仓库,供其他项目使用;
  • deploy :将打好的包安装到远程仓库,供其他项目使用;

site生命周期

  • pre-site
  • site :生成项目的站点文档;
  • post-site
  • site-deploy :发布生成的站点文档

插件的目标

一个插件通常可以完成多个任务,每一个任务就叫做插件的一个目标。如执行mvn install命令时,调用的插件和执行的插件目标如下:

在这里插入图片描述

将插件绑定到生命周期

Maven的生命周期是抽象的,实际需要插件来完成任务,这一过程是通过将插件的目标(goal)绑定到生命周期的具体阶段(phase)来完成的。如:将maven-compiler-plugin插件的compile目标绑定到default生命周期的compile阶段,完成项目的源代码编译:

在这里插入图片描述

举个例子,使用源码生成插件,并绑定到 package 阶段

<plutins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-source-plugin</artifactId>
           <version>2.1.2</version>
           <executions>
               <execution>
                   <phase>package</phase>
                   <goals><goal>jar-no-fork</goal></goals>
               </execution>
           </executions>
    </plugin>
</plugins>

第四部分-maven 的聚合和继承

聚合是为了解决模块的依赖关系,并且方便统一打包和测试。

对于每一个模块来说,都来写一遍属性配置,依赖配置,插件配置,仓库配置未免太麻烦 ,而且不好管理;所以一般都会有一个父项目来配置好这么东西,子项目不需要关心jar 版本,插件配置等信息。

一般把聚合和继承这两个统一放到一个 pom 文件中,做为父项目存在,这两个需要的打包方式为 pom 。

<!--打包方式需要配置为 pom -->
<packaging>pom</packaging>

<!-- 聚合的模块列表,不需要关心顺序,maven 会自动根据依赖关系顺序-->
<modules>
    <module>modul1</module>
    <module>modul2</module>
</modules>

<!--配置子项目可能需要用到的 jar 包-->
<dependencyManagement>
    <dependencies>
    </dependencies>
</dependencyManagement>

<!--配置子项目可能需要用到的 插件-->
<pluginManagement>
     <plugins>
    </plugins>
</pluginManagement>

最后一部分-常用插件和项目中遇到的一些问题

第三方包的安装

mvn install:install-file -Dfile=<path-to-file> -DgroupId=<group-id> -DartifactId=<artifact-id> -Dversion=<version> -Dpackaging=<packaging>

jdk 版本的问题

因为 maven 用的 jdk 一般版本都比较老,所以造成老是提示 jdk 版本不对的问题,这样解决。

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.1</version>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
    </configuration>
</plugin>

打包时跳过测试

<plugin>
       <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.18.1</version>
    <configuration>
        <skipTests>true</skipTests>
    </configuration>
</plugin>

mybatis mapper 文件没有编译问题

把 mapper xml 文件放到同 mapper 同一级的时候 ,经常用找不到 xml 文件的问题,这样解决,放到 build 子节点下

<resources>
    <resource>
        <directory>src/main/java</directory>
        <includes>
            <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
    </resource>
    <resource>
        <directory>src/main/resources</directory>
    </resource>
</resources>

servlet3 不需要 web.xml 问题

<properties>
     <failOnMissingWebXml>false</failOnMissingWebXml>
</properties>

常用插件

  • 打包带上源码,这个其实还挺好用的
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-source-plugin</artifactId>
    <version>2.1.2</version>
    <executions>
       <execution>
            <phase>package</phase>
            <goals><goal>jar-no-fork</goal></goals>
        </execution>
    </executions>
</plugin>
  • 把java工程打包成为一个可执行的jar包
<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <version>3.0.0</version>
  <configuration>
    <archive>
      <manifest>
        <mainClass>com.learn.MyApp</mainClass>
      </manifest>
    </archive>
    <descriptorRefs>
      <descriptorRef>jar-with-dependencies</descriptorRef>
    </descriptorRefs>
  </configuration>
</plugin>
  • tomcat 插件
<plugin>
  <groupId>org.apache.tomcat.maven</groupId>
  <artifactId>tomcat7-maven-plugin</artifactId>
  <version>2.2</version>
  <configuration>
      <port>8080</port>
      <path>/</path>
  </configuration>
</plugin>
  • jetty 插件
<plugin>
      <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>9.2.11.v20150529</version>
    <configuration>
        <httpConnector>
            <port>8081</port>
        </httpConnector>
        <webAppSourceDirectory>src/main/webapp</webAppSourceDirectory>
        <scanIntervalSeconds>10</scanIntervalSeconds>
        <webApp>
            <contextPath>/sanritools</contextPath>
        </webApp>
    </configuration>
</plugin>

一点小推广

Excel 通用导入导出,支持 Excel 公式
https://blog.csdn.net/sanri1993/article/details/100601578

使用模板代码 ,从数据库生成代码 ,及一些项目中经常可以用到的小工具
https://blog.csdn.net/sanri1993/article/details/98664034


sanri1993
490 声望14 粉丝