一起学Maven

转载自:http://blog.csdn.net/songdeitao/article/details/18452459

一. 初识Maven

开场白

在现在的项目开发过程中,越来越重视项目的管理,而且主流的项目管理框架或者说是工具已经慢慢被Maven取代,在求职者面试过程中,项目开发过程 中,Maven的使用已经成为主流,如何很快着手Maven的项目管理,已经成为包括我在内的很多程序员考虑的问题,在本系列博文中,我将以一个初识 Maven的角度和大家共同学习Maven的项目构建工具的使用,在这个过程中,有可能有很多问题,也或许有很多我没有考虑到的地方,还请高手给予指正, 当然,如果是新入手的学者,也可以在实验过程中给出想法和建议,在此感激不尽。下面进入Maven的学习之路。

什么是Maven?

Maven是基于项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具。类似于大家熟知的Ant工具所起到的效果,当然他们之间存在很多异同点。

为什么要学Maven?

大家会发现,在平时项目中,我们每天有相当一部分时间花在了编译、运行单元测试、生成文档、打包和部署等烦琐且不起眼的工作上,如果你使用Ant,会发现
很多东西都要程序员去定义,去编写build文件,然而有了Maven这个构建工具,能够帮我们自动化构建过程,从清理、编译、测试到生成报告,再到打包
和部署。我们不需要也不应该一遍又一遍地输入命令,一次又一次地点击鼠标,或者小心翼翼的写着配置文件,我们要做的是使用Maven配置好项目,然后输入
简单的命令(如mvn
clean install),Maven会帮我们处理那些烦琐的任务。这一切都体现了一句经典“约定优于配置”,当然Maven不仅是构建工具,还是一个依赖管理工具和项目信息管理工具,况且Maven也是跨平台的。这些都会通过实例说明。

获取和安装

下载地址:http://maven.apache.org/download.cgi,进去之后,会发现有很多版本,我们将使用较新的版本apache-maven-3.1.1-bin.zip,  (windows平台)如图1所示:

一起学Maven

图1

如果想查看源码可以下载src版本,当然也可以选择其他操作系统,比如linux平台下的文件,本系列只介绍windows平台下,其他平台还请参照其他博文讲解。

找到下载后的文件,并将文件解压到一个自己定义的目录,如图2所示:

一起学Maven

图2

此时发现有四个目录,下面讲解四个目录中文件的作用

bin目录:

该目录包含了mvn运行的脚本,这些脚本用来配置java命令,准备好classpath和相关的java系统属性,然后执行java命令

boot目录:

该目录只包含一个文件,该文件为plexus-classworlds-xxx.jar。plexus-classworlds是一个类加载器框架,相对于默认的java类加载器,它提供了更丰富的语法以方便配置,maven使用该框架加载自己的类库。

conf目录:

该目录包含了一个非常重要的文件settings.xml。直接修改该文件,就能在机器上全局地定制maven的行为。一般情况下,我们更偏向于复制该文件至~/.m2/目录下(~表示用户目录),然后修改该文件,在用户范围定制maven的行为。

lib目录:

该目录包含了所有maven运行时需要的java类库。

环境变量的配置

打开系统属性(桌面上右键单击“我的电脑”→“属性”),点击高级系统设置,再点击环境变量,在系统变量中新建一个变量,变量名为M2_HOME,变
量值为Maven的安装目录E:\StudySoftware\javaEE\apache-maven-3.1.1(根据自己安装的情况)。点击确定,
接着在系统变量中找到一个名为Path的变量,在变量值的末尾加上%M2_HOME%\bin;,注意多个值之间需要有分号隔开,然后点击确定。至此,环
境变量设置完成,详细情况如图3所示:

一起学Maven

图3

下面将查看配置是否正确,打开命令控制台,输入mvn -v如果发现图4所示的信息,配置就是成功的:

一起学Maven

图4

至此,Maven的环境变量配置成功。

本地仓库

由于运行过mvn命令,那么会在用户目录下发现一个.m2文件,如图5所示:

一起学Maven
                       图5
    其中repository目录,这个目录是存放从网上下载下来的jar,而这些jar就是maven的好处之一,可以自动下载项目中用到的jar包,而这些jar包的存放位置就是一个仓库,存放在本地的就是本地仓库,而存放在网络上的就是maven的*仓库。

由于下载jar文件的增多,会给C盘造成负担,或者在重装系统后,c盘的东西将不复存在,因此可以把repository目录转移到其他盘中储存。

具体做法是:

1. 复制repository目录到其它盘符,本文中是在E:\Workspaces\Maven下

2. 复制刚刚解压好的Maven目录中,conf中的settings.xml文件到E:\Workspaces\Maven目录下,

3. 打开找到如下内容

<localRepository>....</localRepository>改成:

<localRepository>E:/Workspaces/Maven/repository</localRepository>

同样将conf下的settings.xml也改成如上配置,如图6所示:

一起学Maven

图6

保存.完成.

这样就将本地仓库从C:\Users\Steven\.m2\repository移到了E:\Workspaces\Maven\repository中。

Maven小实例

本文在目录E:\Workspaces\STSWorkspace\Maven_01(可以随便找个目录)下,新建pom.xml文件,然后在其中加入如下配置:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. 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">
  4. <modelVersion>4.0.0</modelVersion>
  5. <groupId>com.steven.maven</groupId>
  6. <artifactId>maven_01</artifactId>
  7. <version>0.0.1-SNAPSHOT</version>
  8. </project>

其中

groupId:

项目或者组织的唯一标志,并且配置时生成路径也是由此生成,如com.steven.maven生成的相对路径为:/com/steven/maven
    artifactId:

项目的通用名称
    version:

项目的版本
    接下来在此文件夹中建立src文件夹,然后在src中建立main和test文件夹,然后在main中建立java文件夹,然后在java文件夹中建立com/steven/maven/HelloWorld.java文件,如图7所示:

一起学Maven

图7

HelloWorld.java的内容如下:

  1. package com.steven.maven;
  2. public class HelloWorld{
  3. public void sayHello(){
  4. System.out.println("Hello Maven!");
  5. }
  6. }

然后在命令控制台中执行mvn compile,如图8所示:

一起学Maven
                          图8

会发现出现Downloading下载的提示,这是因为,Maven在执行命令的时候,要加载其他使用到的插件和其他jar包,称为依赖,这个时候就要从
网络上进行下载,所以如何使用Maven,请保持网络是正常的,否则会出现问题。当编译完成的时候出现成功的提示信息,如图9所示:

一起学Maven

图9

此时发现项目目录中多了一个target的目录,如图10所示:

一起学Maven

图10

发现刚刚编译产生的class文件放在了target目录下,所以只要我们按照这个目录格式编写,maven工具就帮助我们执行出结果,然后放在相应的结构目录下。

下面我们将继续编写测试代码,在test目录下新建java文件夹,然后同样新建com/steven/maven/HelloWorldTest.java文件,其中HelloWorldTest文件的内容如下:

  1. package com.steven.maven;
  2. import org.junit.*;
  3. public class HelloWorldTest{
  4. @Test
  5. public void sayHelloTest(){
  6. HelloWorld hw = new HelloWorld();
  7. hw.sayHello();
  8. }
  9. }

此时的目录结构如图11所示:

一起学Maven

图11

然后控制台执行mvn test命令,但此时出现错误信息,如图12所示:

一起学Maven

图12

这是因为测试过程中用到了junit的包,但没有找到,原来的解决办法是:

  • 通过将junit的包加入到环境变量下即可解决

但maven的解决思路是

  • 在pom.xml中加入<dependencies>节点,完成的配置文件如下所示:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. 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">
  4. <modelVersion>4.0.0</modelVersion>
  5. <groupId>com.steven.maven</groupId>
  6. <artifactId>maven_01</artifactId>
  7. <version>0.0.1-SNAPSHOT</version>
  8. <dependencies>
  9. <dependency>
  10. <groupId>junit</groupId>
  11. <artifactId>junit</artifactId>
  12. <version>4.10</version>
  13. </dependency>
  14. </dependencies>
  15. </project>

