Maven
目前项目状况
①添加第三方 jar 包
使用这些 jar 包最简单的方法就是复制粘贴到 WEB-INF/lib 目录下。但是这会导致每次创建一个新的工程就需要将 jar
包重复复制到 lib 目录下,从而造成工作区中存在大量重复的文件,让我们的工程显得很臃肿。 而使用 Maven 后每个 jar
包本身只在本地仓库中保存一份,需要 jar
包的工程只需要以坐标的方式简单的引用一下就可以了。不仅极大的节约了存储空间,让项目更轻巧,更避免了重复文件太多而造成的混乱。
②jar 包之间的依赖关系
最典型的例子是:commons-fileupload-1.3.jar 依赖于 commons-io-2.0.1.jar,如果 没有 IO
包,FileUpload 包就不能正常工作。 那么问题来了,你知道你所使用的所有 jar 包的依赖关系吗?当你拿到一个新的从未使用过的
jar 包,你如何得知他需要哪些 jar 包的支持呢?如果不了解这个情况,导入的 jar
包不够,那么现有的程序将不能正常工作。再进一步,当你的项目中需要用到上百个 jar 包时,你还会人为的,手工的逐一确认它们依赖的其他 jar
包吗?这简直是不可想象的。 而引入 Maven 后,Maven 就可以替我们自动的将当前 jar 包所依赖的其他所有 jar
包全部导入进来,无需人工参与,节约了我们大量的时间和精力。用实际例子来说明就是:通过 Maven 导入
commons-fileupload-1.3.jar 后,commons-io-2.0.1.jar
会被自动导入,程序员不必了解这个依赖关系。
③获取第三方 jar 包
jar 包种类繁多,几乎每个 jar 包在其本身的官网上的获取方式都不尽相同。使用 Maven 我们可以享受到一个完全统一规范的 jar
包管理体系。你只需要在你的项目中以坐标的方式依赖一个 jar 包,Maven 就会自动从中央仓库进行下载,并同时下载这个 jar
包所依赖的其他 jar 包
④将项目拆分成多个工程模块
随着 JavaEE 项目的规模越来越庞大,开发团队的规模也与日俱增。一个项目上千人的团队持续开发很多年对于 JavaEE
项目来说再正常不过。那么我们想象一下:几百上千的人开发的项目是同一个 Web
工程。那么架构师、项目经理该如何划分项目的模块、如何分工呢?这么大的项目已经不可能通过 package
结构来划分模块,必须将项目拆分成多个工程协同开发。多个模块工程中有的是 Java 工程,有的是 Web 工程。
那么工程拆分后又如何进行互相调用和访问呢?这就需要用到 Maven 的依赖管理机制。
Maven简介
Maven 是 Apache 软件基金会组织维护的一款自动化构建工具,专注服务于 Java 平台的项目构建和依赖管理。Maven 这个单词的本意是:专家,内行。读音是['meɪv(ə)n]或['mevn]。
Make->ant->Maven->Gradle
构建并不是创建,创建一个工程并不等于构建一个项目。要了解构建的含义我们应该由浅入深的从以下三个层面来看:
①纯 Java 代码 大家都知道,我们 Java 是一门编译型语言,.java 扩展名的源文件需要编译成.class
扩展名的字节码文件才能够执行。 ②Web 工程 当我们需要通过浏览器访问 Java 程序时就必须将包含 Java 程序的 Web
工程编译的结果“拿”到服务器上的指定目录下,并启动服务器才行。这个过程我们叫部署。 ③实际项目 在实际项目中整合第三方框架,Web
工程中除了 Java 程序和 JSP 页面、图片等静态资源之外,还包括第三方框架的 jar
包以及各种各样的配置文件。所有这些资源都必须按照正确的目录结构部署到服务器上,项目才可以运行。
所以综上所述:构建就是以我们编写的 Java 代码、框架配置文件、国际化等其他资源文件、JSP 页面和图片等静态资源作为“原材料”,去“生产”出一个可以运行的项目的过程。
那么项目构建的全过程中都包含哪些环节呢?
构建过程的几个主要环节
①清理:删除以前的编译结果(class文件),为重新编译做好准备。
②编译:将 Java 源程序编译为字节码文件。
③测试:(自动测试)针对项目中的关键点进行测试,确保项目在迭代开发过程中关键点的正确性。
④报告:在每一次测试后以标准的格式记录和展示测试结果。
⑤打包:将一个包含诸多文件的工程封装为一个压缩文件用于安装或部署。Java 工程对应 jar 包,Web工程对应 war 包。
⑥安装:在 Maven 环境下特指将打包的结果——jar 包或 war 包安装到本地仓库中。
⑦部署:将打包的结果部署到远程仓库或将 war 包部署到服务器上运行。
运行时环境:(查看build->)
安装Maven
1.解压部署Maven核心程序
①检查JAVA_HOME环境变量
C:\Windows\System32>echo %JAVA_HOME%
d:\software\jdk1.7.0_07
②解压Maven的核心程序
将apache-maven-3.2.2-bin.zip解压到一个非中文无空格的目录下。例如:d:\software\apache-maven-3.2.2
③配置环境变量
path d:\software\apache-maven-3.2.2\bin
④查看Maven版本信息验证安装是否正确
C:\Windows\System32>mvn -v
Apache Maven 3.2.2 (45f7c06d68e745d05611f7fd14efb6594181933e; 2014-06-17T21:51:42+08:00)
Maven home: d:\software\apache-maven-3.2.2\bin\..
Java version: 1.7.0_07, vendor: Oracle Corporation
Java home: d:\software\jdk1.7.0_07\jre
Default locale: zh_CN, platform encoding: GBK
OS name: "windows 7", version: "6.1", arch: "amd64", family: "windows"
Maven核心概念
Maven 能够实现自动化构建是和它的内部原理分不开的,这里我们从 Maven 的九个核心概念入手,
①POM
②约定的目录结构
③坐标
④依赖管理
⑤仓库管理
⑥生命周期
⑦插件和目标
⑧继承
⑨聚合
Maven安装目录及配置文件
1、修改本地仓库
①默认本地仓库位置:~\.m2\repository
~表示当前用户的家目录,
例如:C:\Users\[你当前登录系统的用户名]
②指定本地仓库位置的配置信息文件:
apache-maven-3.2.2\conf\settings.xml
③在根标签settings下添加如下内容:
<localRepository>[本地仓库路径,也就是RepMaven.zip的
解压目录]</localRepository>
※注意:运行Maven命令时一定要进入pom.xml文件所在的目录!
几个基本的Maven命令
mvn compile 编译主程序
mvn test-compile 编译测试程序
mvn clean 清理
mvn test 测试
mvn package 打包
①清理:删除以前的编译结果,为重新编译做好准备。
②编译:将 Java 源程序编译为字节码文件。
③测试:针对项目中的关键点进行测试,确保项目在迭代开发过程
中关键点的正确性。
④报告:在每一次测试后以标准的格式记录和展示测试结果。
⑤打包:将一个包含诸多文件的工程封装为一个压缩文件用于安装或部署。
Java 工程对应 jar 包,Web工程对应 war 包。
⑥安装:在 Maven 环境下特指将打包的结果——jar 包或 war 包
安装到本地仓库中。
⑦部署:将打包的结果部署到远程仓库或将 war 包部署到服务器上运行。
第一个Maven程序
POM
Project Object Model:项目对象模型。将 Java 工程的相关信息封装为对象作为便于操作和管理的模型。 pom.xml 是Maven 工程的核心配置
坐标
1、几何中的坐标
[1]在一个平面中使用 x、y 两个向量可以唯一的确定平面中的一个点。
[2]在空间中使用 x、y、z 三个向量可以唯一的确定空间中的一个点。
2、Maven 的坐标
使用如下三个向量在 Maven 的仓库中唯一的确定一个 Maven 工程。
[1]groupid:公司或组织的域名倒序+当前项目名称
[2]artifactId:当前项目的模块名称
[3]version:当前模块的版本
<groupId>com.hqyj.maven</groupId>
<artifactId>Hello</artifactId>
<version>0.0.1-SNAPSHOT</version>
3、如何通过坐标到仓库中查找 jar 包?
[1]将 gav 三个向量连起来 com. hqyj.maven+Hello+0.0.1-SNAPSHOT
[2]以连起来的字符串作为目录结构到仓库中查找 com/ hqyj /maven/Hello/0.0.1-SNAPSHOT/Hello-0.0.1-SNAPSHOT.jar
※注意:我们自己的 Maven 工程必须执行安装操作才会进入仓库。安装的命令是:mvn install
仓库
分类 本地仓库:为当前本机电脑上的所有 Maven 工程服务。 远程仓库 局域网(私服):架设在当前局域网环境下,为当前局域网范围内的所有
Maven 工程服务。
中央仓库:架设在 Internet 上,为全世界所有 Maven 工程服务。
中央仓库镜像:架设在各个大洲,为中央仓库分担流量。减轻中央仓库的压力,同时更快的
存放内容(Maven项目)
所需插件
第三方框架或工具使用jar包
自己开发的maven项目
依赖
setting.xml中的配置
<!-- 改镜像地址
<mirrors>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
-->
修改jdk
<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
修改本地仓库路径
<localRepository>D:\Maven Repository</localRepository>
Maven 中最关键的部分,我们使用 Maven 最主要的就是使用它的依赖管理功能。要理解和掌握 Maven 的依赖管理,我们只需要解决一下几个问题:
1、依赖的目的是什么
当 A jar 包用到了 B jar 包中的某些类时,A 就对 B 产生了依赖,这是概念上的描述。那么如何在项目中以依赖的方式引入一个我们需要的 jar 包呢?
答案非常简单,就是使用 dependency 标签指定被依赖 jar 包的坐标就可以了。
<dependency>
<groupId>com.hqyj.maven</groupId>
<artifactId>Hello</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
2、依赖的范围
大家注意到上面的依赖信息中除了目标 jar 包的坐标还有一个 scope 设置,这是依赖的范围。依赖的范围有几个可选值,我们用得到的是:compile、test、provided 三个。
既标签的可选配置:compile、test、provided、runtime、system、import,下面一一介绍
1)编译依赖范围(compile),该范围就是默认依赖范围,此依赖范围对 于编译、测试、运行三种classpath都有效,举个简单的例子,假如项目中有spring-core的依赖,那么spring-core不管是在编译,测试,还是运行都会被用到,因此spring-core必须是编译范围(构件默认的是编译范围,所以依赖范围是编译范围的无须显示指定)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>2.5</version>
<scope>compile</scope> <!--默认为该依赖范围,无须显示指定--〉
</dependency>
2)测试依赖范围(test),顾名思义就是针对于测试的,使用此依赖范围的依赖,只对测试classpath有效,在编译主代码和项目运行时,都将无法使用该依赖,最典型的例子就是 Junit, 构件在测试时才需要,所以它的依赖范围是测试,因此它的依赖范围需要显示指定为test ,当然不显示指定依赖范围也不会报错,但是该依赖会被加入到编译和运行的classpath中,造成不必要的浪费 。
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
3)已提供依赖范围(provided),使用该依赖范围的maven依赖,只对编译和测试的classpath有效,对运行的classpath无效,典型的例子就是servlet-api, 编译和测试该项目的时候需要该依赖,但是在运行时,web容器已经提供的该依赖,所以运行时就不再需要此依赖,如果不显示指定该依赖范围,并且容器依赖的版本和maven依赖的版本不一致的话,可能会引起版本冲突,造成不良影响。
<dependency>
<groupId>javax-servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
4)运行时依赖范围(runtime),使用该依赖范围的maven依赖,只对测试和运行的classpath有效,对编译的classpath无效,典型例子就是JDBC的驱动实现,项目主代码编译的时候只需要JDK提供的JDBC接口,只有在测试和运行的时候才需要实现上述接口的具体JDBC驱动。
5),系统依赖范围(system),该依赖与classpath的关系与 provided依赖范围完全一致,但是系统依赖范围必须通过配置systemPath元素来显示指定依赖文件的路径,此类依赖不是由maven仓库解析的,而且往往与本机系统绑定,可能造成构件的不可移植,因此谨慎使用,systemPath元素可以引用环境变量:
<dependency>
<groupId>javax.sql</groupId>
<artifactId>jdbc-stext</artifactId>
<version>2.0</version>
<scope>system</scope>
<systemPath>${java.home}/lib/rt.jar</systemPath>
</dependency>
6)导入依赖范围(import),该依赖范围不会对三种classpath产生影响,该依赖范围只能与dependencyManagement元素配合使用,其功能为将目标pom文件中dependencyManagement的配置导入合并到当前pom的dependencyManagement中。有关dependencyManagement的功能请了解maven继承特性。
对于自己开发的Maven工程,使用mvn install命令安装后就可以进入仓库。
生命周期
各构建环节顺序不能乱。
各个阶段生命周期具体任务由插件完成。
Clean 生命周期
Clean 生命周期一共包含了三个阶段:
①pre-clean 执行一些需要在 clean 之前完成的工作
②clean 移除所有上一次构建生成的文件
③post-clean 执行一些需要在 clean 之后立刻完成的工作
Site 生命周期
①pre-site 执行一些需要在生成站点文档之前完成的工作
②site 生成项目的站点文档
③post-site 执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
④site-deploy 将生成的站点文档部署到特定的服务器上
这里经常用到的是 site 阶段和 site-deploy 阶段,用以生成和发布 Maven 站点,这可是 Maven
相当强大的功能,Manager 比较喜欢,文档及统计数据自动生成,很好看。
Default 生命周期
Default 生命周期是 Maven 生命周期中最重要的一个,绝大部分工作都发生在这个生命周期中。这里,
只解释一些比较重要和常用的阶段:
validate
generate-sources
process-sources
generate-resources
process-resources 复制并处理资源文件,至目标目录,准备打包。
compile 编译项目的源代码。
process-classes
generate-test-sources
process-test-sources
generate-test-resources
process-test-resources 复制并处理资源文件,至目标测试目录。
test-compile 编译测试源代码。
process-test-classes
test 使用合适的单元测试框架运行测试。这些测试代码不会被打包或部署。
prepare-package
package 接受编译好的代码,打包成可发布的格式,如 JAR。
pre-integration-test
integration-test
post-integration-test
verify
install 将包安装至本地仓库,以让其它项目依赖。
deploy 将最终的包复制到远程的仓库,以让其它开发人员与项目共享或部署到服务器上运行。
附:Eclipse安装maven
指定maven核心程序位置。
指定本地仓库的位置。
依赖
传递性:
实例
先建立第一个项目project01
建立第二个项目project02
建立第二个项目project03

