转载自: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所示:
图1
如果想查看源码可以下载src版本,当然也可以选择其他操作系统,比如linux平台下的文件,本系列只介绍windows平台下,其他平台还请参照其他博文讲解。
找到下载后的文件,并将文件解压到一个自己定义的目录,如图2所示:
图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所示:
图3
下面将查看配置是否正确,打开命令控制台,输入mvn -v如果发现图4所示的信息,配置就是成功的:
图4
至此,Maven的环境变量配置成功。
本地仓库
由于运行过mvn命令,那么会在用户目录下发现一个.m2文件,如图5所示:
图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所示:
图6
保存.完成.
这样就将本地仓库从C:\Users\Steven\.m2\repository移到了E:\Workspaces\Maven\repository中。
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>
其中
groupId:
项目或者组织的唯一标志,并且配置时生成路径也是由此生成,如com.steven.maven生成的相对路径为:/com/steven/maven
artifactId:
项目的通用名称
version:
项目的版本
接下来在此文件夹中建立src文件夹,然后在src中建立main和test文件夹,然后在main中建立java文件夹,然后在java文件夹中建立com/steven/maven/HelloWorld.java文件,如图7所示:
图7
HelloWorld.java的内容如下:
- package com.steven.maven;
- public class HelloWorld{
- public void sayHello(){
- System.out.println("Hello Maven!");
- }
- }
然后在命令控制台中执行mvn compile,如图8所示:
图8
会发现出现Downloading下载的提示,这是因为,Maven在执行命令的时候,要加载其他使用到的插件和其他jar包,称为依赖,这个时候就要从
网络上进行下载,所以如何使用Maven,请保持网络是正常的,否则会出现问题。当编译完成的时候出现成功的提示信息,如图9所示:
图9
此时发现项目目录中多了一个target的目录,如图10所示:
图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所示:
图11
然后控制台执行mvn test命令,但此时出现错误信息,如图12所示:
图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所示的结果:
图13
这时候maven从网络上下载4.10版本的junit jar包,最后的执行结果如图14所示:
图14
此时发现测试成功,正确执行Hello Maven!的结果。
此时再来看target中的文件会发现如图15所示的结果:
图15
如果此时执行mvn clean命令,如图16所示:
图16
会发现在下载相应插件的同时,执行了清除target目录的操作,然后再来看Maven_01目录中的文件,如图17所示:
图17
发现target目录已经不存在了,即被maven clean命令清空了。如果接着执行maven test,会发现target目录又出现了。
这个时候再来观察一下一开始配置的本地仓库中的文件,会发现图18的结果:
图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所 示:
图1
打开链接http://search.maven.org/#browse,就可以看到如图2所示的*工厂的网页,
图2
在这个文本框中可以输入要寻找的jar包,比如log4j,找到一个1.2.17版本进入后,就可以看到如图2所示的页面:
图3
将红色区域复制后可以加到pom.xml中,Maven就可以将需要的jar文件下载到本地仓库了。
二:
在上节中,我们发现Maven的项目是按照一定的架构来编写的,目录结构都是固定的,也就是如果想使用Maven所带来的功能,就要遵守Maven所定义的规则,约定好了,配置就会减少,从而方便开发。
在这里,将介绍Maven中mvn archetype:generate命令,来建立一个项目。
比如在E:\Workspaces\STSWorkspace下建立Maven_02的项目,首先在控制台输入mvn archetype:generate命令,会发现Maven开始下载命令中需要的插件和jar文件了,如图4所示:
图4
然后等到下载一段时间后停止到如图5所示:
图5
然后回车就可以,出现选择版本,选择最新版本即可,如图6所示:
图6
然后选6后回车,然后填写groupId, artifactId,version,package(敲回车默认包),如图7所示:
图7
此时查看E:\Workspaces\STSWorkspace目录,会发现Maven_02项目已经成功构建了,如图8所示:
图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所示:
图9
然后打开后,做下面的操作,进行配置Maven
首先选择Window->Preference找到左边侧边栏Maven选项,
然后根据图示进行配置,选择本地解压后的Maven目录,点击确定,如图10所示:
图10
然后选择本地仓库的位置,并完成配置,如图11,12所示:
图11
图12
这样的话,Eclipse中就已经正确配置Maven了。接下来就可以使用Eclipse构建Maven项目:
新建New->Other->Maven->Maven Project,如图13所示:
图13
点击Next,默认Workspace,Next,然后选择quickstart模式,如图14所示:
图14
点击Next,填入信息,如图15所示:
图15
比如建议一个用户管理项目,填写以上的信息,然后点击Finish,完成项目的创建,此时如图16所示:
图16
此时通过Eclipse构建的Maven项目已经成功了,如果想进行测试,可以通过如图17所示的方法进行测试:
图17
测试结果可以通过控制台查看:
- [INFO] Scanning for projects...
- [INFO]
- [INFO] ------------------------------------------------------------------------
- [INFO] Building user-core 0.0.1-SNAPSHOT
- [INFO] ------------------------------------------------------------------------
- [INFO]
- [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ user-core ---
- [INFO] Using 'UTF-8' encoding to copy filtered resources.
- [INFO] skip non existing resourceDirectory E:\Workspaces\STSWorkspace\user-core\src\main\resources
- [INFO]
- [INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ user-core ---
- [INFO] Nothing to compile - all classes are up to date
- [INFO]
- [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ user-core ---
- [INFO] Using 'UTF-8' encoding to copy filtered resources.
- [INFO] skip non existing resourceDirectory E:\Workspaces\STSWorkspace\user-core\src\test\resources
- [INFO]
- [INFO] --- maven-compiler-plugin:2.5.1:testCompile (default-testCompile) @ user-core ---
- [INFO] Nothing to compile - all classes are up to date
- [INFO]
- [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ user-core ---
- [INFO] Surefire report directory: E:\Workspaces\STSWorkspace\user-core\target\surefire-reports
- -------------------------------------------------------
- T E S T S
- -------------------------------------------------------
- Running com.steven.entity.AppTest
- Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.044 sec
- Results :
- Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
- [INFO] ------------------------------------------------------------------------
- [INFO] BUILD SUCCESS
- [INFO] ------------------------------------------------------------------------
- [INFO] Total time: 8.959s
- [INFO] Finished at: Sat Jan 18 23:47:29 CST 2014
- [INFO] Final Memory: 6M/15M
- [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,比如在本文的第一章节的如下配置:
- <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文件)
图1
图2
图3
此配置声明了一个对junit的依赖,它的groupId是junit, artifactId是junit,
version是4.10。这一组GAV构成了一个Maven坐标,基于此,Maven就能在本地或者远程仓库中找到对应的junit-4.10.jar
文件。
传递依赖
一:
首先紧跟第二章节的新建项目构建出如下图所示的结构图,
图4
通过此模块的构建,主要说明Maven的一下几个问题
1、目录结构的默认构建,比如资源文件的src/main/resources目录的构建
2、pom.xml文件的使用到的jar包的引入,比如在user-core中的文件内容如下所示:
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.steven.user</groupId>
- <artifactId>user-core</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <packaging>jar</packaging>
- <name>user-core</name>
- <url>http://maven.apache.org</url>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.10</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.14</version>
- </dependency>
- <dependency>
- <groupId>org.hibernate</groupId>
- <artifactId>hibernate-core</artifactId>
- <version>4.1.1.Final</version>
- </dependency>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>5.1.8</version>
- </dependency>
- </dependencies>
- </project>
通过资源库中查找到相应的jar包,放到pom.xml中之后,Eclipse就会自动会和本地资源库或者远程仓库中进行匹配,如果本地中没有,就会通过网络下载从远程仓库中下载到本地仓库中。
3、进行Maven项目模块的打包和加入到本地资源库的命令,如图所示
图5
这样就可以执行打包或者将打包后的jar添加到本地仓库中。
二:
接着引入user-log,user-service
图6 图7
其中user-log的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/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.steven.user</groupId>
- <artifactId>user-log</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <packaging>jar</packaging>
- <name>user-log</name>
- <url>http://maven.apache.org</url>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.10</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>dom4j</groupId>
- <artifactId>dom4j</artifactId>
- <version>1.5</version>
- </dependency>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.4</version>
- </dependency>
- </dependencies>
- </project>
其中user-service的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/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.steven.user</groupId>
- <artifactId>user-service</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <packaging>jar</packaging>
- <name>user-service</name>
- <url>http://maven.apache.org</url>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.10</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>user-log</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>user-core</artifactId>
- <version>${project.version}</version>
- </dependency>
- </dependencies>
- </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图,如图所示:
图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所示
图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中这样编写即可:
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>user-log</artifactId>
- <version>${project.version}</version>
- <exclusions>
- <exclusion>
- <groupId>dom4j</groupId>
- <artifactId>dom4j</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
此时在查看user-service的pom的dependency hierarchy图,发现已经成功使用dom4j1.6.1版本了,如图所示
图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文件中定义相应的操作即可,如下图所示
图1
但在这里我们可以通过Eclipse构建pom.xml文件(可以同时进行聚合和继承的操作),可以通过以下步骤
图2
图3
图4
然后生成pom.xml文件
图5
此时聚合的实现,只要在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/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.steven.user</groupId>
- <artifactId>user-parent</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <packaging>pom</packaging>
- <modules>
- <module>../user-core</module>
- <module>../user-log</module>
- <module>../user-service</module>
- </modules>
- </project>
注意:
这里的<module>模块中../是指代上一级目录,因为在Eclipse中需要指向上一级才可以引入相应的模块。
这时候,对parent模块执行clean操作,会发现其包含的每个模块都已经执行了操作,
- [INFO] Scanning for projects...
- [INFO] ------------------------------------------------------------------------
- [INFO] Reactor Build Order:
- [INFO]
- [INFO] user-core
- [INFO] user-log
- [INFO] user-service
- [INFO] user-parent
- [INFO]
- [INFO] ------------------------------------------------------------------------
- [INFO] Building user-core 0.0.1-SNAPSHOT
- [INFO] ------------------------------------------------------------------------
- [INFO]
- [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ user-core ---
- [INFO] Deleting E:\Workspaces\STSWorkspace\user-core\target
- [INFO]
- [INFO] ------------------------------------------------------------------------
- [INFO] Building user-log 0.0.1-SNAPSHOT
- [INFO] ------------------------------------------------------------------------
- [INFO]
- [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ user-log ---
- [INFO] Deleting E:\Workspaces\STSWorkspace\user-log\target
- [INFO]
- [INFO] ------------------------------------------------------------------------
- [INFO] Building user-service 0.0.1-SNAPSHOT
- [INFO] ------------------------------------------------------------------------
- [INFO]
- [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ user-service ---
- [INFO] Deleting E:\Workspaces\STSWorkspace\user-service\target
- [INFO]
- [INFO] ------------------------------------------------------------------------
- [INFO] Building user-parent 0.0.1-SNAPSHOT
- [INFO] ------------------------------------------------------------------------
- [INFO]
- [INFO] ---<span style="color:#ff0000;"> maven-clean-plugin:2.5:clean (default-clean) @ user-parent </span>---
- [INFO] ------------------------------------------------------------------------
- [INFO] Reactor Summary:
- [INFO]
- [INFO] <span style="color:#ff0000;">user-core</span> ......................................... SUCCESS [0.255s]
- [INFO] <span style="color:#ff0000;">user-log</span> .......................................... SUCCESS [0.014s]
- [INFO] <span style="color:#ff0000;">user-service</span> ...................................... SUCCESS [0.015s]
- [INFO] user-parent ....................................... SUCCESS [0.002s]
- [INFO] ------------------------------------------------------------------------
- [INFO] BUILD SUCCESS
- [INFO] ------------------------------------------------------------------------
- [INFO] Total time: 0.500s
- [INFO] Finished at: Mon Feb 17 21:21:50 CST 2014
- [INFO] Final Memory: 4M/15M
- [INFO] ------------------------------------------------------------------------
下面进行继承的操作,继承的操作在这里主要对依赖和常量进行配置,配置后的pom文件依次是
user-parent中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/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.steven.user</groupId>
- <artifactId>user-parent</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <packaging>pom</packaging>
- <modules>
- <module>../user-core</module>
- <module>../user-log</module>
- <module>../user-service</module>
- </modules>
- <url>http://maven.apache.org</url>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.10</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.14</version>
- </dependency>
- <dependency>
- <groupId>org.hibernate</groupId>
- <artifactId>hibernate-core</artifactId>
- <version>4.1.1.Final</version>
- </dependency>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>5.1.8</version>
- </dependency>
- <dependency>
- <groupId>dom4j</groupId>
- <artifactId>dom4j</artifactId>
- <version>1.5</version>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>user-core</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>user-log</artifactId>
- <version>${project.version}</version>
- <exclusions>
- <exclusion>
- <groupId>dom4j</groupId>
- <artifactId>dom4j</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- </dependencies>
- </dependencyManagement>
- </project>
user-core中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/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>com.steven.user</groupId>
- <artifactId>user-parent</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <relativePath>../user-parent/pom.xml</relativePath>
- </parent>
- <artifactId>user-core</artifactId>
- <packaging>jar</packaging>
- <name>user-core</name>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- </dependency>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- </dependency>
- <dependency>
- <groupId>org.hibernate</groupId>
- <artifactId>hibernate-core</artifactId>
- </dependency>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- </dependency>
- </dependencies>
- </project>
user-log中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/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>com.steven.user</groupId>
- <artifactId>user-parent</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <relativePath>../user-parent/pom.xml</relativePath>
- </parent>
- <artifactId>user-log</artifactId>
- <packaging>jar</packaging>
- <name>user-log</name>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- </dependency>
- <dependency>
- <groupId>dom4j</groupId>
- <artifactId>dom4j</artifactId>
- </dependency>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- </dependency>
- </dependencies>
- </project>
user-service中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/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>com.steven.user</groupId>
- <artifactId>user-parent</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <relativePath>../user-parent/pom.xml</relativePath>
- </parent>
- <artifactId>user-service</artifactId>
- <packaging>jar</packaging>
- <name>user-service</name>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>user-core</artifactId>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>user-log</artifactId>
- </dependency>
- </dependencies>
- </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所示:
图1
第一个文件夹中是Nexus的一些控制文件,类似于tomcat中的结构,第二个文件夹主要是用来存放从*仓库中下载的jar等文件。
将E:\StudySoftware\javaEE\nexus-2.7.2-03-bundle\nexus-2.7.2-03\bin添加到环境变量中(为了在命令控制台总可以很好的操作),如图2所示
图2
接下来,打开命令控制台,输入nexus,即可显示如图3信息
图3
这个表示Nexus环境变量配置成功,下面进行配置E:\StudySoftware\javaEE\nexus-2.7.2-03-bundle\nexus-2.7.2-03\bin\jsw\conf\wrapper.conf文件,做如下修改(如果有配置过JRE路径可以不需要此项配置)
图4
图5
然后执行如下操作nexus install:
图6
会发现安装成功,但有时会出现以下问题,wrapper | OpenSCManager failed问题,如图7所示:
图7
问题是命令控制台没有按管理员权限打开,即没有权限,解决方法就是将命令控制台以管理员的方式打开,如图8所示进行设置:
图8
这样打开后既可和图6的执行效果一样。
刚刚执行过nexus install命令,即将nexus的服务安装到windows的服务中,下面我们启动服务。
方法一:
我们可以通过windows中的服务查看,如图9所示(可以通过系统键+R,然后输入services.msc回车即可出现图示)
图9
方法二:
这两种方法都可以进行服务启动。
检验:
下面可以在浏览器中输入地址http://localhost:8081/nexus/index.html进行打开Nexus的UI界面(如果是装在其他电脑上的,则需要换成电脑的准确IP地址,而我只是作为讲解,装在自己的电脑上了(哎!悲催的电脑,都快吃不消了,以后有钱一定换个好的!))
图11
这是打开后的页面,下面点击右上角的Log in,用户名为admin,密码默认为admin123,如图12所示:
图12
登录成功后如图13所示:
图13
登录成功后,下面就将进行Nexus的配置,以及讲解Nexus的仓库管理功能,由于篇幅问题,或者写的确实有些详细了,然后打算通过再一次讲解具体的Nexus的使用过程。
在此恭祝大家学习愉快!
六. Maven仓库管理器之应用Nexus
注:本博文是接着上一章节继续讲解
Nexus-私有仓库的配置
点击左边导航栏的Repositories选项,会显示一个所有仓库及仓库组的列表,Type字段的值有group,hosted,proxy,virtual(在Maven1中使用,这里不需要关心),如图14所示:
图14
在这里:
- hosted,本地仓库,这个仓库主要是用来存放本地的依赖包,服务于局域网,不访问公网
- proxy,代理仓库,用来存放nexus从公网中获取的依赖包,这里有*仓库,Apache和Codehaus开源网站的依赖包
- group,仓库组,用来合并多个hosted/proxy仓库,通常我们配置maven依赖仓库组
比如点击Type为group,如图15所示:
图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文件中,定义了*仓库的位置,配置文件如下所示
- ………………………………………………………………
- <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仓库
在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),配置如下:
- …………………………………………
- <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的信息:
图16
这表明,Maven已经从通过Nexus下载依赖包了,而Nexus从*工厂中进行下载。
接着看图17:
图17
这也验证了Nexus已经将mybatis的依赖包下载到了仓库中。
但此时会有个问题,如果将Nexus服务停止,如图18所示
图18
这个时候在user-core的pom.xml中添加原来没有的依赖配置文件(可以随便找个不存在的jar依赖文件进行测试,这里用使用Spring)
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-core</artifactId>
- <version>3.2.2.RELEASE</version>
- </dependency>
这个时候在Eclipse中点击保存,会发现如下的信息
- 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.
- 14-3-7 GMT+0800下午8:29:42: [INFO] Number of application's worked threads is 4
- 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
- 14-3-7 GMT+0800下午8:29:44: [INFO] Number of application's worked threads is 4
- 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
- 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访问*仓库,这个时候需要对镜像进行配置。
在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的例子,但都是注释掉的,我们在进行以上的改动时候,可以进行对其复制粘贴后进行修改,这样不容易出错。
验证:(此时没有打开nexus服务)
随便找个不存在的jar依赖文件进行测试,
- <dependency>
- <groupId>org.mortbay.jetty</groupId>
- <artifactId>jetty</artifactId>
- <version>6.1.26</version>
- </dependency>
跟刚才的步骤一样,但此时保存后,Eclipse控制台中的信息如下所示:
- 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
- 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.
- 14-3-7 GMT+0800下午9:13:58: [INFO] Number of application's worked threads is 4
- 14-3-7 GMT+0800下午9:14:02: [INFO] Using 'UTF-8' encoding to copy filtered resources.
- 14-3-7 GMT+0800下午9:14:02: [INFO] skip non existing resourceDirectory E:\Workspaces\STSWorkspace\user-service\src\main\resources
- 14-3-7 GMT+0800下午9:14:02: [INFO] Using 'UTF-8' encoding to copy filtered resources.
- 14-3-7 GMT+0800下午9:14:02: [INFO] skip non existing resourceDirectory E:\Workspaces\STSWorkspace\user-service\src\test\resources
这里只能通过Nexus下载依赖包,但是由于服务停止,所以下载失败,而如果此时将服务打开
图19
然后在Eclipse中刷新依赖包所在的pom.xml文件,
如果没有任何问题,则在控制台中显示如下信息:
- 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
- 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
但此时可能出现以下问题
- [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所示
图20
这样设置以后, Nexus会自动从远程*仓库下载索引文件,索引文件很大,需要很久等待时间。
思路2:
错误信息也有如下所示的提示:
- 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本地库的哪个仓库中,具体如下所示:
- ………………………………………………………………
- <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所示:
图21
而部署使用deployment用户,具体的配置如下
- ………………………………………………………………
- <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所示:
图22
这个时候部署成功,然后我们可以在Nexus中看到部署后的结果,如图23所示
图23
在Snapshots的索引中可以查看到刚刚部署的user-core模块。
通过Nexus搜索构件
首先我们来明确一下构件的含义,
构件:构件是系统中实际存在的可更换部分,它实现特定的功能,符合一套接口标准并实现一组接口,而在我们这里就是我们要使用的即将需找的依赖。
但在我们实际使用构件的过程中通常遇到一个问题,有时候我紧紧知道我所需要的构建的大致名字,并不知道全称或group id, 这是件非常头疼的事情. Nexus基于Nexus indexer(索引)的搜索功能帮我们解决了这个问题。
还记得刚才我们在解决Could not calculate build plan...问题的时候,给出的思路1,其思想就是,通过更改Download Remote Indexes的状态为True,使得Nexus从*仓库中将所有构件的信息同步到本地,这样在以后的开发中,就可以直接下载私有仓库中的依赖,就不需要Nexus还要去*仓库中下载了。下面就来领略Nexus搜索构件的方便之处。
如图所示:
图24
这里有以下几种搜索方式:
keyword(关键字查询), classname(类名查询), GAV(groupId,artifactId,version组合查询), checksum(校验和查询),这里我认为前三种使用的最多。
比如,刚刚通过部署后的user-core模块,这个模块正好被其他项目人员使用到,他知道模块的名称叫user-core,这个时候,可以通过GAV的方式进行查询,如图所示:
图25
查出来之后,只要将依赖文件复制到项目的pom.xml配置中,就可以从私有仓库中下载到其本地仓库进行使用了。
创建本地仓库并设置权限
创建仓库
在大公司的项目开发中,不可能所有的Snapshots和Releases版本都发布到Nexus中默认对应的Snapshots和Releases仓库中,我们可以给每个项目创建自己的本地仓库,并赋予相应的角色权限进行操作。比如创建一个UserRelease仓库用来存储User项目的Release版本,这个时候,操作如图所示:
图26
接着将信息填入New Hosted Repository中,如图27所示
图27
这个时候就创建了UserRelease的本地仓库,如图所示
图28
创建权限
虽然我们已经创建了UserRelease仓库,但仓库的权限仅为预览,如果让其可以有增删改查的权限,只要点击图中Add,如图所示:
图29
接着进行信息填入,如图30所示
图30
这个时候UserRelease仓库就拥有了所有的权限,如图31所示
图31
创建角色
虽然有了权限,但在使用的过程中,进一步创建一个角色,对角色添加相应的权限,然后在让角色中添加相应的用户,这样在发布的时候就可以达到权限的最细致化,管理起来更加方面。
如图32,创建角色
图32
然后进行填写信息,如图33
图33
在这里有Add按钮,点击按钮的时候进行如下操作
图34
此时,创建角色后如图35所示:
图35
创建用户
角色创建好后就可以创建用户,通过专有的用户来进行专有项目的部署和其他操作,如图创建用户
图36
然后填入信息,如图所示
图37
在图37中点击Add按钮出现图38所示的选项,如下操作
图38
就是选择该用户所属的角色,而角色拥有所有的权限,完成后如图39所示
图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仓库中了。
总结
本章节通过对仓库管理器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的开发者多么智慧的头脑,以及多好的设计原则。
(待修改...)