<dependencies>节点代表项目依赖的jar包,然后加入junit的jar包配置文件即可,此时再次执行mvn test,会发现如图13所示的结果:

一起学Maven
                       图13

这时候maven从网络上下载4.10版本的junit jar包,最后的执行结果如图14所示:

一起学Maven

图14

此时发现测试成功,正确执行Hello Maven!的结果。

此时再来看target中的文件会发现如图15所示的结果:

一起学Maven

图15

如果此时执行mvn clean命令,如图16所示:

一起学Maven

图16

会发现在下载相应插件的同时,执行了清除target目录的操作,然后再来看Maven_01目录中的文件,如图17所示:

一起学Maven

图17

发现target目录已经不存在了,即被maven clean命令清空了。如果接着执行maven test,会发现target目录又出现了。

这个时候再来观察一下一开始配置的本地仓库中的文件,会发现图18的结果:

一起学Maven

图18

我们发现,Maven在执行命令的过程中用到的jar都已经在本地仓库中储藏了,至此,Maven小实例结束。

总结

在本节中,通过Maven的介绍,下载,安装,配置,已经小实例的实现,估计大家也多多少少有些头绪了,通过实例,可以看出Maven可以作为项目的构建
工具,而配置文件很好写,而且写的很少,用到的jar包,不需要手动去添加到环境变量中,只要通过配置,Maven就会通过网络寻找到并且下载到本地仓库
中。

在本节中用到的Maven命令:

mvn compile编译java文件

mvn test执行junit操作

mvn clean清空target目录操作

在此恭祝大家学习愉快!

二. eclipse中的项目构建

前情回顾

在上一节中介绍了Maven的基本安装配置,以及通过一个小实例认识一下maven的基本架构,一切都是通过手动去搭建的,本节将通过工具讲解Maven在Eclipse中如何构建项目的,然后如何去执行相应的操作。

知识补充

一:

在上节提到*仓库,在此给出如何找到*仓库的链接,在Maven解压后的目录中,在lib下,有个maven-model-builder- 3.1.1.jar,(E:\StudySoftware\javaEE\apache-maven-3.1.1\lib\maven-model- builder-3.1.1.jar),用解压缩工具打开后,找到pom-4.0.0.xml文件,打开后,即可找到*仓库定义的url链接,如图1所 示:

一起学Maven

图1

打开链接http://search.maven.org/#browse,就可以看到如图2所示的*工厂的网页,

一起学Maven

图2

在这个文本框中可以输入要寻找的jar包,比如log4j,找到一个1.2.17版本进入后,就可以看到如图2所示的页面:

一起学Maven

图3

将红色区域复制后可以加到pom.xml中,Maven就可以将需要的jar文件下载到本地仓库了。

二:

在上节中,我们发现Maven的项目是按照一定的架构来编写的,目录结构都是固定的,也就是如果想使用Maven所带来的功能,就要遵守Maven所定义的规则,约定好了,配置就会减少,从而方便开发。

在这里,将介绍Maven中mvn archetype:generate命令,来建立一个项目。

比如在E:\Workspaces\STSWorkspace下建立Maven_02的项目,首先在控制台输入mvn archetype:generate命令,会发现Maven开始下载命令中需要的插件和jar文件了,如图4所示:

一起学Maven

图4

然后等到下载一段时间后停止到如图5所示:

一起学Maven

图5

然后回车就可以,出现选择版本,选择最新版本即可,如图6所示:

一起学Maven

图6

然后选6后回车,然后填写groupId, artifactId,version,package(敲回车默认包),如图7所示:

一起学Maven

图7

此时查看E:\Workspaces\STSWorkspace目录,会发现Maven_02项目已经成功构建了,如图8所示:

一起学Maven

图8

由此可以看出通过Maven的命令mvn archetype:generate构建出来的框架是约定俗成的!

注:也可以通过mvn archetype:generate -DgroupId=com.steven.maven -DrtifactId=Maven_02 -Dversion=0.0.1-SNAPSHOT创建一样的效果。

Eclipse项目构建

在实际开发中都是会在项目工具中,如Eclipse中使用,下面将通过Eclipse工具,如果我们使用最原始的Eclipse作为开发工具,也就是说用
不带任何插件的Eclipse构建Maven项目,仍然需要下载插件m2eclipse,这里为了方便直接使用Spring Tool
Suite(STS),下载地址为http://download.springsource.com/release/STS/3.4.0/dist/e4.3/spring-tool-suite-3.4.0.RELEASE-e4.3.1-win32.zip,已经带有Maven,下载后打开如图9所示:

一起学Maven

图9

然后打开后,做下面的操作,进行配置Maven

首先选择Window->Preference找到左边侧边栏Maven选项,

然后根据图示进行配置,选择本地解压后的Maven目录,点击确定,如图10所示:

一起学Maven

图10

然后选择本地仓库的位置,并完成配置,如图11,12所示:

一起学Maven

图11

一起学Maven

图12

这样的话,Eclipse中就已经正确配置Maven了。接下来就可以使用Eclipse构建Maven项目:

新建New->Other->Maven->Maven Project,如图13所示:

一起学Maven

图13

点击Next,默认Workspace,Next,然后选择quickstart模式,如图14所示:

一起学Maven

图14

点击Next,填入信息,如图15所示:

一起学Maven

图15

比如建议一个用户管理项目,填写以上的信息,然后点击Finish,完成项目的创建,此时如图16所示:

一起学Maven

图16

此时通过Eclipse构建的Maven项目已经成功了,如果想进行测试,可以通过如图17所示的方法进行测试:

一起学Maven

图17