我们把project01打包安装到本地仓库中。
clean install
在project02中依赖project01
把project02 打包安装在本地仓库
在project03中依赖project02
然后编译项目project03 会发现project01也会在project03中
这就是传递依赖。
排除依赖
上面演示了传递依赖,但是如果我们只需要依赖project02 并不想依赖进来project01怎么办呢?这个时候就要是用exclusions 排除依赖列表
project03排除依赖project01pom.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">
<modelVersion>4.0.0</modelVersion>
<groupId>zzq.mavenProject</groupId>
<artifactId>project03</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>zzq.mavenProject</groupId>
<artifactId>project02</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!--排除依赖传递列表 -->
<exclusions>
<exclusion>
<groupId>zzq.mavenProject</groupId>
<artifactId>project01</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
这样在project03中就不会依赖进来project01
统一版本
统一管理依赖的版本:
这里对Spring各个jar包的依赖版本都是4.0.0
如果需要统一升级为4.1.1,怎么办?手动在pom.xml中逐一修改是不可靠的!!!
可靠的配置方式:
使用标签内使用 自定义标签 统一声明版本号
1.可靠的配置方式
<properties>
<hqyj.spring.version>4.1.1.RELEASE</hqyj.spring.version>
</properties>
2. 在需要统一版本的位置,使用`${自定义标签名}`引用声明的版本号
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${hqyj.spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${hqyj.spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${hqyj.spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${hqyj.spring.version}</version>
</dependency>
其实标签配合自定义标签声明数据的配置并不是只能用于声明依赖的版本号,凡是需要统一声明后再引用的场合都可以使用,例如:统一配置项目构建的源码的字符集格式
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
继承
现状:
project1:junit包:4.0
project2:junit包:4.0
project3:junit包:4.1
需求,需要将三个包版本统一
为了减少重复代码的编写,我们需要创建POM的父子结构,然后在POM中申明一些配置供子POM继承,以实现“一处申明,多处使用的”目的。以之前的模块中的结构为基础,在account-aggregator下创建一个account-parent的子目录,然后在该子目录下创建除account-aggregator模块之外的模块的父模块。为此在该子目录下创建一个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.juvenxu.mvnbook.account</groupId>
<artifactId>account-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
</project>
需要注意的是它的packaging的值必须为pom,这一点与模块聚合一样,作为负模块的POM,其打包类型也必须为pom。由于父模块只是为了消除配置的重复,因此也就不需要src/main/java等目录了。
有了父模块就让其他子模块来继承它,修改account-email的pom文件如下:
<?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>
<parent>
<groupId>com.juvenxu.mvnbook.account</groupId>
<artifactId>account-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../account-parent/pom.xml</relativePath>
</parent>
</project>
parent下的子元素groupId、artifactId和version指定了父模块的坐标,这三个元素是必须的。元素relativePath表示父模块POM的相对路径。当项目构建时,Maven会首先根据relativePath检查父POM,如果找不到,再从本地仓库查找。relativePath的默认值是…/pom.xml,也就是说,Maven默认父POM在上一层目录下。
注:父项目一定要是pom类型,其次…/account-parent/pom.xml
聚合
<modules>
<module>../task-common</module>
<module>../task-sla</module>
<module>../task-sla-web</module>
<module>../task-web-dist</module>
</modules>