Maven实战笔记

一个parent-pom例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mj.maven</groupId>
<artifactId>parentpom-war</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>parentpom-war</name>
<url>http://wiki.inzwc.com/tech/wiki/index.php/Maven</url>
<properties>
<slf4j.version>1.7.9</slf4j.version>
<logback.version>1.1.3</logback.version>
<spring.version>4.2.2.RELEASE</spring.version>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.10</version>
<configuration>
<downloadSources>true</downloadSources>
<downloadJavadocs>false</downloadJavadocs>
<additionalConfig>
<file>
<name>.settings/org.eclipse.core.resources.prefs</name>
<content>
<![CDATA[
eclipse.preferences.version=1
encoding//<project>=UTF-8
]]>
</content>
</file>
</additionalConfig>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<classifier>${project.classifier}</classifier>
<packagingExcludes>
WEB-INF/lib/commons-logging-*.jar,
%regex[WEB-INF/lib/log4j-(?!over-slf4j).*.jar,
WEB-INF/lib/spring-asm-*.jar]
</packagingExcludes>
</configuration>
</plugin>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.2.9.v20150224</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.aicaipiao</groupId>
<artifactId>hessian-aicaipiao</artifactId>
<version>3.2.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
</dependencies>
</project>

maven中央仓库地址:http://mvnrepository.com/
maven是一个项目构建工具,依赖管理工具,项目信息管理工具.大大简化了我们的开发工作.
最佳实践是,将M2_HOME下面conf下面的settings.xml复制到~/.m2/下面,并且修改相应的配置信息.

###maven安装与基本配置
有时候你的公司基于安全考虑,要求你使用安全代理访问互联网,这时候,需要为MAVEN配置HTTP代理,才能让他访问外部仓库,以下载所需要的资源.

1
2
3
4
5
6
7
8
9
10
<proxy>
<id>myproxy</id>
<active>true</active>
<protocol>http</protocol>
<host>nexus.tech.2ceeo.com/</host>
<port>8022</port>
<!--<username>liaoyuding</username>
<password>123456</password> <nonProxyHosts>nexus.tech.2caipiao.com</nonProxyHosts>
-->
</proxy>

proxies下可以有多个proxy元素,但是默认第一个被激活的proxy会生效,可以用|来分割多个主机.nonProxyHosts用来指定哪些主机名不需要代理.
安装m2eclipse
http://download.eclipse.org/technology/m2e/releases/
MAVEN安装最佳实践

  1. 设置MAVEN_OPTS环境变量
    通常设置为-Xms128m -Xms512m,因为java默认的最大可用内存往往不能够满足Maven运行的需要.
  2. 配置用户范围的settings.xml
    M2_HOME/conf/settings.xml是全局范围的,~/.m2/settings.xml是用户范围的.在用户目录下.
  3. 不要使用IDE内嵌的maven

maven使用入门

编写POM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mj</groupId>
<artifactId>springAction</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>springAction</name>
<url>http://maven.apache.org</url>
<properties>
<!-- 打包名称定义. -->
<project.classifier></project.classifier>
<!-- Plugin的属性定义 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compile.encoding>UTF-8</maven.compile.encoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!-- 版本定义 -->
<spring.version>3.2.9.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

编写测试代码

因为maven的核心插件之一-compile默认只支持java1.3.所以配置插件使其支持java1.5.

1
2
3
4
5
6
7
8
9
10
11
12
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>

test命令:mvn clean test

####打包和运行
编译:mvn clean compile
打包:mvn clean package
如果需要别的项目可以引用该项目则需要一个安装的步骤:mvn clean install

main方法的项目打包生成的默认jar包是不能直接运行的,因为带有main方法的类信息不会添加到manifest中(打开jar文件中的META-INF/MANIFEST.MF文件,将无法看到Main-Class一行).为了生成可执行的jar文件,需要借助maven-shade-plugin,配置该插件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>hello.HelloWorld</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>

现在在target目录下有2个jar.一个是原始的,一个是可以直接运行的.
到项目目录下执行:java -jar target\hello-world-1.0-SNAPSHOT.jar
会执行main方法,看到结果.

####使用Archetype生成项目骨架
mvn archetype:generate

依赖范围