测试结果可以通过控制台查看:

  1. [INFO] Scanning for projects...
  2. [INFO]
  3. [INFO] ------------------------------------------------------------------------
  4. [INFO] Building user-core 0.0.1-SNAPSHOT
  5. [INFO] ------------------------------------------------------------------------
  6. [INFO]
  7. [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ user-core ---
  8. [INFO] Using 'UTF-8' encoding to copy filtered resources.
  9. [INFO] skip non existing resourceDirectory E:\Workspaces\STSWorkspace\user-core\src\main\resources
  10. [INFO]
  11. [INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ user-core ---
  12. [INFO] Nothing to compile - all classes are up to date
  13. [INFO]
  14. [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ user-core ---
  15. [INFO] Using 'UTF-8' encoding to copy filtered resources.
  16. [INFO] skip non existing resourceDirectory E:\Workspaces\STSWorkspace\user-core\src\test\resources
  17. [INFO]
  18. [INFO] --- maven-compiler-plugin:2.5.1:testCompile (default-testCompile) @ user-core ---
  19. [INFO] Nothing to compile - all classes are up to date
  20. [INFO]
  21. [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ user-core ---
  22. [INFO] Surefire report directory: E:\Workspaces\STSWorkspace\user-core\target\surefire-reports
  23. -------------------------------------------------------
  24. T E S T S
  25. -------------------------------------------------------
  26. Running com.steven.entity.AppTest
  27. Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.044 sec
  28. Results :
  29. Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
  30. [INFO] ------------------------------------------------------------------------
  31. [INFO] BUILD SUCCESS
  32. [INFO] ------------------------------------------------------------------------
  33. [INFO] Total time: 8.959s
  34. [INFO] Finished at: Sat Jan 18 23:47:29 CST 2014
  35. [INFO] Final Memory: 6M/15M
  36. [INFO] ------------------------------------------------------------------------


      注:至此,Eclipse已经成功构建Maven项目,会发现通过工具会减少很多操作,项目的开发仍旧按照此架构进行,在接下来的博文中将会通过项目来讲解Maven的功能。

在此恭祝大家学习愉快!

三. Maven的依赖管理特性

前情回顾

在上一节中介绍了通过工具eclipse构建了maven项目,并且仅仅做了简单的运行演示,本节将通过eclipse构建出一个项目中的几个模块,并且通过这几个模块的联系讲解maven中依赖的特性。

项目构建

本章通过一个典型的项目构建过程来学习Maven的依赖传递性。

项目获取地址http://download.csdn.net/detail/songdeitao/6927445

总共分为三个模块的项目编写user-core,user-log,user-service,在user-core中主要实现基本的实体类,初始文 件,dao的编写,在user-log中简单模拟日志文件的记录,在user-service模块中主要引入前两个模块,从而进行编写service模块 的功能,在这里模块的编写不是重点,这些都会给出代码,然而进行Maven依赖与传递的讲解才是重点,所以很多时候代码都是为了演示出效果,和实际开发还是有些差别,但所指代的思想是项目中所存在的。

普通依赖

Maven的依赖是使用Maven坐标来定位的,而Maven坐标主要由GAV(groupId, artifactId, version)构成,因此,使用任何一个依赖之间,你都需要知道它的Maven坐标,在之前的第二章节中,从引入了Maven的*工厂的网页,在此引入一个常用的Maven搜索jar包的资源库网页http://www.mvnrepository.com/,在此可以查找所需要的jar文件的GAV,比如在本文的第一章节的如下配置:

  1. <span style="font-family:KaiTi_GB2312;font-size:18px;"><dependency>
  2. <groupId>junit</groupId>
  3. <artifactId>junit</artifactId>
  4. <version>4.10</version>
  5. </dependency></span>

可以通过如下列图所示的步骤进行查找到,而且以后的jar包查找过程都是按照此步骤进行获取,然后复制到pom.xml<dependencies>元素下,Maven就能在本地或者远程仓库中找到对应的jar包(不一定可以找到所有的jar文件)

一起学Maven

图1

一起学Maven

图2

一起学Maven

图3

此配置声明了一个对junit的依赖,它的groupId是junit, artifactId是junit,
version是4.10。这一组GAV构成了一个Maven坐标,基于此,Maven就能在本地或者远程仓库中找到对应的junit-4.10.jar
文件。

传递依赖

一:

首先紧跟第二章节的新建项目构建出如下图所示的结构图,

一起学Maven

图4

通过此模块的构建,主要说明Maven的一下几个问题

1、目录结构的默认构建,比如资源文件的src/main/resources目录的构建

2、pom.xml文件的使用到的jar包的引入,比如在user-core中的文件内容如下所示:

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <groupId>com.steven.user</groupId>
  5. <artifactId>user-core</artifactId>
  6. <version>0.0.1-SNAPSHOT</version>
  7. <packaging>jar</packaging>
  8. <name>user-core</name>
  9. <url>http://maven.apache.org</url>
  10. <properties>
  11. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  12. </properties>
  13. <dependencies>
  14. <dependency>
  15. <groupId>junit</groupId>
  16. <artifactId>junit</artifactId>
  17. <version>4.10</version>
  18. <scope>test</scope>
  19. </dependency>
  20. <dependency>
  21. <groupId>log4j</groupId>
  22. <artifactId>log4j</artifactId>
  23. <version>1.2.14</version>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.hibernate</groupId>
  27. <artifactId>hibernate-core</artifactId>
  28. <version>4.1.1.Final</version>
  29. </dependency>
  30. <dependency>
  31. <groupId>mysql</groupId>
  32. <artifactId>mysql-connector-java</artifactId>
  33. <version>5.1.8</version>
  34. </dependency>
  35. </dependencies>
  36. </project>


            通过资源库中查找到相应的jar包,放到pom.xml中之后,Eclipse就会自动会和本地资源库或者远程仓库中进行匹配,如果本地中没有,就会通过网络下载从远程仓库中下载到本地仓库中。

3、进行Maven项目模块的打包和加入到本地资源库的命令,如图所示

一起学Maven

图5

这样就可以执行打包或者将打包后的jar添加到本地仓库中。

二:

接着引入user-log,user-service

一起学Maven一起学Maven

图6                            图7

其中user-log的pom.xml如下所示

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <groupId>com.steven.user</groupId>
  5. <artifactId>user-log</artifactId>
  6. <version>0.0.1-SNAPSHOT</version>
  7. <packaging>jar</packaging>
  8. <name>user-log</name>
  9. <url>http://maven.apache.org</url>
  10. <properties>
  11. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  12. </properties>
  13. <dependencies>
  14. <dependency>
  15. <groupId>junit</groupId>
  16. <artifactId>junit</artifactId>
  17. <version>4.10</version>
  18. <scope>test</scope>
  19. </dependency>
  20. <dependency>
  21. <groupId>dom4j</groupId>
  22. <artifactId>dom4j</artifactId>
  23. <version>1.5</version>
  24. </dependency>
  25. <dependency>
  26. <groupId>log4j</groupId>
  27. <artifactId>log4j</artifactId>
  28. <version>1.2.4</version>
  29. </dependency>
  30. </dependencies>
  31. </project>


    其中user-service的pom.xml如下所示

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <groupId>com.steven.user</groupId>
  5. <artifactId>user-service</artifactId>
  6. <version>0.0.1-SNAPSHOT</version>
  7. <packaging>jar</packaging>
  8. <name>user-service</name>
  9. <url>http://maven.apache.org</url>
  10. <properties>
  11. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  12. </properties>
  13. <dependencies>
  14. <dependency>
  15. <groupId>junit</groupId>
  16. <artifactId>junit</artifactId>
  17. <version>4.10</version>
  18. <scope>test</scope>
  19. </dependency>
  20. <dependency>
  21. <groupId>${project.groupId}</groupId>
  22. <artifactId>user-log</artifactId>
  23. <version>${project.version}</version>
  24. </dependency>
  25. <dependency>
  26. <groupId>${project.groupId}</groupId>
  27. <artifactId>user-core</artifactId>
  28. <version>${project.version}</version>
  29. </dependency>
  30. </dependencies>
  31. </project>

此时细心的读者会发现在user-service的pom文件中出现${project.groupId}和${project.version}的写法,这是Maven的内置隐式变量,常用的如下介绍:

${basedir} 项目根目录
${project.build.directory} 构建目录,缺省为target
${project.build.outputDirectory} 构建过程输出目录,缺省为target/classes
${project.build.finalName} 产出物名称,缺省为${project.artifactId}-${project.version}
${project.packaging} 打包类型,缺省为jar
${project.xxx} 当前pom文件的任意节点的内容(这里所使用到的)

注意:

在完成user-service对user-log和user-service模块的jar包引入的时候,一定要将这两个模块进行install处理,这样在user-service中才可以访问到前两个模块的jar包。

传递依赖

此时打开user-service的pom的dependency  hierarchy图,如图所示:

一起学Maven

图8

会发现在user-log中使用log4j-1.2.4.jar而user-core中使用log4j-1.2.14.jar,但user-service包含user-log和user-core后,所使用的是log4j-1.2.4,为什么不使用新的版本呢?

这是因为我在user-service中将user-log写在了user-core前面。但难道谁写在前面就在前面了吗?

那我就将这两个配置调换一下,得到的图如图9所示

一起学Maven

图9

再看log4j变成了log4j-1.2.14.jar(图中没有标出,但不难看出),那确实是这样吗?然后看图8中dom4j是1.5版本,在图9中调换过位置后还是1.5版本,怎么回事?细心的读者会发现log4j是出于user-core和user-log的同一级别,而dom4j在user-core和user-log却不是在同一级别。

奥,我明白了,原来是这么一回事:

结论:

1、当依赖的级别相同时,引入最先导入的jar包

2、当依赖级别不同时候,引入级别最近的jar包

那我偏要使用dom4j1.6.1的版本,那怎么办呢?

排除依赖

Maven很智能,在此提供一个元素,exclusion,只要在不想要的模块中添加此元素,比如不想要user-log的dom4j1.5版本,则只要在user-service中这样编写即可:

  1. <dependency>
  2. <groupId>${project.groupId}</groupId>
  3. <artifactId>user-log</artifactId>
  4. <version>${project.version}</version>
  5. <exclusions>
  6. <exclusion>
  7. <groupId>dom4j</groupId>
  8. <artifactId>dom4j</artifactId>
  9. </exclusion>
  10. </exclusions>
  11. </dependency>


            此时在查看user-service的pom的dependency  hierarchy图,发现已经成功使用dom4j1.6.1版本了,如图所示

一起学Maven

图10

依赖范围(scope)

读者还会发现,在图8,9,10中,每个jar后都有类似[compile]的标识,这是什么意思呢?这里将引入Maven的依赖范围概念。

什么是依赖范围呢?

引入:

Maven在编译主代码的时候需要使用一套classpath,在编译和执行测试的时候会使用另一套classpath,实际运行项目的时候,又会使用一套classpath。
    依赖范围就是用来控制依赖与这三种classpath(编译classpath、测试classpath、运行classpath)的关系,

Maven有以下几种依赖范围:
    compile: 编译依赖范围。

如果没有指定,就会默认使用该依赖范围。使用此依赖范围的Maven依赖,对于编译、测试、运行三种classpath都有效。
 
    test: 测试依赖范围。

使用此依赖范围的Maven依赖,只对于测试classpath有效,在编译主代码或者运行项目的使用时将无法使用此类依赖。典型的例子就是JUnit,
它只有在编译测试代码及运行测试的时候才需要。这也是本文的pom文件中为何junit的scope是使用test范围的原因。
 
    provided: 已提供依赖范围。

使用此依赖范围的Maven依赖,对于编译和测试classpath有效,但在运行时无效。典型的例子是servlet-api,编译和测试项目的时候需要该依赖,但在运行项目的时候,由于容器已经提供,就不需要Maven重复地引入一遍。
 
    runtime: 运行时依赖范围。

使用此依赖范围的Maven依赖,对于测试和运行classpath有效,但在编译主代码时无效。典型的例子是JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体JDBC驱动。

   

    注意:以上四种范围是开发中常用的配置,而以下两种都是不要求的,使用的很少,了解即可

system: 系统依赖范围。

该依赖与三种
classpath的关系,和provided依赖范围完全一致。但是,使用system范围依赖时必须通过systemPath元素显式地指定依赖文件
的路径。由于此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此应该谨慎使用。

import(Maven 2.0.9及以上): 导入依赖范围。

总结

至此,对于Maven的依赖性已经讲解差不多了,余下的在开发中很少使用到,所以掌握以上内容已经足够使用了,而且Maven的依赖算是Maven的学习中的一个难点,因此需要自己手动创建项目进行测试验证。

    在此,一样恭祝大家学习愉快,新年快乐!

 

四. Maven聚合和继承

前情回顾

在上一章节中,通过三个模块的项目开发,讲解了Maven依赖管理的特性,从而对Maven依赖的表现,范围等有着一定的认识,但每次对一个模块进行更 改,都要将对应模块进行test或者package或者install的操作后,使用到该模块的项目才可以使用,这样的操作有些繁琐,如果有过多的模块, 那将需要执行多次的操作,还有,在每个模块pom.xml文件中,存在很多之前模块相同的依赖包,并且以后开发时候还会有很多相同的常量。

问题引出

能不能执行一次命令就可以完成对每个模块的操作?(Maven的聚合)

能不能不要在每个模块中都要定义相同的依赖包或者重复的元素呢?(Maven的继承)

聚合和继承的实现

在实现过程中,将继续使用上一个章节构建的项目模块,并在上进行更改,如果没有项目概念的,可以参考上一章节的讲解,构建相应的项目。

聚合继承的操作只要在项目模块的目录中创建实现的pom.xml文件,然后在pom.xml文件中定义相应的操作即可,如下图所示

一起学Maven

图1

但在这里我们可以通过Eclipse构建pom.xml文件(可以同时进行聚合和继承的操作),可以通过以下步骤

一起学Maven

图2

一起学Maven

图3

一起学Maven

图4

然后生成pom.xml文件

一起学Maven

图5

此时聚合的实现,只要在pom.xml中添加聚合的模块即可,实现的操作如下所示:

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <groupId>com.steven.user</groupId>
  5. <artifactId>user-parent</artifactId>
  6. <version>0.0.1-SNAPSHOT</version>
  7. <packaging>pom</packaging>
  8. <modules>
  9. <module>../user-core</module>
  10. <module>../user-log</module>
  11. <module>../user-service</module>
  12. </modules>
  13. </project>


注意:

这里的<module>模块中../是指代上一级目录,因为在Eclipse中需要指向上一级才可以引入相应的模块。
    这时候,对parent模块执行clean操作,会发现其包含的每个模块都已经执行了操作,

  1. [INFO] Scanning for projects...
  2. [INFO] ------------------------------------------------------------------------
  3. [INFO] Reactor Build Order:
  4. [INFO]
  5. [INFO] user-core
  6. [INFO] user-log
  7. [INFO] user-service
  8. [INFO] user-parent
  9. [INFO]
  10. [INFO] ------------------------------------------------------------------------
  11. [INFO] Building user-core 0.0.1-SNAPSHOT
  12. [INFO] ------------------------------------------------------------------------
  13. [INFO]
  14. [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ user-core ---
  15. [INFO] Deleting E:\Workspaces\STSWorkspace\user-core\target
  16. [INFO]
  17. [INFO] ------------------------------------------------------------------------
  18. [INFO] Building user-log 0.0.1-SNAPSHOT
  19. [INFO] ------------------------------------------------------------------------
  20. [INFO]
  21. [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ user-log ---
  22. [INFO] Deleting E:\Workspaces\STSWorkspace\user-log\target
  23. [INFO]
  24. [INFO] ------------------------------------------------------------------------
  25. [INFO] Building user-service 0.0.1-SNAPSHOT
  26. [INFO] ------------------------------------------------------------------------
  27. [INFO]
  28. [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ user-service ---
  29. [INFO] Deleting E:\Workspaces\STSWorkspace\user-service\target
  30. [INFO]
  31. [INFO] ------------------------------------------------------------------------
  32. [INFO] Building user-parent 0.0.1-SNAPSHOT
  33. [INFO] ------------------------------------------------------------------------
  34. [INFO]
  35. [INFO] ---<span style="color:#ff0000;"> maven-clean-plugin:2.5:clean (default-clean) @ user-parent </span>---
  36. [INFO] ------------------------------------------------------------------------
  37. [INFO] Reactor Summary:
  38. [INFO]
  39. [INFO] <span style="color:#ff0000;">user-core</span> ......................................... SUCCESS [0.255s]
  40. [INFO] <span style="color:#ff0000;">user-log</span> .......................................... SUCCESS [0.014s]
  41. [INFO] <span style="color:#ff0000;">user-service</span> ...................................... SUCCESS [0.015s]
  42. [INFO] user-parent ....................................... SUCCESS [0.002s]
  43. [INFO] ------------------------------------------------------------------------
  44. [INFO] BUILD SUCCESS
  45. [INFO] ------------------------------------------------------------------------
  46. [INFO] Total time: 0.500s
  47. [INFO] Finished at: Mon Feb 17 21:21:50 CST 2014
  48. [INFO] Final Memory: 4M/15M
  49. [INFO] ------------------------------------------------------------------------


    下面进行继承的操作,继承的操作在这里主要对依赖和常量进行配置,配置后的pom文件依次是

user-parent中pom.xml

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <groupId>com.steven.user</groupId>
  5. <artifactId>user-parent</artifactId>
  6. <version>0.0.1-SNAPSHOT</version>
  7. <packaging>pom</packaging>
  8. <modules>
  9. <module>../user-core</module>
  10. <module>../user-log</module>
  11. <module>../user-service</module>
  12. </modules>
  13. <url>http://maven.apache.org</url>
  14. <properties>
  15. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  16. </properties>
  17. <dependencyManagement>
  18. <dependencies>
  19. <dependency>
  20. <groupId>junit</groupId>
  21. <artifactId>junit</artifactId>
  22. <version>4.10</version>
  23. <scope>test</scope>
  24. </dependency>
  25. <dependency>
  26. <groupId>log4j</groupId>
  27. <artifactId>log4j</artifactId>
  28. <version>1.2.14</version>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.hibernate</groupId>
  32. <artifactId>hibernate-core</artifactId>
  33. <version>4.1.1.Final</version>
  34. </dependency>
  35. <dependency>
  36. <groupId>mysql</groupId>
  37. <artifactId>mysql-connector-java</artifactId>
  38. <version>5.1.8</version>
  39. </dependency>
  40. <dependency>
  41. <groupId>dom4j</groupId>
  42. <artifactId>dom4j</artifactId>
  43. <version>1.5</version>
  44. </dependency>
  45. <dependency>
  46. <groupId>${project.groupId}</groupId>
  47. <artifactId>user-core</artifactId>
  48. <version>${project.version}</version>
  49. </dependency>
  50. <dependency>
  51. <groupId>${project.groupId}</groupId>
  52. <artifactId>user-log</artifactId>
  53. <version>${project.version}</version>
  54. <exclusions>
  55. <exclusion>
  56. <groupId>dom4j</groupId>
  57. <artifactId>dom4j</artifactId>
  58. </exclusion>
  59. </exclusions>
  60. </dependency>
  61. </dependencies>
  62. </dependencyManagement>
  63. </project>

user-core中pom.xml

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <parent>
  5. <groupId>com.steven.user</groupId>
  6. <artifactId>user-parent</artifactId>
  7. <version>0.0.1-SNAPSHOT</version>
  8. <relativePath>../user-parent/pom.xml</relativePath>
  9. </parent>
  10. <artifactId>user-core</artifactId>
  11. <packaging>jar</packaging>
  12. <name>user-core</name>
  13. <dependencies>
  14. <dependency>
  15. <groupId>junit</groupId>
  16. <artifactId>junit</artifactId>
  17. </dependency>
  18. <dependency>
  19. <groupId>log4j</groupId>
  20. <artifactId>log4j</artifactId>
  21. </dependency>
  22. <dependency>
  23. <groupId>org.hibernate</groupId>
  24. <artifactId>hibernate-core</artifactId>
  25. </dependency>
  26. <dependency>
  27. <groupId>mysql</groupId>
  28. <artifactId>mysql-connector-java</artifactId>
  29. </dependency>
  30. </dependencies>
  31. </project>

user-log中pom.xml

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <parent>
  5. <groupId>com.steven.user</groupId>
  6. <artifactId>user-parent</artifactId>
  7. <version>0.0.1-SNAPSHOT</version>
  8. <relativePath>../user-parent/pom.xml</relativePath>
  9. </parent>
  10. <artifactId>user-log</artifactId>
  11. <packaging>jar</packaging>
  12. <name>user-log</name>
  13. <dependencies>
  14. <dependency>
  15. <groupId>junit</groupId>
  16. <artifactId>junit</artifactId>
  17. </dependency>
  18. <dependency>
  19. <groupId>dom4j</groupId>
  20. <artifactId>dom4j</artifactId>
  21. </dependency>
  22. <dependency>
  23. <groupId>log4j</groupId>
  24. <artifactId>log4j</artifactId>
  25. </dependency>
  26. </dependencies>
  27. </project>

user-service中pom.xml

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <parent>
  5. <groupId>com.steven.user</groupId>
  6. <artifactId>user-parent</artifactId>
  7. <version>0.0.1-SNAPSHOT</version>
  8. <relativePath>../user-parent/pom.xml</relativePath>
  9. </parent>
  10. <artifactId>user-service</artifactId>
  11. <packaging>jar</packaging>
  12. <name>user-service</name>
  13. <dependencies>
  14. <dependency>
  15. <groupId>junit</groupId>
  16. <artifactId>junit</artifactId>
  17. </dependency>
  18. <dependency>
  19. <groupId>${project.groupId}</groupId>
  20. <artifactId>user-core</artifactId>
  21. </dependency>
  22. <dependency>
  23. <groupId>${project.groupId}</groupId>
  24. <artifactId>user-log</artifactId>
  25. </dependency>
  26. </dependencies>
  27. </project>


    此时即可完成继承的操作,会发现user-core,user-log,user-service中版本号,依赖范围,排除依赖都不需要写了,只要都写在父文件中就可以了,这样就减少了很多重复代码的编写了。

总结

此时就可以通过父类user-parent执行聚合继承操作后,对其他模块进行统一管理,这里有几个提示点:

1、通过聚合就可以共同操作,通过继承就可以解决jar冲突,排除依赖一样可以写在父文件中,

2、在Eclipse中进行对模块依赖的控制,可以先将一个模块的所有依赖放到父文件的<dependencyManagement>节点
下,然后在该模块中Eclipse会有重复的提示,删除重复行即可,然后在其他模块中先对重复行进行删除,对父文件中没有的依赖进行拷贝。

在此预祝大家学习愉快!有任何错误或者问题可以提出,在此不胜感激!

五. Maven仓库管理器之初识Nexus

认识Nexus

Nexus是Maven的最常用的仓库管理器,可以认为是Maven的私服,通过此可以免去自己(本地仓库)直接去购买游戏提供商的服务(Maven的中 央仓库),减少费用开支(带宽和时间等)。同时,Nexus提供强大的仓库管理功能,友好的操作界面,占用内存小等优势已经让Nexus成为主流的 Maven仓库管理器。

为什么要构建Nexus

大家可以考虑一下,在实际的开发中,我们不可能是自己开发(如果这样,我只能说Maven可以不需要使用了),而且在多人多个模块开发的时候,我们构建的 Maven项目,总会有一个模块需要另一个模块的依赖,或者有相同的jar包,当然,我们可以通过svn这样的工具进行同步,但这样不断进行同步,会增加 开发的复杂度;

再一个,开发中,如果新增加一个开发者,那么当他将项目构建时候,或许会根据pom文件从*仓库中下载大量的jar包,会造成网络问题,同时,当一直访问同一个地址,有可能被认为是攻击,还有,如果外网断掉了,这样会造成业务中断。

获取和使用

打开连接http://www.sonatype.org/downloads/nexus-latest-bundle.zip,Nexus提供了两种使用方式,刚下载的就是内嵌服务器jetty的方式,只要你有JRE就能直接运行,第二种方式是WAR包,需要将其发布到web容器比如tomcat中才可以。

注:下载后有可能会比文中使用的版本要新,但都是一样的操作。

下载完后,进行解压,解压后会发现有两个文件夹,如图1所示:

一起学Maven

图1

第一个文件夹中是Nexus的一些控制文件,类似于tomcat中的结构,第二个文件夹主要是用来存放从*仓库中下载的jar等文件。

将E:\StudySoftware\javaEE\nexus-2.7.2-03-bundle\nexus-2.7.2-03\bin添加到环境变量中(为了在命令控制台总可以很好的操作),如图2所示

一起学Maven

图2

接下来,打开命令控制台,输入nexus,即可显示如图3信息

一起学Maven

图3

这个表示Nexus环境变量配置成功,下面进行配置E:\StudySoftware\javaEE\nexus-2.7.2-03-bundle\nexus-2.7.2-03\bin\jsw\conf\wrapper.conf文件,做如下修改(如果有配置过JRE路径可以不需要此项配置)

一起学Maven

图4

一起学Maven

图5

然后执行如下操作nexus install:

一起学Maven

图6

会发现安装成功,但有时会出现以下问题,wrapper | OpenSCManager failed问题,如图7所示:

一起学Maven

图7

问题是命令控制台没有按管理员权限打开,即没有权限,解决方法就是将命令控制台以管理员的方式打开,如图8所示进行设置:

一起学Maven

图8

这样打开后既可和图6的执行效果一样。

刚刚执行过nexus install命令,即将nexus的服务安装到windows的服务中,下面我们启动服务。

方法一:

我们可以通过windows中的服务查看,如图9所示(可以通过系统键+R,然后输入services.msc回车即可出现图示)

一起学Maven

图9

方法二:

一起学Maven

这两种方法都可以进行服务启动。

检验:

下面可以在浏览器中输入地址http://localhost:8081/nexus/index.html进行打开Nexus的UI界面(如果是装在其他电脑上的,则需要换成电脑的准确IP地址,而我只是作为讲解,装在自己的电脑上了(哎!悲催的电脑,都快吃不消了,以后有钱一定换个好的!))

一起学Maven

图11

这是打开后的页面,下面点击右上角的Log in,用户名为admin,密码默认为admin123,如图12所示:

一起学Maven

图12

登录成功后如图13所示:

一起学Maven

图13

登录成功后,下面就将进行Nexus的配置,以及讲解Nexus的仓库管理功能,由于篇幅问题,或者写的确实有些详细了,然后打算通过再一次讲解具体的Nexus的使用过程。

在此恭祝大家学习愉快!

六. Maven仓库管理器之应用Nexus

注:本博文是接着上一章节继续讲解

Nexus-私有仓库的配置

点击左边导航栏的Repositories选项,会显示一个所有仓库及仓库组的列表,Type字段的值有group,hosted,proxy,virtual(在Maven1中使用,这里不需要关心),如图14所示:

一起学Maven

图14

在这里:

  • hosted,本地仓库,这个仓库主要是用来存放本地的依赖包,服务于局域网,不访问公网
  • proxy,代理仓库,用来存放nexus从公网中获取的依赖包,这里有*仓库,Apache和Codehaus开源网站的依赖包
  • group,仓库组,用来合并多个hosted/proxy仓库,通常我们配置maven依赖仓库组

比如点击Type为group,如图15所示:

一起学Maven

图15

会发现,在Ordered Group Repositories中,有所有hosted和proxy的仓库,而图15中箭头所指的地方有四种类型的仓库,分别是Releases(hosted), Snapshots(hosted),
3rd Party(hosted),Central(proxy),而Central指的是*仓库,不知道大家是否还有印象,在本系列第二章节,曾经提到*仓库的位置,存在于apache-maven-3.1.1\lib\maven-model-builder-3.1.1.jar中的org\apache\maven\model\pom-4.0.0.xml文件中,定义了*仓库的位置,配置文件如下所示

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


    其中url指向了*仓库的位置http://repo.maven.apache.org/maven2,

而Releases, Snapshots, 3rd Party,主要功能如下:
    Releases: 这里存放我们自己项目中发布的构建, 通常是Release版本
    Snapshots: 这个仓库非常的有用, 它的目的是让我们可以发布那些非release版本, 非稳定版本,
比如我们在trunk下开发一个项目,在正式release之前你可能需要临时发布一个版本给你的同伴使用, 因为你的同伴正在依赖你的模块开发,
那么这个时候我们就可以发布Snapshot版本到这个仓库, 你的同伴就可以通过简单的命令来获取和使用这个临时版本
    3rd Party: 顾名思义, 第三方库, 你可能会问不是有*仓库来管理第三方库嘛, 没错, 这里的是指可以让你添加自己的第三方库,
比如有些构件在*仓库是不存在的. 比如你在*仓库找不到Oracle 的JDBC驱动, 这个时候我们就需要自己添加到3rd party仓库

在settings.xml中配置远程仓库

既然这个group已经包含了四个仓库,那么只要将这个组进行配置,在Maven中就会引用所有在这个组对应的仓库中的依赖包,配置的URL地址为http://localhost:8081/nexus/content/groups/public/。我们可以配置在项目中的user-parent的pom.xml文件中,但此时会有个问题,这样的配置仅仅是对当前的项目有效(user-parent是父文件,其子文件继承),如果项目有很多,而不需要每个项目都要进行以上设置,也就是只要设置一次,然后本机的项目就会自动从nexus中寻找依赖包,如何做呢?

Maven仓库组

因为Maven在本机中是同一个,所以只要在Maven所对应的settings.xml中进行配置就好,(本博客settings.xml对应的路径为E:\Workspaces\Maven\settings.xml),配置如下:

  1. …………………………………………
  2. <profiles>
  3. <profile>
  4. <id>nexusProFile</id>
  5. <repositories>
  6. <repository>
  7. <id>localNexus</id>
  8. <name>Nexus Repository</name>
  9. <url>http://localhost:8081/nexus/content/groups/public/</url>
  10. <releases>
  11. <enabled>true</enabled>
  12. </releases>
  13. <snapshots>
  14. <!-- 此选项默认是关闭的,手动打开 -->
  15. <enabled>true</enabled>
  16. </snapshots>
  17. </repository>
  18. </repositories>
  19. </profile>
  20. </profiles>
  21. <activeProfiles>
  22. <!-- 激活上面的配置 -->
  23. <activeProfile>nexusProFile</activeProfile>
  24. </activeProfiles>
  25. …………………………………………


      Maven中的profile是一组可选的配置,可以用来设置或者覆盖配置默认值。有了profile,你就可以为不同的环境定制构建。  
    这个时候,做个试验,可以在user-core的pom.xml中加入以下依赖(这个依赖包并不存在于本地或者Nexus仓库中)

  1. <dependency>
  2. <groupId>org.mybatis</groupId>
  3. <artifactId>mybatis</artifactId>
  4. <version>3.1.1</version>
  5. </dependency>


    添加好后进行保存,会发现Eclipse的控制台中有如图16的信息:
一起学Maven
                       图16

这表明,Maven已经从通过Nexus下载依赖包了,而Nexus从*工厂中进行下载。
    接着看图17:

一起学Maven                    图17

这也验证了Nexus已经将mybatis的依赖包下载到了仓库中。
    但此时会有个问题,如果将Nexus服务停止,如图18所示

一起学Maven                   图18

这个时候在user-core的pom.xml中添加原来没有的依赖配置文件(可以随便找个不存在的jar依赖文件进行测试,这里用使用Spring)

  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-core</artifactId>
  4. <version>3.2.2.RELEASE</version>
  5. </dependency>


这个时候在Eclipse中点击保存,会发现如下的信息

  1. 14-3-7 GMT+0800下午8:29:41: [INFO] Using org.eclipse.m2e.jdt.JarLifecycleMapping lifecycle mapping for MavenProject: com.steven.user:user-core:0.0.1-SNAPSHOT @ E:\Workspaces\STSWorkspace\user-core\pom.xml.
  2. 14-3-7 GMT+0800下午8:29:42: [INFO] Number of application's worked threads is 4
  3. 14-3-7 GMT+0800下午8:29:44: [INFO] Downloaded http://localhost:8081/nexus/content/groups/public/org/springframework/spring-core/3.2.2.RELEASE/spring-core-3.2.2.RELEASE.pom
  4. 14-3-7 GMT+0800下午8:29:44: [INFO] Number of application's worked threads is 4
  5. 14-3-7 GMT+0800下午8:29:47: [INFO] Downloading http://repo.maven.apache.org/maven2/org/springframework/spring-core/3.2.2.RELEASE/spring-core-3.2.2.RELEASE.pom
  6. 14-3-7 GMT+0800下午8:29:47: [INFO] Downloaded http://repo.maven.apache.org/maven2/org/springframework/spring-core/3.2.2.RELEASE/spring-core-3.2.2.RELEASE.pom
  7. ………………………………………………………………………………


      首先通过Nexus下载,但服务已经关闭,这个时候仍然可以下载,而且通过*仓库进行下载。但在项目中,不允许本地仓库直接下载*仓库的依赖包,这个时候就需要进行对*仓库进行覆盖,使之只能通过Nexus访问*仓库,这个时候需要对镜像进行配置。

在settings.xml中配置镜像

首先配置镜像,使得只有通过Nexus才可以访问*仓库

  1. …………………………………………………………
  2. <mirror>
  3. <id>nexusMirror</id>
  4. <mirrorOf>*</mirrorOf>
  5. <name>Human Readable Name for this Mirror.</name>
  6. <url>http://localhost:8081/nexus/content/groups/public/</url>
  7. </mirror>
  8. …………………………………………………………


    这里的*号代表所有的仓库都是通过这个url地址访问,这个时候可以附加一段配置,原来的*仓库中snapshots版本的依赖包默认是不可以下载的,但可以通过以下配置进行修改

  1. ……………………………………
  2. </profiles>
  3. ……………………………………
  4. <profile>
  5. <id>centralProFile</id>
  6. <repositories>
  7. <repository>
  8. <id>central</id>
  9. <name>Central Repository</name>
  10. <!--由于配置过镜像,这个url不起作用-->
  11. <url>http://repo.maven.apache.org/maven2</url>
  12. <layout>default</layout>
  13. <snapshots>
  14. <!--覆盖*仓库中的false配置,可以从*仓库中下载snapshot版本-->
  15. <enabled>true</enabled>
  16. </snapshots>
  17. </repository>
  18. </repositories>
  19. </profile>
  20. </profiles>
  21. <activeProfiles>
  22. <!-- 激活上面的配置 -->
  23. <activeProfile>centralProFile</activeProfile>
  24. </activeProfiles>
  25. ……………………………………


    这样进行保存后,既可生效。
    注意:配置文件settings.xml中会默认有相应的mirror和profile的例子,但都是注释掉的,我们在进行以上的改动时候,可以进行对其复制粘贴后进行修改,这样不容易出错。
    验证:(此时没有打开nexus服务)

随便找个不存在的jar依赖文件进行测试,

  1. <dependency>
  2. <groupId>org.mortbay.jetty</groupId>
  3. <artifactId>jetty</artifactId>
  4. <version>6.1.26</version>
  5. </dependency>


跟刚才的步骤一样,但此时保存后,Eclipse控制台中的信息如下所示:

  1. 14-3-7 GMT+0800下午9:13:58: [INFO] Downloaded http://localhost:8081/nexus/content/groups/public/org/mortbay/jetty/jetty/6.1.25/jetty-6.1.25.pom
  2. 14-3-7 GMT+0800下午9:13:58: [INFO] Using org.eclipse.m2e.jdt.JarLifecycleMapping lifecycle mapping for MavenProject: com.steven.user:user-service:0.0.1-SNAPSHOT @ E:\Workspaces\STSWorkspace\user-service\pom.xml.
  3. 14-3-7 GMT+0800下午9:13:58: [INFO] Number of application's worked threads is 4
  4. 14-3-7 GMT+0800下午9:14:02: [INFO] Using 'UTF-8' encoding to copy filtered resources.
  5. 14-3-7 GMT+0800下午9:14:02: [INFO] skip non existing resourceDirectory E:\Workspaces\STSWorkspace\user-service\src\main\resources
  6. 14-3-7 GMT+0800下午9:14:02: [INFO] Using 'UTF-8' encoding to copy filtered resources.
  7. 14-3-7 GMT+0800下午9:14:02: [INFO] skip non existing resourceDirectory E:\Workspaces\STSWorkspace\user-service\src\test\resources


          这里只能通过Nexus下载依赖包,但是由于服务停止,所以下载失败,而如果此时将服务打开

一起学Maven
                     图19

然后在Eclipse中刷新依赖包所在的pom.xml文件,
    如果没有任何问题,则在控制台中显示如下信息:

  1. 14-3-8 GMT+0800上午12:00:31: [INFO] Downloading http://localhost:8081/nexus/content/groups/public/org/mortbay/jetty/jetty-util/6.1.26/jetty-util-6.1.26.jar
  2. 14-3-8 GMT+0800上午12:00:31: [INFO] Downloaded http://localhost:8081/nexus/content/groups/public/org/mortbay/jetty/jetty-util/6.1.26/jetty-util-6.1.26.jar


    但此时可能出现以下问题

  1. [ERROR] Could not calculate build plan: Plugin org.apache.maven.plugins:maven-resources-plugin:2.5 or one of its dependencies could not be resolved: Failed to read artifact descriptor for org.apache.maven.plugins:maven-resources-plugin:jar:2.5


    原因:这是因为在进行配置后,所有本地仓库的依赖包都将通过nexus私有仓库访问*仓库进行下载,而此时在加载一些Maven插件的时候,由于一开始本地仓库中已经存在,而私有仓库中没有这些依赖包的索引(就是指在nexus中存在对依赖包的GAV标识),这个时候就会容易报错。
    解决思路:
    思路1:
    一开始可以进行对索引更新,具体参照图20所示

一起学Maven                      图20

这样设置以后, Nexus会自动从远程*仓库下载索引文件,索引文件很大,需要很久等待时间。

思路2:

错误信息也有如下所示的提示:

  1. Could not calculate build plan: Failure to transfer org.apache.maven.plugins:maven-surefire-plugin:pom:2.7.1 from http://repo1.maven.org/maven2 was cached in the local repository, resolution will not be reattempted until the update interval of central has elapsed or updates are forced. Original error: Could not transfer artifact org.apache.maven.plugins:maven-surefire-plugin:pom:2.7.1 from/to central (http://repo1.maven.org/maven2): Access denied to http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-surefire-plugin/2.7.1/maven-surefire-plugin-2.7.1.pom.


    解决方案:
    1.找到maven库目录,进入:\repository\org\apache\maven\plugins\maven-surefire-plugin\2.7.1
    2.若2.7.1目录下只有,"maven-surefire-plugin-2.7.1.pom.lastUpdated" 则需要到http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-surefire-plugin/2.7.1/,把里面的文件下载下来放到2.7.1文件夹中
    3.删除2.7.1下的maven-surefire-plugin-2.7.1.pom.lastUpdated文件。
    4.项目右键-->maven-->Update Project即可。
    思路3:

首先关掉Eclipse,停止Nexus运行,然后将本地E:\Workspaces\Maven\repository中所有的依赖包删除,然后启动Nexus,打开Eclipse,这时候将通过Nexus进行下载依赖包到本地仓库中,一般情况可以解决问题,如果还有思路2中的错误信息,则执行思路2。

通过Maven部署项目到Nexus中

当项目已经编写完成,需要部署到Nexus中,这样团队人员可以通过Nexus下载到自己的本地仓库中,比如说,我是编写user-core的模块的,部署到Nexus中,需要以下两个步骤,

1、需要配置user-core的pom.xml文件,定义发布的版本以及发布到Nexus本地库的哪个仓库中,具体如下所示:

  1. ………………………………………………………………
  2. <distributionManagement>
  3. <repository>
  4. <id>user-core-release</id>
  5. <name>user core release</name>
  6. <url>http://localhost:8081/nexus/content/repositories/releases/</url>
  7. </repository>
  8. <snapshotRepository>
  9. <id>user-core-snapshot</id>
  10. <name>user core snapshot</name>
  11. <url>http://localhost:8081/nexus/content/repositories/snapshots/</url>
  12. </snapshotRepository>
  13. </distributionManagement>
  14. ………………………………………………………………



    2、配置本地settings.xml文件,让部署过程中有足够的权限,而Nexus中本来存在的有三个用户,如图21所示:

一起学Maven

图21

而部署使用deployment用户,具体的配置如下

  1. ………………………………………………………………
  2. <server>
  3. <id>user-core-release</id>
  4. <username>deployment</username>
  5. <password>deployment123</password>
  6. </server>
  7. <server>
  8. <id>user-core-snapshot</id>
  9. <username>deployment</username>
  10. <password>deployment123</password>
  11. </server>
  12. ………………………………………………………………



    完成以上两个步骤,此时进行部署(deploy)操作,如图22所示:

一起学Maven

图22

这个时候部署成功,然后我们可以在Nexus中看到部署后的结果,如图23所示

一起学Maven

图23

在Snapshots的索引中可以查看到刚刚部署的user-core模块。

通过Nexus搜索构件

首先我们来明确一下构件的含义,

构件:构件是系统中实际存在的可更换部分,它实现特定的功能,符合一套接口标准并实现一组接口,而在我们这里就是我们要使用的即将需找的依赖。

但在我们实际使用构件的过程中通常遇到一个问题,有时候我紧紧知道我所需要的构建的大致名字,并不知道全称或group id, 这是件非常头疼的事情. Nexus基于Nexus indexer(索引)的搜索功能帮我们解决了这个问题。

还记得刚才我们在解决Could not calculate build plan...问题的时候,给出的思路1,其思想就是,通过更改Download Remote Indexes的状态为True,使得Nexus从*仓库中将所有构件的信息同步到本地,这样在以后的开发中,就可以直接下载私有仓库中的依赖,就不需要Nexus还要去*仓库中下载了。下面就来领略Nexus搜索构件的方便之处。

如图所示:

一起学Maven

图24

这里有以下几种搜索方式:

keyword(关键字查询), classname(类名查询), GAV(groupId,artifactId,version组合查询), checksum(校验和查询),这里我认为前三种使用的最多。

比如,刚刚通过部署后的user-core模块,这个模块正好被其他项目人员使用到,他知道模块的名称叫user-core,这个时候,可以通过GAV的方式进行查询,如图所示:

一起学Maven

图25

查出来之后,只要将依赖文件复制到项目的pom.xml配置中,就可以从私有仓库中下载到其本地仓库进行使用了。

创建本地仓库并设置权限

创建仓库

在大公司的项目开发中,不可能所有的Snapshots和Releases版本都发布到Nexus中默认对应的Snapshots和Releases仓库中,我们可以给每个项目创建自己的本地仓库,并赋予相应的角色权限进行操作。比如创建一个UserRelease仓库用来存储User项目的Release版本,这个时候,操作如图所示:

一起学Maven

图26

接着将信息填入New Hosted Repository中,如图27所示

一起学Maven

图27

这个时候就创建了UserRelease的本地仓库,如图所示

一起学Maven

图28

创建权限

虽然我们已经创建了UserRelease仓库,但仓库的权限仅为预览,如果让其可以有增删改查的权限,只要点击图中Add,如图所示:

一起学Maven

图29

接着进行信息填入,如图30所示

一起学Maven

图30

这个时候UserRelease仓库就拥有了所有的权限,如图31所示

一起学Maven

图31

创建角色

虽然有了权限,但在使用的过程中,进一步创建一个角色,对角色添加相应的权限,然后在让角色中添加相应的用户,这样在发布的时候就可以达到权限的最细致化,管理起来更加方面。

如图32,创建角色

一起学Maven

图32

然后进行填写信息,如图33

一起学Maven

图33

在这里有Add按钮,点击按钮的时候进行如下操作

一起学Maven

图34

此时,创建角色后如图35所示:

一起学Maven

图35

创建用户

角色创建好后就可以创建用户,通过专有的用户来进行专有项目的部署和其他操作,如图创建用户

一起学Maven

图36

然后填入信息,如图所示

一起学Maven

图37

在图37中点击Add按钮出现图38所示的选项,如下操作

一起学Maven

图38

就是选择该用户所属的角色,而角色拥有所有的权限,完成后如图39所示

一起学Maven

图39

注:在以上操作中,我们首先创建一个本地仓库(这里是Release版本的,项目中可以在创建一个Snapshot版本,操作过程同上),然后给这个仓库赋予权限,然后将这些权限通过一个角色进行拥有,当然在这里可以创建不同的角色赋予不同的权限,这时候,创建一个用户,使得该用户担当一个角色,这样的话,这个用户就可以拥有这个角色中的权限,下面就可以按需对所在的项目使用相应的用户进行操作了。

这样根据以上情况可以建立UserSnapshot的仓库,以及将所有的权限付给不同的角色,或者可以让UserReleaseRole同样拥有UserSnapshot的所有权限,并且同样的用户拥有Release和Snapshot仓库的所有权限,这样的话如果进行部署,就可以如下进行配置,在对应部署模块的pom.xml中可以这样配置

  1. ………………………………………………………………
  2. <distributionManagement>
  3. <repository>
  4. <id>user-core-release</id>
  5. <name>user core release</name>
  6. <url>http://localhost:8081/nexus/content/repositories/UserRelease/</url>
  7. </repository>
  8. <snapshotRepository>
  9. <id>user-core-snapshot</id>
  10. <name>user core snapshot</name>
  11. <url>http://localhost:8081/nexus/content/repositories/UserSnapshots/</url>
  12. </snapshotRepository>
  13. </distributionManagement>
  14. ………………………………………………………………



    而在settings.xml中就可以这样进行配置

  1. ………………………………………………………………
  2. <server>
  3. <id>user-core-release</id>
  4. <username>UserRelease</username>
  5. <password>user123</password>
  6. </server>
  7. <server>
  8. <id>user-core-snapshot</id>
  9. <username>UserRelease</username>
  10. <password>user123</password>
  11. </server>
  12. ………………………………………………………………



    这样就可以把相应的Release和Snapshot版本部署到相应的Nexus仓库中了。

总结

本章节通过对仓库管理器Nexus的讲解,包括如何下载安装Nexus,配置Nexus代理*仓库,管理Nexus的代理仓库,本地仓库,以及仓库组。并帮助你了解如何通过Nexus搜索构件。最后,如何在Maven中配置Nexus仓库,以及如何部署构件到Nexus仓库中。同时,根据大公司的要求,创建了专有的仓库,并且学习了如何进行用户管理,角色权限管理等等。

如有什么疑问或者建议意见都可以提出,本人在此不胜感激,同时,同样恭祝大家学习愉快!

七. Maven中的生命周期与插件机制

Maven的生命周期

就像人生一样,出生,成长,死亡,这个每个人乃至整个生命都拥有的特性。Maven的构造者就发现,整个项目的构建过程都拥有高度的相似性,清理、初 始化、编译、测试、打包、集成测试、验证、部署、站点发布等等,于是,Maven就在这些过程中抽象出三套执行机制,也就是独立的三种生命周期,分别是

  • Clean Lifecycle 项目的构建之前进行清理操作
  • Compile(Default) Lifecycle 主要进行项目构建的操作,编译测试打包部署等核心操作
  • Site Lifecycle 项目报告的生成,站点发布操作
完整生命周期(供参考)

1.Clean 
  pre-clean 执行一些清理前需要完成的工作。
  clean 清理上一次构建生成的文件
  post-clean 执行一些清理后需要完成的工作
2.Compile(Default) 
  validate 验证项目是正确的并且所有必需的信息都是可用的
  initialize 初始化构建状态
  generate-sources 产生所有的用来编译的源代码
  process-sources 处理源代码
  generate-resources 产生包含在package中的资源
  process-resources 复制和处理资源到目标目录,为打包做好准备
  compile 编译项目的主源代码
  process-classes 对编译器产生的文件进行后期处理
  generate-test-sources 产生所有用来编译的测试源代码
  process-test-sources 处理测试源代码
  generate-test-resources 创建测试所需要的资源
  process-test-resources 复制和处理资源到测试目标目录
  compile 编译测试源代码到目标目录
  process-test-classes 对编译测试源代码产生的文件进行后期处理
  test 使用适当的单元测试框架运行测试,这些测试代码不应该被打包或者部署
  prepare-package 执行所有需要执行的操作为打包做准备,这往往会产生一个还未打包的处理过的包版本
  package 使用设置的方式对编译过的文件进行打包
  pre-integration-test 执行一些集成测试执行前必须的操作
   integration-test 处理和部署包到集成测试环境中,进行测试
  post-integration-test 对集成测试进行后期处理
   verify 执行所有检查确保包是正确的和符合质量要求的
  install 将包安装至本地仓库,以让其它项目依赖
    deploy 将最终的包复制到远程的仓库,以让其它开发人员与项目共享
3.Site 
  pre-site 前期准备
  site 产生项目的站点文档
  post-site 后期处理
  site-deploy 部署站点到服务器

插件机制

虽然Maven生命周期中有这么多个执行过程,但这些都是一个抽象的概念,这个概念性的东西意味着它并不做任何实质性的事情,也就是说:它就像接口,只定
义规范,具体细节它不管。具体的 实现细节则交给了Maven
的各个丰富的插件,也就是说Maven的插件是要完全依赖于Maven的生命周期的,根据周期中的这些执行过程,才可以定义出相应功能的插件。

因此Maven的生命周期和Maven插件是相辅相成的,只有周期,没有插件,Maven是没有法子执行相应的操作,只有插件,没有周期,插件将失去了意义,在这里,可以很好的赞叹Maven的开发者多么智慧的头脑,以及多好的设计原则。

(待修改...)

上一篇:C#获取并修改文件扩展名的方法


下一篇:10分钟教你用Python打造微信天气预报机器人