Maven详细介绍

时间:2022-07-24
本文章向大家介绍Maven详细介绍,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Maven

什么是Maven?

如何回答这个问题要看你怎么看这个问题。 绝大部分Maven用户都称Maven是一个"构建工具":一个用来把源代码构建成可发布的构件的工具。 构建工程师和项目经理会说 Maven是一个更复杂的东西:一个项目管理工具。那么区别是什么? 像Ant这样的构建 工具仅仅是关注预处理,编译,打包,测试和分发。像 Maven 这样的一个项目管理工 具提供了构建工具所提供功能的超集。 除了提供构建的功能,Maven还可以生成报告, 生成Web站点,并且帮助推动工作团 队成员间的交流。一个更正式的 Apache Maven 1 的定义: Maven是一个项目管理工具,它包含了一个项目对象模型 (Project Object Model),一组标准集合,一个项目生命周期(ProjectLifecycle),一个依赖管理系统(Dependency Management System),和用来运行定义在生命周期阶段(phase)中插件(plugin)目标(goal)的逻辑。 当你使用Maven的时候,你用一个明确定义的项目对象模型来描述你的项目,然后 Maven 可以应用横切的逻辑,这些逻辑来自一组共享的(或者自定义的)插件。别让Maven是一个"项目管理"工具的事实吓跑你。如果你只是在找一个构建工具,Maven能做这个工作。 事实上,本书的一些章节将会涉及使用Maven来构建和分发你的项目。

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所示:

如果想查看源码可以下载src版本,当然也可以选择其他操作系统,比如linux平台下的文件,本系列只介绍windows平台下,其他平台还请参照其他博文讲解。 找到下载后的文件,并将文件解压到一个自己定义的目录,如图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所示:

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

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

设置本地仓库

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

其中repository目录,这个目录是存放从网上下载下来的jar,而这些jar就是maven的好处之一,可以自动下载项目中用到的jar包,而这些jar包的存放位置就是一个仓库,存放在本地的就是本地仓库,而存放在网络上的就是maven的中央仓库。 由于下载jar文件的增多,会给C盘造成负担,或者在重装系统后,c盘的东西将不复存在,因此可以把repository目录转移到其他盘中储存。

具体做法是:

A. 复制repository目录到其它盘符,本文中是在E:WorkspacesMaven下

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

C. 打开找到如下内容 <localRepository>....</localRepository>改成:

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

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

保存.完成. 这样就将本地仓库从C:UsersSteven.m2repository移到了E:WorkspacesMavenrepository中。

创建简单的Maven实例

使用骨架创建maven项目

使用默认的骨架创建项目

使用 mvn archetype:generate创建maven骨架

如图,创建一个Maven项目

这样会生成两个目录:
   C:UsersAdministratoraaTestsrcmainjavacomaayongcheaaTet目录,这是一个正式代码目录
   C:UsersAdministratoraaTestsrctestjavacomaayongcheaaTet,这是一个测试代码目录。
   这是一个简单的Maven项目,使用其他骨架可以生成适合我们开发的目录结构。

骨架介绍