依赖范围就是用来控制依赖与这三种classpath(编译classpath,测试calsspath,运行classpath)的关系,maven有以下几种依赖范围:

  1. compile:编译依赖范围,默认情况下是这个,此种范围,对编译,测试,运行都有效.如spring-core.
  2. test:测试依赖范围,只用于测试classpath.在编译和运行时无法使用此依赖.典型的例子是Junit.
  3. provided:已提供依赖范围.这种只对编译和测试有效,运行时无效.典型的例子是servlet-api,编译和测试项目的时候需要该依赖,但是运行时由于容器已经提供,就不需要maven重复的引入一遍.
  4. runtime:运行时依赖范围.此种只对测试和运行时有效.但在编译主代码时无效,典型的例子是jdbc驱动实现,项目主代码的编译只需要jdk提供的jdbc接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体jdbc驱动.
  5. system:系统依赖范围.该依赖与三种classpath的关系和provided依赖范围完全一致.但是需要使用systemPath显式指定依赖位置,造成构建的不可移植性,因此谨慎使用.
  6. import(maven2.0.9及以上):导入依赖范围.该依赖范围不会对3种classpath产生实际的影响.

优化依赖

查看所有依赖:mvn dependency:list
查看依赖树:mvn dependency:tree
分析依赖查找潜在风险:mvn dependency:analyze

maven仓库

中央仓库

maven安装时自带了中央仓库的默认配置,通过解压$M2_HOME/lib/maven-model-builder-3.3.3.jar,然后访问org\apache\maven\model\pom-4.0.0.xml,可以看到下面的配置:

1
2
3
4
5
6
7
8
9
10
11
<repositories>
<repository>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>

这是所有maven项目都会继承的超级POM,false表示不从该仓库下载快照版本的构件.

私服

私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,私服代理广域网上的远程仓库,供局域网内的Maven用户使用.当maven需要下载构件的时候,它从私服请求,如果私服上不存在该构件,则从外部的远程仓库下载,缓存在私服上之后,再供请求使用.另外,一些无法从外部仓库下载的构件也能从本地上传到私服上供大家使用.

私服可以帮你:

  1. 节省自己的外网带宽.
  2. 加速maven构建.
  3. 部署第三方构件.
  4. 提高稳定性,增强控制.
  5. 降低中央仓库的负荷.

远程仓库的配置

1
2
3
4
5
6
7
8
9
10
11
12
<repository>
<id>jboss</id>
<name>JBoss Repository</name>
<url>https://repository.jboss.com/maven2</url>
<releases>
<enable>true</enable>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<layout>default</layout>
</repository>

repositories下面,可以使用repository声明一个或多个远程仓库,id都是唯一的,Maven自带的中央仓库的id为central ,所以自己配置的不能和central同名,否则会覆盖中央仓库的配置.
该配置例子中的,releasessnapshots元素比较重要,它们用来控制maven对发布版构件和快照版构件的下载.
例子中maven只会从jboss下载发布版的构件,而不会下载快照版的.

####远程仓库的认证
大部分远程仓库无需认证就可以访问,但是一般组织内部的maven服务器因为安全考虑会为用户配置一组用户名和密码.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<localRepository>D:/Program Files/repo-jing.ming/.m2/repository</localRepository>
<servers>
<server>
<id>aicai-release</id>
<username>liaoyuding</username>
<password>123456</password>
</server>
<server>
<id>aicai-snapshot</id>
<username>liaoyuding</username>
<password>123456</password>
</server>
<server>
<id>thirdparty</id>
<username>liaoyuding</username>
<password>123456</password>
</server>
</servers>

部署至远程仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
<!--部署至远程仓库 -->
<distributionManagement>
<repository>
<id>proj-releases</id>
<name>Proj Release Repository</name>
<url>http://192.168.1.100/content/repositories/proj-releases</url>
</repository>
<snapshotRepository>
<id>proj-snapshots</id>
<name>Proj Snapshot Repository</name>
<url>http://192.168.1.100/content/repositories/proj-snapshots</url>
</snapshotRepository>
</distributionManagement>

