前言:背景介绍
-
Maven是什么?
如果没有Maven,你可能不得不经历下面的过程:
-
如果使用了spring,去spring的官网下载jar包;如果使用hibernate,去hibernate的官网下载Jar包;如果使用Log4j,去log4j的官网下载jar包.....
-
当某些jar包有依赖的时候,还要去下载对应的依赖jar包
-
当jar包依赖有冲突时,不得不一个一个的排查
-
执行构建时,需要使用ant写出很多重复的任务代码
-
当新人加入开发时,需要拷贝大量的jar包,然后重复进行构建
-
当进行测试时,需要一个一个的运行....检查
有了Maven,它提供了三种功能:
-
依赖的管理:仅仅通过jar包的几个属性,就能确定唯一的jar包,在指定的文件pom.xml中,只要写入这些依赖属性,就会自动下载并管理jar包。
-
项目的构建:内置很多的插件与生命周期,支持多种任务,比如校验、编译、测试、打包、部署、发布...
-
项目的知识管理:管理项目相关的其他内容,比如开发者信息,版本等等
Maven项目的结构和内容在一个XML文件中声明,pom.xml 项目对象模型(POM,Project-Object-Model),这是整个Maven系统的基本单元。
2、Maven如何管理jar包
关于jar包的坐标, maven是通过groupId,artifactId,以及version确定一个唯一的jar包。
例如,最常使用的Junit的声明就是如下:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
首先先来说说Maven下载jar包的过程:
在Maven中会涉及到几种仓库:
-
工作空间,即我们的项目工程,这里面可能会放着pom.xml文件,这个pom.xml就是maven的配置文件
-
本地仓库,本地仓库用于存放jar包,其实Jar包并不是直接放入工作空间的,它是存放在本地仓库。默认的文件夹是 ".m2" 目录。,然后在执行发布打包的时候,添加依赖路径
-
私库:私库是使用者自己搭建的maven仓库,用于缓解频繁从外网下载jar包资源的压力。而且使用私库作为缓存层,也相对安全一些。(一般公司都会有自己的Maven私服(采用Nexus搭建),它会与中央仓库进行index同步)
-
共享仓库:Maven中央仓库或者一些常用的镜像网站都属于这。Maven中央存储库 https://repo1.maven.org/maven2/ (查询三方组件时可用https://search.maven.org)
3、Apache Maven 是做什么用的?
Maven 是一个项目管理和构建自动化工具。但是对于我们
程序员来说,我们最关心的是它的项目构建功能。Maven 使用约定优于配置的原则 。它要求在没有定制之前,所有的项目都有如下的结构:
${basedir}
存放 pom.xml和所有的子目录
${basedir}/src/main/java
项目的 java源代码
${basedir}/src/main/resources
项目的资源配置,比如说 property文件
${basedir}/src/test/java
项目的测试类,比如说 JUnit代码
${basedir}/src/test/resources
测试使用的资源
一个 maven 项目在默认情况下会产生 JAR 文件(也可配置生成war等),另外 ,编译后 的 classes 会放在 ${basedir}/target/classes 下面, JAR 文件会放在 ${basedir}/target 下面。
-
Maven基本操作
一些基本的操作,编译,构建,单元测试,安装,网站生成和基于Maven部署项目。
使用Maven构建项目
"mvn clean package" 来构建项目
使用Maven清理项目
"mvn clean" 来清理项目
使用Maven运行单元测试
"mvn clean test" 来执行单元测试
将项目安装到Maven本地资源库
"mvn install" 打包和部署项目到本地资源库
生成基于Maven的项目文档站点
"mvn site" 来为您的项目生成信息文档站点
使用"mvn site-deploy"部署站点(WebDAV例子)
"mvn site-deploy" 通过WebDAV部署自动生成的文档站点到服务器
部署基于Maven的war文件到Tomcat (一般结合jenkins使用)
"mvn tomcat:deploy" 以 WAR 文件部署到 Tomcat
参考学习网站推荐:
http://www.oracle.com/technetwork/cn/community/java/apache-maven-getting-started-1-406235-zhs.html
http://www.cnblogs.com/xing901022/p/5024357.html
学习书籍PDF推荐:https://pan.baidu.com/s/1gdu1rDD
一、环境准备:Maven,Eclipse-Maven-Plugin
-
Maven下载: http://maven.apache.org/download.cgi ,解压即可。然后配置M2_HOME以及Path环境变量。Maven默认下载的jar包放在用户目录下的 .m2目录(注意windows默认当成隐藏目录). 测试:打开cmd输入mvn –v看是否安装成功
%M2_HOME%\bin
-
Eclipse-Maven-Plugin:在高版本Eclipse中其实内置了Maven插件
(此处低版本maven可选)然后在Window->Preference->Java->Installed JREs->Edit
在Default VM arguments中设置
-Dmaven.multiModuleProjectDirectory=$M2_HOME
然后配置maven取消勾选下载远程索引
二、Maven的生命周期与阶段
理解Maven核心概念博客:
http://www.cnblogs.com/holbrook/archive/2012/12/24/2830519.html
官方文档部分: http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
https://maven.apache.org/ref/3.3.9/maven-core/lifecycles.html
Maven中有三大生命周期,他们相互独立,分别是:
1 clean 清理
2 default 构建
3 site 建站
一般来说,clean和default比较常用。
每个生命周期又有不同的阶段,阶段按顺序执行,并且可以指定执行结束的阶段。构建的时候,会依次从最上面的阶段执行到指定的那个阶段。
比如,clean有3个阶段:
1 pre-clean 执行清理前要完成的工作
2 clean 清理上一次构建生成的文件
3 post-clean 执行清理后需要完成的工作
当我们输入mvn clean的时候,执行的是pre-clean和clean两个阶段。
default的阶段比较多:
1 validate
2 initialize
3 generate-sources
4 process-sources
5 generate-resources
6 process-resources
7 compile
8 process-classes
9 generate-test-sources
10 process-test-sources
11 generate-test-resources
12 process-test-resources
13 test-compile
14 process-test-classes
15 test
16 prepare-package
17 package
18 pre-integration-test
19 integration-test
20 post-integration-test
21 verify
22 install
23 deploy
看名字大概就能理解,当执行mvn install的时候,实际会执行validate-->initialize-->...-->verify-->install等二十几个阶段。
为了操作方便,不同的声明周期可以在一起执行,比如mvn clean install,会先执行clean的阶段,在执行install的阶段。
三、ProjectObjectModel文件介绍
如果使用过Ant都知道Ant是通过build.xml执行构建任务的,Maven中是通过pom.xml来执行任务。
POM,project object model,即项目对象模型,它通过这个pom.xml描述一个项目的构建以及信息。
<?<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xinoo.test</groupId>
<artifactId>first-maven</artifactId>
<version>1.0-SNAPSHOT</version>
<name>First Maven Project</name>
</project>
第一行指定了文档的XML版本和编码
第二行即每个pom.xml的核心元素——project
project下面有几个子元素,这几个子元素一般是每个项目都会使用到的:
1 modelVersion这个元素指定了POM的版本,Maven2或者Maven3 都只能是4.0.0
2 groupId 是项目组的ID,一般是com.公司组织名.项目名
3 artifactId 是该项目在项目组中的ID,比如当前的项目是项目组的一个代理项目,就可以叫做myproxy
4 version 是项目的版本号,用于维护项目的升级和发布
5 name 一般没有实际的用处,只是用于标识该项目
比较重要的参数是 groupId、artifactId、version,这三个属性确定唯一的一个项目。
1、pom文件的变量:
pom.xml隐式变量
env
env 变量暴露了你操作系统或者shell 的环境变量。例如,在Maven POM 中一个对${env.PATH}的引用将会被${PATH}环境变量替换(或者Windows 中的%PATH%)。
project
project 变量暴露了POM。你可以使用点标记(.)的路径来引用POM 元素的值。例如,在本节中我们使用过groupId 和artifactId 来设置构建配置中的finalName 元素。这个属性引用的语法是:
${project.groupId}-${project.artifactId}。
settings
settings 变量暴露了Maven settings 信息。可以使用点标记(.)的路径来引用settings.xml 文件中元素的值。例如,${settings.offline}会引用~/.m2/settings.xml 文件中offline 元素的值。
Java 系统属性
所有可以通过java.lang.System 中getProperties()方法访问的属性都被暴露成POM 属性。一些系统属性的例子是:${user.name},${user.home},${java.home},和${os.name}。一个完整的系统属性列表可以在java.lang.System 类的Javadoc 中找到。
自定义属性:
<properties>
<foo>bar</foo>
</properties>
2、依赖
会包含基本的groupId, artifactId,version等元素,根元素project下的dependencies可以包含一个或者多个dependency元素,以声明一个或者多个依赖。
下面详细讲解每个依赖可以包含的元素:
groupId,artifactId和version:依赖的基本坐标,对于任何一个依赖来说,基本坐标是最重要的,Maven根据坐标才能找到需要的依赖
type: 依赖的类型,对应于项目坐标定义的packaging。大部分情况下,该元素不必声明,其默认值是jar,war
scope: 依赖的范围,
-
compile 编译,测试,运行都有效。默认的依赖范围。
-
test 测试,对于编译测试有效,对于运行无效。如:servlet-api,junit
-
runtime 运行,对于测试和运行均有效。但在编译时无效。如 JDBC。
-
provided 编译,测试,如 ServletAPI。
-
system 编译,测试,依赖于系统变量。
optional: 标记传递依赖是否可选
exclusions: 用来排除传递性依赖
classifier代表附属构建如javadoc,source等
大部分依赖声明只包含基本坐标。
依赖的传递性:
依赖是具有传递性的,例如 Project A 依赖于 Project B,B 依赖于 C,那么 B 对 C 的依赖关系也会传递给 A,如果我们不需要这种传递性依赖,也可以用 <optional> 去除这种依赖的传递,如清单 5。
清单 5. 选择性依赖
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
<optional>true<optional>
</dependency>
假设第三方的 jar 包中没有使用 <optional> 来去除某些依赖的传递性,那么可以在当前的 POM 文件中使用 <exclusions> 元素声明排除依赖,exclusions 可以包含一个或者多个 exclusion 子元素,因此可以排除一个或者多个传递性依赖。如清单 6。
清单 6. 排除依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
-
Maven 插件
插件列表:http://maven.apache.org/plugins/index.html
Maven 本质上是一个插件框架,它的核心并不执行任何具体的构建任务,仅仅定义了抽象的生命周期,所有这些任务都交给插件来完成的。每个插件都能完成至少一个任务,每个任务即是一个功能,将这些功能应用在构建过程的不同生命周期中。
常用插件:
-
java编译插件:
<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>${project-encoding}</encoding>
</configuration>
</plugin>
</plugins>
以上的这个就是java编译插件。
-
war包打包插件:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
</plugin>
<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>${project-encoding}</encoding>
<compilerArguments>
<extdirs>${project.basedir}/src/main/webapp/WEB-INF/lib</extdirs>
</compilerArguments>
</configuration>
</plugin>
-
Jar包打包插件:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.css.sword.sitesync.App</mainClass>
</transformer>
<!-- <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>applicationContext.xml</resource> </transformer> -->
</transformers>
</configuration>
</execution>
</executions>
</plugin>
-
模块聚合与继承
现实中一个项目往往是由多个 project 构成的,在进行构建时,我们当然不想针对多个 project 分别执行多次构建命令,这样极容易产生遗漏也会大大降低效率。Maven 的聚合功能可以通过一个父模块将所有的要构建模块整合起来,将父模块的打包类型声明为 POM,通过 <modules> 将各模块集中到父 POM 中。如清单 7,其中 <module></module> 中间的内容为子模块工程名的相对路径。
清单 7. 聚合
<modules>
<module>../com.dugeng.project1</module>
<module>../com.dugeng.project2</module>
</modules>
在面向对象的编程中我们学会了继承的概念,继承是可重用行即消除重复编码的行为。Maven 中继承的用意和面向对象编程中是一致的。与聚合的实现类似,我们通过构建父模块将子模块共用的依赖,插件等进行统一声明,在聚合和继承同时使用时,我们可以用同一个父模块来完成这两个功能。
例如将 com.dugeng.parent 这个模块声明为 project1 和 project2 的父模块,那么我们在 project1 和 2 中用如下代码声明父子关系,如清单 8:
清单 8. 继承
<parent>
<groupId>com.dugeng.mavenproject</groupId>
<artifactId>com.dugeng.parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../com.dugeng.parent/pom.xml</relativePath>
</parent>
由于父模块只是用来声明一些可共用的配置和插件信息,所以它也像聚合模块一样只需要包括一个 POM 文件,其它的项目文件如 src/main/java 是不需要的。
聚合和继承存在一些共性和潜在的联系,在实际的应用中,经常将聚合模块的父模块和继承的父模块定义为同一个。
-
分环境配置打包:
当我们存在多个环境需要部署时,我们不需要每次部署时都去改变配置,只需要配置一次即可。
<profiles>
<profile>
<!-- 本地开发环境 -->
<id>development</id>
<properties>
<profile.env>development</profile.env>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<!-- 测试环境 -->
<id>test</id>
<properties>
<profile.env>test</profile.env>
</properties>
</profile>
<profile>
<!-- 生产环境 -->
<id>production</id>
<properties>
<profile.env>production</profile.env>
</properties>
</profile>
</profiles>
<build>
<finalName>${base-name}</finalName>
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
<!-- 资源根目录排除各环境的配置,使用单独的资源目录来指定 -->
<excludes>
<exclude>test/*</exclude>
<exclude>production/*</exclude>
<exclude>development/*</exclude>
</excludes>
</resource>
<resource>
<directory>${project.basedir}/src/main/resources/${profile.env}</directory>
</resource>
</resources>
<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>${project-encoding}</encoding>
</configuration>
</plugin>
</plugins>
比如我想根据测试环境打包,执行 mvn –Ptest clean package即可
四、Nexus仓库搭建:(开发人员不需要搭建)
参考:http://www.cnblogs.com/luotaoyeah/p/3791966.html
http://blog.youkuaiyun.com/shenshen123jun/article/details/9084293
http://blog.youkuaiyun.com/liujiahan629629/article/details/39272321
注意:nexus无法更新索引问题解决:(https://issues.sonatype.org/browse/NEXUS-10233)
修改conf/nexus.properties文件,添加:
org.sonatype.nexus.proxy.maven.routing.Config.prefixFileMaxSize=500000
如出现刷新索引时出现
There was an error communicating with the server: request timed out.
解决(https://issues.sonatype.org/browse/NEXUS-5823):
修改administration/server 的UI time 默认为60s
五、向Nexus私服发布
发布命令mvn clean deploy
条件:默认发布用户名和密码: deployment deployment123
配置maven的setting.xml配置:
<servers>
<server>
<id>releases</id>
<username>deployment</username>
<password>admin123</password>
</server>
<server>
<id>snapshots</id>
<username>deployment</username>
<password>admin123</password>
</server>
</servers>
在pom.xml配置:
<distributionManagement>
<repository>
<id>releases</id>
<name>deployment</name>
<url>http://localhost:8081/nexus/content/repositories/releases</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<name>deployment</name>
<url>http://localhost:8081/nexus/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>然后运行发布
mvn clean deploy
在控制台发布成功
然后进入到私服上的仓库中,看一下是否存在刚刚发布的项目
五、新建Maven项目
常用的有两种,一种是jar包形式的为maven-archetype-quickstart,一种是war形式的为maven-archetype-webapp
(如果是依赖于war包的情形(其它情形不必理会):新建运行项目的时候需要运clean package,然后它会自动在target下生成解压的war与当前项目代码合并的项目。
添加至eclipse servers需要配置的deployment assembly如下:
)
各种配置见pom示例文件夹
附录:pom.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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<! – The Basics – >
<groupId> … </groupId>
<artifactId> … </artifactId>
<version> … </version>
<packaging> … </packaging>
<dependencies> … </dependencies>
<parent> … </parent>
<dependencyManagement> … </dependencyManagement>
<modules> … </modules>
<properties> … </properties>
<! – Build Settings – >
<build> … </build>
<reporting> … </reporting>
<! – More Project Information – >
<name> … </name>
<description> … </description>
<url> … </url>
<inceptionYear> … </inceptionYear>
<licenses> … </licenses>
<organization> … </organization>
<developers> … </developers>
<contributors> … </contributors>
<! – Environment Settings – >
<issueManagement> … </issueManagement>
<ciManagement> … </ciManagement>
<mailingLists> … </mailingLists>
<scm> … </scm>
<prerequisites> … </prerequisites>
<repositories> … </repositories>
<pluginRepositories> … </pluginRepositories>
<distributionManagement> … </distributionManagement>
<profiles> … </profiles>
</project>