骨架:是Maven 内置的骨架插件,他可以给我们生成符合开发的目录结构,不用我们自己定义目录。 1: internal -> appfuse-basic-jsf (创建一个基于Hibernate,Spring和JSF的Web应用程序的原型) 2: internal -> appfuse-basic-spring (创建一个基于Hibernate,Spring和Spring MVC的Web应用程序的原型) 3: internal -> appfuse-basic-struts (创建一个基于Hibernate,Spring和Struts 2的Web应用程序的原型) 4: internal -> appfuse-basic-tapestry (创建一个基于Hibernate, Spring 和 Tapestry 4的Web应用程序的原型) 5: internal -> appfuse-core (创建一个基于 Hibernate and Spring 和 XFire的jar应用程序的原型) 6: internal -> appfuse-modular-jsf (创建一个基于 Hibernate,Spring和JSF的模块化应用原型) 7: internal -> appfuse-modular-spring (创建一个基于 Hibernate, Spring 和 Spring MVC 的模块化应用原型) 8: internal -> appfuse-modular-struts (创建一个基于 Hibernate, Spring 和 Struts 2 的模块化应用原型) 9: internal -> appfuse-modular-tapestry (创建一个基于 Hibernate, Spring 和 Tapestry 4 的模块化应用原型) 10: internal -> maven-archetype-j2ee-simple (一个简单的J2EE的Java应用程序) 11: internal -> maven-archetype-marmalade-mojo (一个Maven的 插件开发项目 using marmalade) 12: internal -> maven-archetype-mojo (一个Maven的Java插件开发项目) 13: internal -> maven-archetype-portlet (一个简单的portlet应用程序) 14: internal -> maven-archetype-profiles () 15: internal -> maven-archetype-quickstart () 16: internal -> maven-archetype-site-simple (简单的网站生成项目) 17: internal -> maven-archetype-site (更复杂的网站项目) 18: internal -> maven-archetype-webapp (一个简单的Java Web应用程序) 19: internal -> jini-service-archetype (Archetype for Jini service project creation) 20: internal -> softeu-archetype-seam (JSF+Facelets+Seam Archetype) 21: internal -> softeu-archetype-seam-simple (JSF+Facelets+Seam (无残留) 原型) 22: internal -> softeu-archetype-jsf (JSF+Facelets 原型) 23: internal -> jpa-maven-archetype (JPA 应用程序) 24: internal -> spring-osgi-bundle-archetype (Spring-OSGi 原型) 25: internal -> confluence-plugin-archetype (Atlassian 聚合插件原型) 26: internal -> jira-plugin-archetype (Atlassian JIRA 插件原型) 27: internal -> maven-archetype-har (Hibernate 存档) 28: internal -> maven-archetype-sar (JBoss 服务存档) 29: internal -> wicket-archetype-quickstart (一个简单的Apache Wicket的项目) 30: internal -> scala-archetype-simple (一个简单的scala的项目) 31: internal -> lift-archetype-blank (一个 blank/empty liftweb 项目) 32: internal -> lift-archetype-basic (基本(liftweb)项目) 33: internal -> cocoon-22-archetype-block-plain ([ http://cocoapacorg2/maven-plugins/ ]) 34: internal -> cocoon-22-archetype-block ([ http://cocoapacorg2/maven-plugins/ ]) 35: internal -> cocoon-22-archetype-webapp ([ http://cocoapacorg2/maven-plugins/ ]) 36: internal -> myfaces-archetype-helloworld (使用MyFaces的一个简单的原型) 37: internal -> myfaces-archetype-helloworld-facelets (一个使用MyFaces和Facelets的简单原型) 38: internal -> myfaces-archetype-trinidad (一个使用MyFaces和Trinidad的简单原型) 39: internal -> myfaces-archetype-jsfcomponents (一种使用MyFaces创建定制JSF组件的简单的原型) 40: internal -> gmaven-archetype-basic (Groovy的基本原型) 41: internal -> gmaven-archetype-mojo (Groovy mojo 原型)

创建其他骨架语法

A、在命令窗口中输入mvn archetype:generate如下图:

B、回车执行之后出现会看到一段长长的输出,有很多可用的archetype供我们选择,每一个archetype前面都会对应有一个编号,同时命令行会提示一个默认的编号,如下图,其对应的archetype为maven-archetype-quickstart,我们直接回车以选择该archetype:

C、然后Maven会提示我们输入要创建项目的groupId、artifactId、version、以及包名package,按照下图所示填写。最后出现确认提示,输入Y。看到BUILD SUCCESS表示成功完成mvn project的构建。

自己编写Maven格式的项目

本文在目录E:/Workspaces/STSWorkspace/Maven_01(可以随便找个目录)下,新建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.steven.maven</groupId>   
   <artifactId>maven_01</artifactId>  
   <version>0.0.1-SNAPSHOT</version>
</project>

其中

  第一行是xml的头,定义了xml文档的版本和编码。
  紧接着是project元素,该元素是所有元素的根节点,声明了一些POM相关的命令空间及xsd元素。
  根元素的下一个元素是modelVersion 指定了当前POM 模型的版本,对于Maven2和Maven3来说,都是4.0
  groupId:项目或者组织的唯一标志,并且配置时生成路径也是由此生成,如com.steven.maven生成的相对路径为:/com/steven/maven 
  artifactId:项目的通用名称 
  version:项目的版本  eg:x.x.x-里程碑号(SNAPSHOT->ALPHA->BETA->RELEASE)

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

HelloWorld.java的内容如下:

	package com.steven.maven;  	  
	public class HelloWorld{  
	    public void sayHello(){  
	        System.out.println("Hello Maven!");  
	    }  
	}

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

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

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

发现刚刚编译产生的class文件放在了target目录下,所以只要我们按照这个目录格式编写,maven工具就帮助我们执行出结果,然后放在相应的结构目录下。 下面我们将继续编写测试代码,在test目录下新建java文件夹,然后同样新建com/steven/maven/HelloWorldTest.java文件,其中HelloWorldTest文件的内容如下:

        package com.steven.maven;  
	import org.junit.*;  
	public class HelloWorldTest{  
	    @Test  
	    public void sayHelloTest(){  
	        HelloWorld hw = new HelloWorld();  
	        hw.sayHello();  
	    }  
	}

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

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

这是因为测试过程中用到了junit的包,但没有找到,原来的解决办法是: 通过将junit的包加入到环境变量下即可解决 但maven的解决思路是:在pom.xml中加入<dependencies>节点,完成的配置文件如下所示:

  <?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.steven.maven</groupId>  
     <artifactId>maven_01</artifactId>  
     <version>0.0.1-SNAPSHOT</version>  	  
     <dependencies>  
      <dependency>  
	<groupId>junit</groupId>  
	<artifactId>junit</artifactId>  
	<version>4.10</version>  
      </dependency>  
     </dependencies>  
    </project>

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

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

此时发现测试成功,正确执行Hello Maven!的结果。 此时再来看target中的文件会发现如图15所示的结果:

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

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

发现target目录已经不存在了,即被maven clean命令清空了。如果接着执行maven test,会发现target目录又出现了。 这个时候再来观察一下一开始配置的本地仓库中的文件,会发现图18的结果:

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

总结: 在本节中,通过Maven的介绍,下载,安装,配置,以及小案例的实现,估计大家也多多少少有些头绪了,通过案例,可以看出Maven可以作为项目的构建工具,而配置文件很好写,而且写的很少,用到的jar包,不需要手动去添加到环境变量中, 只要通过配置,Maven就会通过网络寻找到并且下载到本地仓库中。 在本节中用到的Maven命令: mvn compile编译java文件 mvn test执行junit操作 mvn clean清空target目录操作

使用IDEA 创建Maven项目

(1)点击settings ,如下图设计maven为本地自己的Maven,不要使用编译器自带的Maven插件。

(2)依次点击File 、new 、Maven,选择适合自己的骨架, 如下图:

(3)填写GroupId、ArtifactId、version,如下图:

(4)查看并关联自己的Maven配置,如下图:

(5)填写自己的项目名

(6)产生的目录结构

(7)主要使用IDEA右侧的Maven操作列表

依赖管理

项目构建

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

依赖的定义和好处

有人认为Maven是一个依赖管理工具,当然这种想法是错误的(确切的说Maven是一个项目管理工具,贯穿了整个项目生命周期,编译,测试,打包,发布...),但Maven给人造成这种错误的印象也是有原因的,因为Maven的依赖管理十分强大,用好了Maven,你不再需要面对一大堆jar感到头大,依赖冲突,无用依赖等问题也能够得到有效的防止和解决。本节介绍如何用好Maven的依赖管理。 取自:http://juvenshun.iteye.com/blog/337405

依赖用法

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

<span style="font-family:KaiTi_GB2312;font-size:18px;">
<dependency>  
   <groupId>junit</groupId>  
   <artifactId>junit</artifactId>  
   <version>4.10</version>  
</dependency>
</span>

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

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

依赖传递

创建user-core

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

通过此模块的构建,主要说明Maven的一下几个问题: A、目录结构的默认构建,比如资源文件的src/main/resources目录的构建 B、pom.xml文件的使用到的jar包的引入,比如在user-core中的文件内容如下所示:

通过资源库中查找到相应的jar包,放到pom.xml中之后,IDEA就会自动会和本地资源库或者远程仓库中进行匹配,如果本地中没有,就会通过网络下载从远程仓库中下载到本地仓库中。 C、进行Maven项目模块的打包和加入到本地资源库的命令,如图所示:

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

接着引入user-log,user-service

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

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

此时细心的读者会发现在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包。

在IDEA 中查看依赖关系

如图,点击视图按钮,查看依赖关系。

依赖的难点

(1)依赖级别不相同时:

 A--->l1.0
 B--->l2.0
 c---->A,B
 在C的POM中,谁先声明依赖谁

(2)依赖级别相同时:

  依赖层级最短的那个。

排除依赖

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

依赖的范围

A. 好处

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

B.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及以上): 导入依赖范围。

聚合和继承

聚合

把同一个项目中的很多模块,使用一个外部的pom文件统一管理,简化每次都要分别编译不同模块的。

继承

多模块开发时,写一个公共的父类,把各个模块的配置写入这个POM文件中,这时子类只需要引入自己所需的配置即可。 父类写法:

子类的写法:

Maven 生命周期

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

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

完整生命周期(供参考)

A.Clean

 pre-clean 执行一些清理前需要完成的工作。
 
 clean 清理上一次构建生成的文件
 
 post-clean 执行一些清理后需要完成的工作

B.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 将最终的包复制到远程的仓库,以让其它开发人员与项目共享

C.Site

 pre-site 前期准备
 site 产生项目的站点文档
 post-site 后期处理
 site-deploy 部署站点到服务器

插件机制

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

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

Nexus

Nexus 简介

前边简单介绍了Maven,而Maven默认提供的中央仓库是在远程网络服务Appache提供的,这对于我们开发时不合理的。如果我们没网了或者什么情况,我们怎么办?也就是说我们队中央仓库的依赖性太大。而Nexus私服则可以解决我们这个问题。先看下这张图应该大家就非才明白了:

这样就相当于在我们本地的局域网搭建了一个类似中央仓库的服务器,我们开始将中央仓库的一些资料下载到私服务器上,然后平时我们的maven项目就是直接访问局域网内的私服即可,既节省了网络带宽也会加速项目搭建的进程,这样对我们开发来说,对公司来说都是非常好的选择。

Nexus 下载安装

下载

下载地址:http://www.sonatype.org/nexus/go

Nexus 启动

我下载的是zip包,解压后进入nexus-2.1.2-bundlenexus-2.1.2binjsw,根据操作系统类型选择文件夹,我选的是windows-x86-32文件夹,进入后可看到如下所示bat文件。

双击console-nexus.bat运行。游览器中输入http://127.0.0.1:8081/nexus/,出现如下图所示就代表nexus已经启动成功。

8081为默认的端口号,要修改端口号可进入nexus-2.1.2-bundlenexus-2.1.2conf打开nexus.properties文件,修改application-port属性值就可以了。

默认的用户名和密码:admin/admin123,登录后看到如下图所示:

Nexus 仓库介绍

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

在这里:

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

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

会发现,在Ordered Group Repositories中,有所有hosted和proxy的仓库,而图15中箭头所指的地方有四种类型的仓库,分别是Releases(hosted), Snapshots(hosted), 3rd Party(hosted),Central(proxy),而Central指的是中央仓库,存在于apache-maven-3.1.1libmaven-model-builder-3.1.1.jar中的orgapachemavenmodelpom-4.0.0.xml文件中,定义了中央仓库的位置,配置文件如下所示。

  	<repositories>  
	<repository>  
	  <id>central</id>  
	  <name>Central Repository</name>  
	  <url>http://repo.maven.apache.org/maven2</url>  
	  <layout>default</layout>  
	  <snapshots>  
	    <enabled>false</enabled>  
	  </snapshots>  
	</repository>  
	</repositories>

其中url指向了中央仓库的位置http://repo.maven.apache.org/maven2,而Releases, Snapshots, 3rd Party,主要功能如下:

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

Nexus 仓库配置

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

	 <profiles>  
	   <profile>  
	    <id>nexusProFile</id>  
	    <repositories>  
	      <repository>  
	        <id>localNexus</id>  
	    <name>Nexus Repository</name>  
	        <url>http://localhost:8081/nexus/content/groups/public/</url>  
	        <releases>  
	          <enabled>true</enabled>  
	        </releases>  
	        <snapshots>  
	      <!-- 此选项默认是关闭的,手动打开 -->  
	          <enabled>true</enabled>  
	        </snapshots>  
	      </repository>  
	     </repositories>  
	   </profile>  
	  </profiles>  
	  <activeProfiles>  
	    <!-- 激活上面的配置 -->  
	    <activeProfile>nexusProFile</activeProfile>  
	  </activeProfiles>

Maven中的profile是一组可选的配置,可以用来设置或者覆盖配置默认值。有了profile,你就可以为不同的环境定制构建。

这个时候,做个试验,可以在user-core的pom.xml中加入以下依赖(这个依赖包并不存在于本地或者Nexus仓库中)

<dependency>  
  <groupId>org.mybatis</groupId>  
  <artifactId>mybatis</artifactId>  
   <version>3.1.1</version>  
</dependency>

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

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

这也验证了Nexus已经将mybatis的依赖包下载到了仓库中。

Nexus 配置镜像

A. 但此时会有个问题,如果将Nexus服务停止。这个时候在user-core的pom.xml中添加原来没有的依赖配置文件(可以随便找个不存在的jar依赖文件进行测试,这里用使用Spring)

<dependency>  
   <groupId>org.springframework</groupId>  
   <artifactId>spring-core</artifactId>  
   <version>3.2.2.RELEASE</version>  
</dependency>

点击保存,会发现如下的信息

 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:WorkspacesSTSWorkspaceuser-corepom.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  

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

B. 在settings.xml中配置镜像 首先配置镜像,使得只有通过Nexus才可以访问中央仓库

	<mirror>  
	  <id>nexusMirror</id>  
	  <mirrorOf>*</mirrorOf>  
	  <name>Human Readable Name for this Mirror.</name>  
	  <url>http://localhost:8081/nexus/content/groups/public/</url>  
	</mirror>

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

	</profiles>  
	 <profile>  
	   <id>centralProFile</id>  
	   <repositories>  
	     <repository>  
	    <id>central</id>  
	    <name>Central Repository</name>  
	    <!--由于配置过镜像,这个url不起作用-->  
	    <url>http://repo.maven.apache.org/maven2</url>  
	    <layout>default</layout>  
	    <snapshots>  
	      <!--覆盖中央仓库中的false配置,可以从中央仓库中下载snapshot版本-->  
	      <enabled>true</enabled>  
	    </snapshots>  
	  </repository>  
	    </repositories>  
	  </profile>  
 
	 </profiles>  
	 <activeProfiles>  
	   <!-- 激活上面的配置 -->  
	   <activeProfile>centralProFile</activeProfile>  
	 </activeProfiles>

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

C.验证:(此时没有打开nexus服务) 随便找个不存在的jar依赖文件进行测试,

	<dependency>  
	    <groupId>org.mortbay.jetty</groupId>  
	    <artifactId>jetty</artifactId>  
	    <version>6.1.26</version>  
	</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:WorkspacesSTSWorkspaceuser-servicepom.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:WorkspacesSTSWorkspaceuser-servicesrcmainresources  
 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:WorkspacesSTSWorkspaceuser-servicesrctestresources  

这里只能通过Nexus下载依赖包,但是由于服务停止,所以下载失败。

通过Maven 部署项目到Nexus

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

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

       <distributionManagement>  
	    <repository>  
	        <id>user-core-release</id>  
	        <name>user core release</name>  
	        <url>http://localhost:8081/nexus/content/repositories/releases/</url>  
	    </repository>  
	    <snapshotRepository>  
	        <id>user-core-snapshot</id>  
	        <name>user core snapshot</name>  
	        <url>http://localhost:8081/nexus/content/repositories/snapshots/</url>  
	    </snapshotRepository>  
	</distributionManagement>

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

而部署使用deployment用户,在settings.xml具体的配置如下:

	<server>  
	      <id>user-core-release</id>  
	      <username>deployment</username>  
	      <password>deployment123</password>  
	</server>  
	<server>  
	      <id>user-core-snapshot</id>  
	      <username>deployment</username>  
	      <password>deployment123</password>  
	</server>

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

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

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

通过Nexus搜索构件

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

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

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

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

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

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

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

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

创建本地仓库并设置权限

创建仓库

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

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

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

创建权限

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

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

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

创建角色

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

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

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

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

创建用户

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

然后填入信息,如图所示

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

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

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

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

	<distributionManagement>  
	    <repository>  
	        <id>user-core-release</id>  
	        <name>user core release</name>  
	        <url>http://localhost:8081/nexus/content/repositories/UserRelease/</url>  
	    </repository>  
	    <snapshotRepository>  
	        <id>user-core-snapshot</id>  
	        <name>user core snapshot</name>  
	        <url>http://localhost:8081/nexus/content/repositories/UserSnapshots/</url>  
	    </snapshotRepository>  
	</distributionManagement>

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

	<server>  
	      <id>user-core-release</id>  
	      <username>UserRelease</username>  
	      <password>user123</password>  
	</server>  
	<server>  
	      <id>user-core-snapshot</id>  
	      <username>UserRelease</username>  
	      <password>user123</password>  
	</server>

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