往远程仓库部署构件的时候.需要认证.认证的方式是在settings.xml中创建一个server元素,其id与仓库的id匹配,并配置正确的认证信息.从远程下载个部署,认证配置的方式是一样的.
配置正确后,执行mvn clean deploy,maven就会将项目构建输出的构件部署到对应的远程仓库.

####镜像
如果仓库x可以提供仓库y存储的所有内容,那么就可以认为x是y的一个镜像.

1
2
3
4
5
<mirror>
<id>maven.net.cn</id>
<mirrorOf>central</mirrorOf>
<url>http://maven.net.cn/content/groups/public/</url>
</mirror>

mirrorOf为’central’,表示对于中央仓库central的请求都会转至该镜像.

但是更常见的镜像配置是结合私服:

1
2
3
4
5
<mirror>
<id>nexus</id>
<mirrorOf>*</mirrorOf>
<url>http://nexus.tech.sss.com/content/groups/public</url>
</mirror>

生命周期和插件

生命周期

maven生命周期介绍:http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html

maven拥有三套相互独立的生命周期,它们分别为clean,default,site.clean生命周期的目的是清理项目,default生命周期的目的是构建项目,site生命周期的目的是建立项目站点.每个生命周期包含一些阶段,这些阶段是有顺序的,并且后面的阶段依赖前面的阶段,用户和maven最直接的交互方式是调用这些生命周期的阶段.
这三个阶段是相互独立的,例如,当用户调用clean生命周期的clean阶段时,不会触发default生命周期的任何阶段.

#####clean生命周期
这个阶段主要工作是清理项目,它包含三个阶段:

  1. pre-clean执行一些清理前需要完成的工作.
  2. clean清理上一次构建生成的文件.
  3. post-clean执行一些清理后需要完成的工作.
    #####default生命周期
    site生命周期
    ####插件
    #####命令行插件配置:
    很多插件的目标参数都支持从命令行配置,用户可以在maven命令中使用-D参数,并伴随一个参数键=参数值的形式,来配置插件目标的参数.
    例如,maven-surefire-plugin提供了一个maven.test.skip参数,当其值为true的时候,就会跳过执行测试.
    $ mvn install -Dmaven.test.skip=true
    参数D是java自带的,其功能是通过命令行设置一个java系统属性,maven简单的重用了该参数,在准备插件的时候检查系统属性,便实现了插件参数的配置.

插件自定义绑定到pom.xml示例:(自定义将某个插件目标绑定到生命周期的某个阶段上)
http://maven.apache.org/components/plugins/maven-source-plugin/usage.html
tips:

  1. 插件列表:http://maven.apache.org/components/plugins/
  2. 可以使用maven-help-plugin查看插件详细信息,了解插件目标的默认绑定阶段.
    $ mvn help:describe-Dplugin=org.apache.maven.plugins:maven-source-plugin:2.1.1-Ddetail
  3. maven生命周期介绍:http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
    #####pom中插件全局配置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <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>

mvn -h显示命令行帮助:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
C:\Users\mingjing>mvn -h
usage: mvn [options] [<goal(s)>] [<phase(s)>]
Options:
-am,--also-make If project list is specified, also
build projects required by the
list
-amd,--also-make-dependents If project list is specified, also
build projects that depend on
projects on the list
-B,--batch-mode Run in non-interactive (batch)
mode
-b,--builder <arg> The id of the build strategy to
use.
-C,--strict-checksums Fail the build if checksums don't
match
-c,--lax-checksums Warn if checksums don't match
-cpu,--check-plugin-updates Ineffective, only kept for
backward compatibility
-D,--define <arg> Define a system property
-e,--errors Produce execution error messages

1
2
3
4
5
6
##### 插件解析机制
插件和依赖都基于坐标存储在Maven仓库中,在需要的时候,maven会从本地仓库寻找插件,如果不存在则从远程仓库查找,找到插件之后再下载到本地仓库使用.
但是maven会区别对待依赖的远程仓库和插件的远程仓库,通过settings.xml配置的远程仓库只对一般的依赖有效.
即maven需要的插件在本地仓库不存在时.不会去配置的远程仓库查找.
插件的远程仓库使用`pluginRepositories`和`pluginRepository`配置,例如,maven内置了如下的插件远程仓库配置:


central
maven plugin Repository
http://repo1.maven.org/maven2
default

false


never



```

热评文章