笔记以学习许晓斌的《Maven实战》为主整理,非原创
什么是Maven
定义:Maven 是专门用于构建(清理、编译、单元测试、生成文档、打包、部署等一系列操作)和管理Java相关项目的工具。
Maven其他用途:
- 依赖管理工具:通过坐标系统准确定位每一个构件(artifact),即通过一组坐标能够找到任何一个Java类库(如jar文件)。提供中央仓库,自动下载构件。解决版本不一致、冲突、依赖臃肿等问题。
- 项目信息管理工具:管理分散在项目中各个角落的项目信息(项目描述、开发者列表、版本控制系统地址、许可证等)。结合插件还能轻松获得项目文档、测试报告、静态分析报告、源码版本、日志报告等项目信息。
- 约定优于配置:Maven对项目目录结构、测试用例命名方式等内容有既定规则,便于用户在项目间切换。
Maven目录分析(M2_HOME)
bin:包含mvn运行脚本,脚本用于配置Java命令。其中有m2.conf文件,是classworlds的配置文件
boot:仅包含类加载器,提供丰富语法以方便配置
conf:包含settings.xml,可在机器上全局定制Maven行为(放入~/.m2/中可以用户范围定制Maven行为)
lib:所有Maven运行时Java类库
设置HTTP代理
过程:1. 通过命令ping repo1.maven.org看是否能访问maven中央仓库;2. telnet检测代理服务器端口是否通畅;3. 编辑 ~/.m2/settings.xml 添加代理配置如下:
<settings>
...
<proxies>
<proxy> <!----可以配置多个proxy,默认第一个激活的proxy会生效----->
<id>myProxy</id>
<active>true</active>
<protocol>http</protocol>
<host>123.123.123.123</host>
<port>8080</port>
<username>*****</username> <!----需要认证的情况下才有----->
<password>*****</password>
<nonProxyHosts>*.XXX.com|XXX.org</nonProxyHosts> <!---不需要代理的地址--->
</proxy>
</proxies>
...
</settings>
TIPS:尽量不使用IDE自带的Maven(版本新不稳定,与命令行的版本一致避免构建不一致)
一个简单项目构建流程
POM编写:POM(Project Object Model)项目对象模型,定义了项目的基本信息,用于描述项目如何构建,声明项目依赖等。
内容在项目根目录pom.xml中。
<?xml version="1.0" encoding="UTF-8"?> <!---xml版本和编码--->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <!----根元素,声明了POM相关命名空间及xsd元素---->
<modelVersion>4.0.0</modelVersion> <!-----指定POM模型版本---->
<groupId>com.juvenxu.mvnbook</groupId> <!-----定义了项目的组,关联所在公司或组织,一般为:com + 公司名 + 项目名 ------>
<artifactId>hello-world</artifactId> <!-----当前Maven项目在组中唯一ID,可能会为不同子项目分配,如myapp-util, myapp-web等---->
<version>1.0-SNAPSHOT</version> <!-----项目当前版本号,SNAPSHOT为快照说明还在开发中----->
<name>Maven Hello World Project</name> <!-----更为友好的项目名,不是必须的--->
<dependencies>
<dependency>
<groupId>junit</groupId> <!-----可以在中央仓库junit/junit/4.7/找到junit-4.7.pom和junit-4.7.jar----->
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope> <!-----依赖范围,意味着只能在测试代码中import JUnit,如果主代码的话编译出错,默认compile对主测都都有效---->
</dependency>
</dependencies>
</project>
主代码:根据Maven的约定,主代码位于src/main/java目录中,因此在该目录下创建文件com/juvenxu/mvnbook/helloworld/HelloWorld.java(一般Java的类包应基于groupId和artifactId,更清晰符合逻辑)
- 执行编译:mvn clean compile 。首先执行了clean:clean删除target/目录(包含Maven构建的所有输出);接着resources:resources任务;最后compile:compile将主代码编译至target/classes目录。
测试代码:位于src/test/java,在该目录下创建com/juvenxu/mvnbook/helloworld/HelloWorldTest.java
- 执行测试:mvn clean test ,会先执行主代码的编译过程,然后resources:testResources和compiler:testCompile。编译结果输出到target/test-classes中,接着通过surefire插件运行测试。
打包:默认使用打包类型jar。
- 执行打包:mvn clean package 。执行编译、测试等操作后,jar:jar任务负责打包,结果在target/目录中,名字为hello-world-1.0-SNAPSHOT.jar(命名方式为artifactId-version.jar)。
导入本地仓库:项目导入本地仓库才能被其他项目所使用(类似前面测试用的JUnit)。
- 执行安装:mvn clean install ,打包后又执行了install:install任务,将该项目输出的jar安装到了本地仓库,打开相应文件夹可以看到项目的pom和jar。
生成可执行jar包:借助maven-shade-plugin,内容入下:
<project>
...
<build>
<plugins>
<plugin> <!----这个插件使complier插件支持Java6,而默认只支持1.3(JUnit4使用注解时会编译出错)---->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin> <!----这个插件用于生成可执行jar---->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>package</phase> <!-- 执行package的phase -->
<goals>
<goal>shade</goal> <!-- 为这个phase绑定goal -->
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.juvenxu.mvnbook.helloworld.HelloWorld</mainClass> <!-- 打成可执行的jar包 的主方法入口-->
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
</project>
- 执行安装:mvn clean install,会生成hello-world-1.0-SNAPSHOT.jar和original-hello-world-1.0-SNAPSHOT.jar在target/目录中,前者为带有Main-class信息(在jar中的META-INF/MANIFEST.MF)的可运行jar,后者是原始jar。
TIPS:Maven3执行:mvn archetype:generate 自动生成骨架(基本目录结构和pom.xml内容)
Maven坐标详解
每个构件必须明确定义自己的坐标,他们通过这些元素定义:groupId,artifactId,version,packaging,classifier。
groupId:(必须)
定义当前Maven项目隶属的实际项目。一般实际项目下有多个Maven项目(一个实际项目被划分成多个模块),如SpringFramework这一实际项目下有spring-core、spring-context等Maven项目。
表达方式一般与Java包名类似,通常与域名反向一一对应,如org.sonatype.nexus,org.sonatype表示Sonatype公司建立的一个非盈利组织,nexus表示Nexus这一实际项目。
artifactId:(必须)
定义实际项目中的一个Maven项目(模块)。表示方法一般以实际项目为前缀,比如:nexus-indexer。
version:(必须)
定义Maven项目所处的版本。
packaging:(可选)
定义Maven项目打包方式,默认是jar。打包方式影响构建的生命周期,比如jar和war的打包使用不同命令。
classifier:(不能直接定义)
用于定义构建输出的一些附属构建。例如主构件是nexus-indexer-2.0.0.jar,该项目可能还会通过使用一些插件生成如nexus-indexer-2.0.0-javadoc.jar、nexus-indexer-2.0.0-sources.jar等一些附属构件,其中包含Java文档和源代码。这时javadoc和sources就是这两个附属构件的classifier。不能直接定义,它由附件插件帮助生成。
依赖的配置
一个依赖声明可以包含以下一些元素: