预期读者
对 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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。