Apache Maven是一个软件项目管理的综合工具。基于项目对象模型(POM)的概念,提供了帮助管理构建、文档、报告、依赖、发布等方法,Maven简化和标准化项目建设过程。处理编译,分配,文档,团队协作和其他任务的无缝连接。 Maven增加可重用性并负责建立相关的任务。
maven的好处在于可以将项目过程规范化、自动化、高效化以及强大的可扩展性,利用maven自身及其插件还可以获得代码检查报告、单元测试覆盖率、实现持续集成等等。
Maven的基本原理很简单,采用远程仓库和本地仓库以及一个核心的配置文件pom.xml,pom.xml中定义的jar文件从远程仓库下载到本地仓库,各个项目使用同一个本地仓库的jar,同一个版本的jar只需下载一次,而且避免每个应用都去拷贝jar。同时它采用了现在流行的插件体系架构,所以maven的核心非常的小,只有几兆大小的文件,在执行maven任务时,才会自动下载需要的插件。
具体的概念模型如下图:
Maven官方把maven定义为一个项目管理工具,下面我们来看看maven给我们的项目管理做了哪些工作?
项目标准化:
Maven项目具有统一的项目结构,这个项目结构是参考业界的最佳实践而成,为后面使用统一的maven命令打下了基础,如测试mvn test、打包mvn package等,无需写一行脚本,就可以方便的实现众多功能。
文档和报告:
使用mvn site可以快速生成项目站点,apache很多开源项目站点都采用maven生成,会出现built by maven字样的图标。
类库管理:
类库管理是maven一个比较核心的功能,我们就需要将项目所依赖的类库加入到pom.xml中,那么maven会自动将依赖的类库下载到本地,并且下载的类库如果还依赖其他的类库,它也会自动下载过来,这样我们就不需要一个一个类库去下载了。
发布管理:
使用maven可以方便的进行项目发表管理。在项目开发到一定阶段,可以使用mvn package打包,它会自动先运行mvn test,跑所有的Test Case,只有全部通过才能正确打包。生成的war包(如果项目的packaging为war)在target目录下。这个 war包与使用ant脚本生成一样,但无需一行脚本,这也是maven对比ant的优势之一。使用mvn install将编译和打包好的文件发布到本地仓库中。使用mvn deploy在整合或者发布环境下执行,将最终版本的包拷贝到远程的repository。
想要安装 Apache Maven在Windows 系统上, 需要下载 Maven 的 zip 文件,并将其解压到你想安装的目录,并配置 Windows
环境变量。
所需工具 :
1.JDK
2.Maven
3.Windows 7
注
Maven 3.2 要求 JDK 1.6 或以上版本, 而 Maven 3.0/3.1 需要 JDK 1.5 或以上。
1.JDK 和 JAVA_HOME
确保已安装JDK,并 将“JAVA_HOME” 变量已加入到 Windows 环境变量中。
我们可以打开Windows的命令行,运行如下的命令来检查Java的安装:
上述命令首先检查环境变量JAVA_HOME是否指向了正确的JDK目录,然后运行了java命令,如果无法执行命令,
或者无法找到JAVA_HOME环境变量,就需要检查Java是否安装了,或者环境变量是否设置正确。
2.下载Apache Maven
下载地址:http://maven.apache.org/download.html,打开后找到下载链接,如图:
小Alan是老以前下载的3.2.2的版本,用着也没什么问题,所以也懒得下载最新的版本,这里大家可以下载最新的版本下来用。
当然,如果你对Maven的源代码感兴趣并想自己构建Maven,也可以下载apache-maven-3.3.9-src.zip。
将下载的安装包解压到特定的目录下,假设你解压缩到文件夹 – D:\apache-maven-3.2.2,如图:
3.添加 M2_HOME 和 MAVEN_HOME
打开系统属性面板(右击“计算机”>"属性"),单击高级系统设置,再单击环境变量,在系统变量中新建一个变量,变量名为M2_HOME,变量值为Maven的安装目录,如图:
M2_HOME 或 MAVEN_HOME
Maven 说只是添加 M2_HOME , 但一些项目仍引用 Maven 的文件夹 MAVEN_HOME, 因此,为了安全也把它添加进去。
小Alan使用的是M2_HOME。
4.添加到环境变量 - PATH
编辑 PATH 变量,添加 Maven bin 文件夹到 PATH 的最后,如: %M2_HOME%\bin, 这样就可以在命令中的任何目录下运行
Maven 命令了。
5.验证
在命令行中输入:echo %M2_HOME%以及mvn –version或-v,出现下面这个界面,说明我们的maven已经安装成功。
第一条命令echo %M2_HOME%用来检查M2_HOME是否指向了正确的Maven安装目录,mvn -v用来检查Windows
是否能够找到正确的mvn执行脚本。
6.升级
在Windows上更新Maven非常简单,只需要下载新的文件解压至本地目录,然后更新M2_HOME环境变量指向的目录即可,
降级也是同理,不做过多介绍。
1.Maven本地仓库/远程仓库的基本介绍
示意图:
本地仓库是指存在于我们本机的仓库,在我们加入依赖时候,首先会跑到我们的本地仓库去找,如果找不到则会跑到远程仓库中去找。对于依赖的包大家可以从这个地址进行搜索:http://mvnrepository.com/。
远程仓库是指其他服务器上的仓库,包括全球中央仓库,公司内部的私服,又或者其他公司提供的公共库。后面会专门聊聊私服,公共库的话只是一个地址,大家会引用就行了。
Maven的本地仓库是用来存储所有项目的依赖关系(插件jar和其他文件,这些文件被Maven下载)到本地文件夹。很简单,当你建立一个Maven项目,所有相关文件将被存储在你的Maven本地仓库。
默认情况下,Maven的本地仓库默认为系统用户的 .m2 目录文件夹,如图:
2.更新Maven的本地仓库地址
默认的本地仓库地址在c盘下面,如果开发的项目比较大,可能会占用过多的c盘空间,而且c盘会随着系统的损坏可能有格式化的风险。通常情况下,可改变默认的 .m2 目录下的默认本地存储库文件夹到其他盘并取一个有意义的名称,如:maven_repository。
我们来看一个文件,文件放在maven的安装目录下面的conf子目录下面,大家打开这个文件夹可以看到有个叫settings.xml的文件夹,这个里面包含仓库地址、镜像、插件、代理等配置,也是maven中一个核心配置文件,在后面我们会经常跟她打交道。下面我来看看这个文件以及如何配置本地仓库。
打开这个文件,我们会看到Default: ~/.m2/repository这样一句话,这话就告诉我们maven的默认仓库位置,我们修改setting中的仓库目录位置
如图:
为了保持核心的配置文件不变,我们可以将settings.xml文件拷贝到.m2目录下面。以后只要对这个文件做修改就可以了,maven会优先读取.m2下面的配置文件。(可选)
也可直接指向的maven安装目录的conf子目录下面的setting.xml.
我们以简单的helloworld来作为入门的实例,有些人说掌握了helloworld你就掌握了这门技术的一半了,对于maven来说,你掌握helloworld,你可能还稀里糊涂的。
1.从maven模板创建一个项目
在命令提示符(Windows)中,浏览到要创建 Java 项目的文件夹。键入以下命令:
project-packaging:项目包名
project-name:项目名称
这告诉 Maven 来从 maven-archetype-quickstart 模板创建 Java 项目。如果忽视 archetypeArtifactId 选项,一个巨大的 Maven 模板列表将列出。
例如,这里的工作目录是E:\workspace_maven,执行命令过程时间可能比较久,看个人的网络状况。
在上述情况下,一个新的Java项目命名 “HelloWorld”, 而整个项目的目录结构会自动创建。
注意
有少数人说 mvn archetype:generate 命令未能生成项目结构。 如果您有任何类似的问题,不用担心,只需跳过此步骤,手动创建文件夹。
2.Maven项目目录布局
src/main/java:用来存放源代码
src/main/resources:用来存放源代码的资源文件
src/test/java:用来存放单元测试代码
src/test/resources:用来存放测试代码的资源文件
3.在Eclipse IDE中使用我们的项目
为了使它成为一个 Eclipse 项目,进入到 “HelloWorld” 项目目录,键入以下命令:
执行以上命令后,它自动下载更新相关资源和配置信息(需要等待一段时间),并产生 Eclipse IDE所要求的所有项目文件。要导入项目到Eclipse IDE中,
选择 “File -> Import… -> General->Existing Projects into Workspace”,将“HelloWord项目导入到Eclipse中”。
项目导入到 Eclipse IDE中,如图:
4.更新POM文件(注意:前面部分与后面部分是隔了一段时间写的,所处的电脑不一样,所以工作空间不同,这个大家知道一下就好了)
默认的 pom.xml 太简单了,很多时候,你需要添加编译器插件来告诉 Maven 使用哪个 JDK 版本来编译项目,我们用4.11版本的junit,并用插件指明使用哪个JDK版本。
5.运行maven项目
现在,我们将使用Maven这个项目,并输出编译成一个 “jar” 的文件。pom.xml 文件中包元素packaging定义应该输出什么包。如图:
回到我们的项目目录,输入命令: mvn package
它编译,运行单元测试并打包项目成一个 jar 文件,并把它放在 project/target 文件夹。
最终项目的目录结构, 如下图 :
最后,我们来运行一下这个jar文件,看看运行结果:
打印输出:“HelloWorld”。
前面提到的部分知识有涉及到Maven目录结构与Maven常用的一些命令,在这里专门给大家做个简单的介绍。
1.Maven目录结构说明
Maven总体目录结构如下图:
bin目录:该目录包含了mvn运行的脚本,这些脚本用来配置java命令,准备好classpath和相关的Java系统属性,然后执行Java命令。
boot目录:该目录只包含一个文件,以maven3.2.2为例,该文件为plexus-classworlds-2.5.1.jar。plexus-classworlds是一个类加载器框架,相对于默认的java类加载器,它提供了更丰富的语法以方便配置,Maven使用该框架加载自己的类库。更多关于classworlds的信息请参考http://classworlds.codehaus.org/。对于一般的Maven用户来说,不必关心该文件。
conf目录:该目录包含了一个非常重要的文件settings.xml,Maven的核心配置文件。
lib目录:该目录包含了所有Maven运行时需要的Java类库,Maven本身是分模块开发的,因此用户能看到诸如mavn-core-3.2.2.jar、maven-model-3.2.2.jar之类的文件,此外这里还包含一些Maven用到的第三方依赖如commons-cli-1.2.jar、commons-lang-2.6.jar等等。
2.Maven常用命令说明
mvn clean:表示运行清理操作(会默认把target文件夹中的数据清理)。
mvn clean compile:表示先运行清理之后运行编译,会将代码编译到target文件夹中。
mvn clean test:运行清理和测试。
mvn clean package:运行清理和打包。
mvn clean install:运行清理和安装,会将打好的包安装到本地仓库中,以便其他的项目可以调用。
mvn clean deploy:运行清理和发布(发布到私服上面)。
上面的命令大部分都是连写的,大家也可以拆分分别执行,这是活的,看个人喜好以及使用需求,Eclipse Run as对maven项目会提供常用的命令。
3.特别说明
自从Maven3出来之后,后续的Eclipse IDE中往往都集成了Maven项目管理工具,所以这里不会特定给大家去说怎么在Eclipse中安装Maven插件,在后续的介绍中可能会提到部分如何在Eclipse中配置我们自己的Maven,这都是比较简单的内容,大家完全可以自己摸索。
祝大家都能够掌握这个好用的项目管理工具,如果喜欢关注技术的朋友还可以了解了解其他类似于这方面的技术以及框架,给大家举个简单的例子:Gradle。至于Maven之前的Make、Ant傻傻啥的,我觉得是没必要再去学习了,也基本不会用到,现实一点,吃饭的东西最要紧。
通过前面几部分知识,我们对maven已经有了初步的印象,就像Make的Makefile、Ant的build.xml一样,Maven项目的核心是pom.xml。POM(Project Object Model,项目对象模型)定义了项目的基本信息,用于描述项目如何构建,声明依赖,等等。我们来看看maven中pom.xml文件主要标签的意思及其用法,来看一下pom.xml文件的结构:
1 <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"> 2 <modelVersion>4.0.0modelVersion> 3 4 <groupId>com.uidpgroupId> 5 <artifactId>UidpParentartifactId> 6 <version>0.0.1-SNAPSHOTversion> 7 <packaging>pompackaging> 8 9 10 <name>UidpParentname> 11 12 <url>http://maven.apache.orgurl> 13 14 15 <properties> 16 <project.build.sourceEncoding>UTF-8project.build.sourceEncoding> 17 18 <repository-url>http://192.168.0.70:8081/content/groups/public/repository-url> 19 20 <maven-compiler-plugin.version>3.1maven-compiler-plugin.version> 21 <maven-war-plugin.version>2.4maven-war-plugin.version> 22 <maven-javadoc-plugin.version>2.9.1maven-javadoc-plugin.version> 23 <maven-release-plugin.version>2.4.1maven-release-plugin.version> 24 <maven-deploy-plugin.version>2.7maven-deploy-plugin.version> 25 26 27 28 <junit.version>4.11junit.version> 29 <oracle.version>10.2.0.4oracle.version> 30 <springframework.version>3.2.8.RELEASEspringframework.version> 31 <mybatis.version>3.2.2mybatis.version> 32 <mybatis-spring.version>1.2.0mybatis-spring.version> 33 <mysql-driver.version>5.1.25mysql-driver.version> 34 <aspectjweaver.version>1.7.3aspectjweaver.version> 35 36 <commons-dbcp.version>1.4commons-dbcp.version> 37 <commons-pool.version>1.5.5commons-pool.version> 38 <commons-fileupload.version>1.2.2commons-fileupload.version> 39 40 <log4j.version>1.2.17log4j.version> 41 <slf4j-api.version>1.7.5slf4j-api.version> 42 <slf4j-log4j12.version>1.7.5slf4j-log4j12.version> 43 44 <freemarker.version>2.3.19freemarker.version> 45 46 <jackson-core.version>2.5.0jackson-core.version> 47 <jackson-mapper-asl.version>1.9.7jackson-mapper-asl.version> 48 49 <javax.servlet-api.version>3.0.1javax.servlet-api.version> 50 <jsp-api.version>2.2jsp-api.version> 51 <kryo.version>1.04kryo.version> 52 <snakeyaml.version>1.8snakeyaml.version> 53 <jedis.version>2.0.0jedis.version> 54 <commons-lang.version>2.6commons-lang.version> 55 56 57 <mockito-core.version>1.8.5mockito-core.version> 58 <powermock-core.version>1.4.9powermock-core.version> 59 <powermock-api-mockito.version>1.4.9powermock-api-mockito.version> 60 <powermock-module-junit4.version>1.4.9powermock-module-junit4.version> 61 62 63 properties> 64 65 66 <dependencyManagement> 67 <dependencies> 68 69 <dependency> 70 <groupId>junitgroupId> 71 <artifactId>junitartifactId> 72 <version>${junit.version}version> 73 <scope>testscope> 74 dependency> 75 76 77 <dependency> 78 <groupId>org.springframeworkgroupId> 79 <artifactId>spring-webartifactId> 80 <version>${springframework.version}version> 81 dependency> 82 83 <dependency> 84 <groupId>org.springframeworkgroupId> 85 <artifactId>spring-webmvcartifactId> 86 <version>${springframework.version}version> 87 dependency> 88 89 <dependency> 90 <groupId>org.springframeworkgroupId> 91 <artifactId>spring-beansartifactId> 92 <version>${springframework.version}version> 93 dependency> 94 95 <dependency> 96 <groupId>org.springframeworkgroupId> 97 <artifactId>spring-contextartifactId> 98 <version>${springframework.version}version> 99 dependency> 100 101 <dependency> 102 <groupId>org.springframeworkgroupId> 103 <artifactId>spring-context-supportartifactId> 104 <version>${springframework.version}version> 105 dependency> 106 107 <dependency> 108 <groupId>org.springframeworkgroupId> 109 <artifactId>spring-coreartifactId> 110 <version>${springframework.version}version> 111 dependency> 112 113 <dependency> 114 <groupId>org.springframeworkgroupId> 115 <artifactId>spring-jdbcartifactId> 116 <version>${springframework.version}version> 117 dependency> 118 119 <dependency> 120 <groupId>org.springframeworkgroupId> 121 <artifactId>spring-txartifactId> 122 <version>${springframework.version}version> 123 dependency> 124 125 <dependency> 126 <groupId>org.springframeworkgroupId> 127 <artifactId>spring-testartifactId> 128 <version>${springframework.version}version> 129 dependency> 130 131 <dependency> 132 <groupId>org.springframeworkgroupId> 133 <artifactId>spring-expressionartifactId> 134 <version>${springframework.version}version> 135 dependency> 136 137 <dependency> 138 <groupId>org.springframeworkgroupId> 139 <artifactId>spring-aopartifactId> 140 <version>${springframework.version}version> 141 dependency> 142 143 144 <dependency> 145 <groupId>org.mybatisgroupId> 146 <artifactId>mybatisartifactId> 147 <version>${mybatis.version}version> 148 dependency> 149 150 <dependency> 151 <groupId>org.mybatisgroupId> 152 <artifactId>mybatis-springartifactId> 153 <version>${mybatis-spring.version}version> 154 dependency> 155 156 <dependency> 157 <groupId>mysqlgroupId> 158 <artifactId>mysql-connector-javaartifactId> 159 <version>${mysql-driver.version}version> 160 dependency> 161 162 <dependency> 163 <groupId>com.oraclegroupId> 164 <artifactId>ojdbc14artifactId> 165 <version>${oracle.version}version> 166 dependency> 167 168 <dependency> 169 <groupId>org.aspectjgroupId> 170 <artifactId>aspectjweaverartifactId> 171 <version>${aspectjweaver.version}version> 172 dependency> 173 174 175 <dependency> 176 <groupId>commons-dbcpgroupId> 177 <artifactId>commons-dbcpartifactId> 178 <version>${commons-dbcp.version}version> 179 dependency> 180 <dependency> 181 <groupId>commons-poolgroupId> 182 <artifactId>commons-poolartifactId> 183 <version>${commons-pool.version}version> 184 dependency> 185 <dependency> 186 <groupId>commons-fileuploadgroupId> 187 <artifactId>commons-fileuploadartifactId> 188 <version>${commons-fileupload.version}version> 189 dependency> 190 191 192 193 <dependency> 194 <groupId>log4jgroupId> 195 <artifactId>log4jartifactId> 196 <version>${log4j.version}version> 197 dependency> 198 <dependency> 199 <groupId>org.slf4jgroupId> 200 <artifactId>slf4j-apiartifactId> 201 <version>${slf4j-api.version}version> 202 dependency> 203 <dependency> 204 <groupId>org.slf4jgroupId> 205 <artifactId>slf4j-log4j12artifactId> 206 <version>${slf4j-log4j12.version}version> 207 dependency> 208 209 210 <dependency> 211 <groupId>org.freemarkergroupId> 212 <artifactId>freemarkerartifactId> 213 <version>${freemarker.version}version> 214 dependency> 215 216 217 218 <dependency> 219 <groupId>com.fasterxml.jackson.coregroupId> 220 <artifactId>jackson-coreartifactId> 221 <version>${jackson-core.version}version> 222 dependency> 223 <dependency> 224 <groupId>org.codehaus.jacksongroupId> 225 <artifactId>jackson-mapper-aslartifactId> 226 <version>${jackson-mapper-asl.version}version> 227 dependency> 228 229 <dependency> 230 <groupId>javax.servletgroupId> 231 <artifactId>javax.servlet-apiartifactId> 232 <version>${javax.servlet-api.version}version> 233 <scope>providedscope> 234 dependency> 235 236 <dependency> 237 <groupId>javax.servlet.jspgroupId> 238 <artifactId>jsp-apiartifactId> 239 <version>${jsp-api.version}version> 240 <scope>providedscope> 241 dependency> 242 243 <dependency> 244 <groupId>com.googlecodegroupId> 245 <artifactId>kryoartifactId> 246 <version>${kryo.version}version> 247 dependency> 248 249 <dependency> 250 <groupId>org.yamlgroupId> 251 <artifactId>snakeyamlartifactId> 252 <version>${snakeyaml.version}version> 253 dependency> 254 255 <dependency> 256 <groupId>redis.clientsgroupId> 257 <artifactId>jedisartifactId> 258 <version>${jedis.version}version> 259 dependency> 260 261 <dependency> 262 <groupId>commons-langgroupId> 263 <artifactId>commons-langartifactId> 264 <version>${commons-lang.version}version> 265 dependency> 266 267 268 <dependency> 269 <groupId>org.mockitogroupId> 270 <artifactId>mockito-coreartifactId> 271 <version>${mockito-core.version}version> 272 <scope>testscope> 273 dependency> 274 275 <dependency> 276 <groupId>org.powermockgroupId> 277 <artifactId>powermock-coreartifactId> 278 <version>${powermock-core.version}version> 279 <scope>testscope> 280 dependency> 281 282 <dependency> 283 <groupId>org.powermockgroupId> 284 <artifactId>powermock-api-mockitoartifactId> 285 <version>${powermock-api-mockito.version}version> 286 <scope>testscope> 287 dependency> 288 289 <dependency> 290 <groupId>org.powermockgroupId> 291 <artifactId>powermock-module-junit4artifactId> 292 <version>${powermock-module-junit4.version}version> 293 <scope>testscope> 294 dependency> 295 296 297 dependencies> 298 dependencyManagement> 299 300 <distributionManagement> 301 <repository> 302 <id>releasesid> 303 <name>publicname> 304 <url>http://59.50.95.66:8081/nexus/content/repositories/releasesurl> 305 repository> 306 <snapshotRepository> 307 <id>snapshotsid> 308 <name>Snapshotsname> 309 <url>http://59.50.95.66:8081/nexus/content/repositories/snapshotsurl> 310 snapshotRepository> 311 distributionManagement> 312 313 314 315 <build> 316 <plugins> 317 318 <plugin> 319 <groupId>org.apache.maven.pluginsgroupId> 320 <artifactId>maven-compiler-pluginartifactId> 321 <version>${maven-compiler-plugin.version}version> 322 <configuration> 323 <source>1.7source> 324 <target>1.7target> 325 configuration> 326 plugin> 327 328 <plugin> 329 <groupId>org.apache.maven.pluginsgroupId> 330 <artifactId>maven-javadoc-pluginartifactId> 331 <version>${maven-javadoc-plugin.version}version> 332 plugin> 333 334 335 <plugin> 336 <groupId>org.apache.maven.pluginsgroupId> 337 <artifactId>maven-release-pluginartifactId> 338 <version>${maven-release-plugin.version}version> 339 plugin> 340 341 <plugin> 342 <groupId>org.apache.maven.pluginsgroupId> 343 <artifactId>maven-deploy-pluginartifactId> 344 <version>${maven-deploy-plugin.version}version> 345 <configuration> 346 <updateReleaseInfo>trueupdateReleaseInfo> 347 configuration> 348 plugin> 349 350 plugins> 351 build> 352 353 354 <pluginRepositories> 355 <pluginRepository> 356 <id>nexusid> 357 <name>nexusname> 358 <url>${repository-url}url> 359 <releases> 360 <enabled>trueenabled> 361 releases> 362 <snapshots> 363 <enabled>trueenabled> 364 snapshots> 365 pluginRepository> 366 pluginRepositories> 367 368 369 project>
我们可以看到maven的pom.xml文件结构非常清晰,把项目创建好后,我们基本上是在dependencies元素下添加一些子元素及plugins元素下添加一些插件,下面我们来介绍一下各个元素的含义。
1) project是所有pom.xml的根元素,并且在里面定义了命名空间和xsd元素。
2) modelVersion 当前pom模型的版本。
3) groupId定义当前maven项目隶属的实际项目,并会根据这给项目建立包结构。
4) artifactId定义项目中的某个模块名称,如果只有一个模块那就是项目的名称。
5) version 定义maven项目当前所处的版本号,默认0.0.1-SNAPSHOT为快照版本。
6) packaging定义maven项目的打包方式,可以是jar包、war包、pom。
7) dependencies元素底下就是加入依赖包的地方,那么我们从哪里查询依赖包呢,可以查询的地方比较多,我给出一个大家用得比较多的仓库:http://mvnrepository.com。
8) 每个dependency都是一个依赖包,依赖包也就是在dependency里面定义各个依赖包的坐标,这样maven就会从网上下载依赖包到你本地仓库中,有所不同的是dependency元素包含了一个子元素,这个就是对maven生命周期的一个说明,当然除了上面四个子元素外,还包含几个其他的元素。
(1)type说明依赖的类型
(2)optional标记依赖是否可选
(3)exclusions 用来排斥传递依赖
我们具体来看看这个结构:
Maven是通过groupId、artifactId、version这三类似于坐标的元素来确定唯一性的,因此这三个元素对于每个依赖大多是必须的,后面会详细介绍依赖、聚合、继承等知识点。
没有任何实际的Java代码,我们能够定义一个Maven项目的POM,这体现了Maven的一大优点,它能让项目对象模型最大程度地与实际代码相独立,我们可以称之为解耦。这在很大程度上避免了Java代码和POM代码的相互影响。只要我们定义的POM稳定后,日常的Java代码开发工作中基本不会涉及到POM的修改。
这里说一下在使用Maven过程中不是必须的,但十分有用的几个实践,关键时刻或许能解决您的问题。
1.设置MAVEN_OPTS环境变量
通常需要设置MAVEN_OPTS的值为-Xms128m -Xmx512m,因为Java默认的最大可用内存往往不能够满足Maven运行的需要,比如在项目较大时,使用Maven生成项目站点需要占用大量的内存,如果没有该配置,则很容易得到java.lang.OutOfMemeoryError异常。因此,一开始就配置该环境变量是推荐的做法。
关于如何设置环境变量,请参考前面的知识。
2.配置用户范围settings.xml
Maven用户可以选择配置Maven安装目录conf下的settings.xml或者系统用户目录.m2下的settings.xml。前者是全局范围的,整台机器上的所有用户都会直接受到该配置的影响,而后者是用户范围的,只有当前用户才会受到该配置的影响。
推荐使用用户范围的settings.xml,主要是为了避免无意识地影响到系统中的其他用户。如果有切实的需求,需要统一系统中所有用户的settings.xml配置,当然应该使用全局范围的settings.xml。
除了影响范围这一因素,配置用户范围settings.xml文件还便于Maven升级。直接修改conf目录下的settings.xml会导致Maven升级的不便,每次升级到新版本的Maven,都需要复制settings.xml文件。如果使用.m2目录下的settings.xml,就不会影响到Maven安装文件,升级时就不需要触动settings.xml文件。
一般情况下.m2目录下是没有settings.xml配置文件的,需要我们复制conf下面的settings.xml至.m2目录下,然后再进行修改。
3.不要使用IDE内嵌的Maven
Eclipse在集成Maven时,都会安装上一个内嵌的Maven,这个内嵌的Maven通常会比较新,但不一定很稳定,而且往往也和在命令行使用的Maven不是同一个版本。这里会有两个潜在的问题:首先,较新版本的Maven存在很多不稳定因素,容易造成一些难以理解的问题;其次,除了IDE,也经常还会使用命令行的Maven,如果版本不一致,容易造成构建行为的不一致,这是我们所不希望看到的。因此,应该在IDE中配置Maven插件时使用与命令行一致的Maven。
在Eclipse环境中,点击菜单栏中的Window,然后选择Preferences,在弹出的对话框中展开左边的Maven项,选择Installations子项,在右边的面板中,能够看到有一个默认的EMBEDDED Maven安装被选中了。单击Add...按钮,然后选择Maven安装目录,添加完毕之后选择我们自己安装的Maven,点击OK按钮,如图:
其他类似的IDE或许在集成的时候也内嵌了Maven,同理,我们最好将它改为我们自己安装的Maven。
4.在Eclipse中指定使用的settings.xml配置文件
在Eclipse环境中,点击菜单栏中的Window,然后选择Preferences,在弹出的对话框中展开左边的Maven项,选择User Settings子项,在右边的面板中,单击Browse...按钮,然后选择对应的settings.xml文件,设置完毕之后点击OK按钮,如图:
也可使用的都是conf目录下settings.xml,要统一系统中所有用户的settings.xml配置,其他类似的IDE应该也有专门设置使用的settings.xml的地方。
1.Eclipse创建Maven项目
使用Eclipse创建一个Maven项目非常的简单,选择菜单项File>New>Other(也可以在项目结构空白处右击鼠标键),在弹出的对话框中选择Maven下的Maven Project,如图:
然后点击Next按钮,Next按钮,选择一个Archetype指定我们要创建的项目类型。我们选择普通的Java项目“maven-archetype-quickstart”,如图:
再点击Next按钮,输入Group Id、Artifact Id、Version、Package,如图:
这里要注意一个问题,当我们输入Group Id和Artifact Id时Eclipse会自动给我们在Package后面组成包名,要注意包名不能大写的问题,建议Group Id全部使用小写,Artifact Id如果是大写就自己手动改成自己想要的包名,这样就不会违背Java包命名规范了。
然后点击Finish按钮,Maven项目就创建完成了。
2.Eclipse运行mvn命令
在Maven项目或者pom.xml上右击,在弹出的快捷菜单中选择Run As,就能看到常见的Maven命令,如图:
选择要执行的命令就能执行相应的操作了,Eclipse会在控制台输出构建信息。
如果默认选项中没有我们要执行的命令怎么办?选择Maven build来自定义我们要执行的命令,在弹出对话框的Goals中输入我们要执行的命令,比如clean install,设置一下Name说明含义,单击Run运行即可。Eclipse会给我们保存这次设置,可以在Run Configurations...中找到,如图:
保存的记录,如图:
使用Eclipse创建项目和运行mvn命令就是这么so easy。
Maven的一个核心的作用就是管理项目的依赖,引入我们所需的各种jar包等。为了能自动化的解析任何一个Java构件,Maven必须将这些Jar包或者其他资源进行唯一标识,这是管理项目的依赖的基础,也就是我们要说的坐标。包括我们自己开发的项目,也是要通过坐标进行唯一标识的,这样才能才其它项目中进行依赖引用。
1.何为Maven坐标
关于坐标(Coordinate),大家最熟悉的应该就是数学中的坐标了吧,我印象不是特别深刻,说的数学专业一点叫作平面几何。在一个平面坐标系中,有x轴和y轴,x轴就是横线,y轴就是竖线,坐标(x,y)表示这个点距离x轴为y,距离y轴为x的一点,任何一个坐标都能唯一标识该平面中的一点。
在实际的生活中,我们可以将地址看成是一种坐标。不同的省,不同的市,不同的区,不同的街道等一系列信息标识了每一个不同的地址。在深圳经常吃外卖的人应该是有体会的,送外卖的小哥都会根据你填写的地址将外卖送给你,而你填的地址就标识了唯一的一个地址。
坐标就好比每一个Java构件的身份证一样。Maven的世界是拥有非常多的Java构件的,可能是jar、可能是war、也可能是其他的一些东西。假如Maven中没有坐标的概念,我们是无法来区分这些构件的,所以我们要唯一标识每一个构件。不然就和传统的手工方式一样,你需要spring就去spring下载spring的包,需要mysql又去mysql下载mysql的包,没有统一的规范又怎么能够自动化的去依赖这些构件。
Maven便给我们制定了一套规则那就是使用坐标进行唯一标识。Maven的坐标元素包括groupId、artifactId、version、packaging、classfier。只要我们提供正确的坐标元素,Maven就能找到对应的构件,首先去你的本地仓库查找,没有的话再去远程仓库下载。如果没有配置远程仓库,会默认从中央仓库地址(http://repo1.maven.org/maven2)下载构件,该中央仓库包含了世界上大部分流行的开源项目构件,但不一定所有构件都有,我在以前的开发中就遇到过找不到oracle数据库jar包的问题,不知道现在是否依然如此。
在我们自己开发项目的时候,也是要给我们的项目定义坐标的,这是强制性要求,只有这样,其他项目才能引用该项目的构件。
2.坐标详细说明
Maven坐标是通过groupId、artifactId、version、packaging、classfier这些元素来定义的,我们来看看示例:
我们在平时的开发中一般只需要使用必要的几个元素就好了,不必要的一些元素往往是用不着的,我们来看看每个元素所代表的含义,前面也是有简单的提到过的。
groupId :定义当前Maven项目隶属的实际项目。首先,Maven项目和实际项目不一定是一对一的关系。比如SpringFrameWork这一实际项目,其对应的Maven项目会有很多,如spring-core,spring-context等。这是由于Maven中模块的概念,因此,一个实际项目往往会被划分成很多模块。其次,groupId不应该对应项目隶属的组织或公司。原因很简单,一个组织下会有很多实际项目,如果groupId只定义到组织级别,而后面我们会看到,artifactId只能定义Maven项目(模块),那么实际项目这个层次将难以定义。最后,groupId的表示方式与Java包名的表达方式类似,通常与域名反向一一对应。上例中,groupId为junit,是不是感觉很特殊,这样也是可以的,因为全世界就这么个junit,它也没有很多分支。
artifactId : 该元素定义当前实际项目中的一个Maven项目(模块),推荐的做法是使用实际项目名称作为artifactId的前缀。比如上例中的junit,junit就是实际的项目名称,方便而且直观。在默认情况下,maven生成的构件,会以artifactId作为文件头,如junit-3.8.1.jar,使用实际项目名称作为前缀,就能方便的从本地仓库找到某个项目的构件。
version : 该元素定义了使用构件的版本,如上例中junit的版本是3.8.1,你也可以改为4.0表示使用4.0版本的junit。
packaging :定义Maven项目打包的方式,使用构件的什么包。首先,打包方式通常与所生成构件的文件扩展名对应,如上例中没有packaging,则默认为jar包,最终的文件名为junit-3.8.1.jar。也可以打包成war等。
classifier: 该元素用来帮助定义构建输出的一些附件。附属构件与主构件对应,如上例中的主构件为junit-3.8.1.jar,该项目可能还会通过一些插件生成如junit-3.8.1-javadoc.jar,junit-3.8.1-sources.jar, 这样附属构件也就拥有了自己唯一的坐标。
上述5个元素中,groupId、artifactId、version是必须定义的,packaging是可选的(默认为jar),而classfier是不能直接定义的,需要结合插件使用。
大家可以发现一个构件的名称就是由这几个元素的值所组成的,junit-3.8.1.jar,自己去比对一下,不仅如此,Maven仓库的布局也是基于Maven坐标的,大家可以看看本地仓库的布局是否如此。
理解了Maven坐标以后,大家就能够开始去学习Maven的依赖管理了。
1.何为依赖?
比如你是个男的,你要生孩子,呸呸呸...男的怎么生孩子,所以你得依赖你老婆,不过也不一定咯,你也可以依赖其她妹子。
我们在平时的项目开发中也是同理,你需要依赖一些东西才能实现相应的功能,但相应的功能或许也可以依赖其它的东西实现,比如数据库操作吧,你可以依赖hibernate,但你也可以通过mybatis来做。
这就是所谓的依赖关系咯。
以前我们需要手动的去找hibernate或者mybatis的jar包,系统抛异常我们还不知哪里报错,通过琢磨才明白没有引入相应的jar包,然后就去找啊找,找到了然后引入到工程当中。在这里我们就看到maven的好处了,它就是一个仓库,仓库里面有各种各样的包,想要什么就在pom.xml中依赖一下就好了,就算仓库中没有的包也可以把它扔到仓库中,想用的时候就依赖一下。
2.依赖的配置
1 <project> 2 <dependencies> 3 <dependency> 4 <groupId>junitgroupId> 5 <artifactId>junitartifactId> 6 <version>3.8.1version> 7 <type>...type> 8 <scope>testscope> 9 <optional>...optional> 10 <exclusions> 11 <exclusion> 12 <groupId>...groupId> 13 <artifactId>...artifactId> 14 exclusion> 15 exclusions> 16 dependency> 17 dependencies> 18 project>
根元素下project下的dependencies可以包含一个或者多个dependency元素,以声明一个或者多个项目依赖。每个依赖可以包含的元素有:
groupId,artifactId和version:依赖的基本坐标,对于任何一个依赖来说,基本坐标是最重要的,Maven根据坐标才能找到需要的依赖。
type:依赖的类型,对应于项目坐标定义的packaging。大部分情况下,该元素不必声明,其默认值是jar。
scope:依赖的范围,后面会进行详解。
optional:标记依赖是否可选。
exclusions:用来排除传递性依赖,后面会进行详细介绍。
大部分依赖声明只包含基本坐标,然而在一些特殊情况下,其他元素至关重要,我们来看看。
3.依赖范围说明
由于不同的包在不同的地方用到,像junit我们只有在做测试的时候会用到这个包,在我们项目发布的时候,用不到这个包;还有servlet-api,在项目编译的时候将会用到这个包,而项目发布的时候就不会用到这个包,因为一般容器已经自带这个包,如果我们导入,有可能会出现冲突,所以maven引入了依赖范围这个概念,即我们上面提到的scope来解决这个问题。Maven中有主要有以下这几种依赖范围:
1) test:指的是测试范围有效,在编译打包、运行时都不会使用这个依赖。例如:junit jar包。
2) compile:指的是编译范围有效,在编译、测试、打包、运行时都会将依赖存储进去。如果没有指定,就会默认使用该依赖范围。例如:hibernate jar包。
3) provided:在编译和测试的过程有效,最后生成包时不会加入,运行时自然也没效果。例如:servlet-api,因为servlet-api,tomcat等web服务器已经存在该jar包了,如果再打包可能会有冲突。
4) runtime:在测试、运行的时候依赖,在编译的时候不依赖。例如:JDBC驱动,项目代码只需要jdk提供的jdbc接口,只有在执行测试和运行项目的时候才需要实现jdbc的功能。
5) system:系统依赖范围。该依赖范围与provided所表示的依赖范围一致,对于编译和测试有效,但在运行时无效。只是使用system范围依赖时必须通过systemPath元素显式地指定依赖文件的路径。由于此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此应该谨慎使用,systemPath元素可以引用环境变量。例如:
1 <dependency> 2 3 <groupId>javax.sqlgroupId> 4 5 <artifactId>jdbc-stdextartifactId> 6 7 <version>2.0version> 8 9 <scope>systemscope> 10 11 <systemPath>${java.home}/lib/rt.jarsystemPath> 12 13 dependency>
6) import(Maven 2.0.9及以上):导入依赖范围。该依赖范围不会对三种classpath产生实际的影响。
上述除import以外的各种依赖范围与三种classpath的关系如下:
依赖范围(scope) | 测试classpath | 编译classpath | 运行classpath | 例子 |
compile | Y | Y | Y | spring-core |
provided | Y | servlet-api | ||
test | Y | junit | ||
runtime | Y | Y | JDBC驱动实现 | |
system | Y | Y | 本地的,Maven仓库之外的类库文件 |
4.传递性依赖和依赖范围
Maven的依赖是具有传递性的,比如A->B,B->C,那么A间接的依赖于C,这就是依赖的传递性,其中A对于B是第一直接依赖,B对于C是第二直接依赖,C为A的传递性依赖。
在平时的开发中,如果我们的项目依赖了spring-core,依赖范围是compile,spring-core又依赖了commons-logging,依赖范围也是compile,那么我们的项目对于commons-logging这一传递性依赖的范围也就是compile。第一直接依赖的范围和第二直接依赖的范围决定了传递性依赖的范围。我们通过下面这个表格来说明,其中最左边一栏是第一直接依赖,最上面那一栏为第二直接依赖。中间交叉的是传递性依赖范围。
|
Compile |
Test |
Provided |
Runtime |
Compile |
Compile |
|
|
Runtime |
Test |
Test |
|
|
Test |
Provided |
Provided |
|
Provided |
Provided |
Runtime |
Runtime |
|
|
Runtime |
例如:第一直接依赖范围是Test,第二直接依赖范围是Compile,那么传递性依赖的范围就是Test,大家可以根据这个表去判断。
仔细观察一下表格,我们可以发现这样的规律:
5.依赖调解
下面我们来思考这样一个问题,如果A->B->C->X(1.0),A->D-X(2.0),即A间接依赖X,我们可以看到有两条路径都依赖X,那么maven将会选择哪个版本的X?maven当中有一套自己的规则,我们来说明一下,maven传递性依赖的一些规则以及如何排除依赖冲突。
Maven里面对于传递性依赖有以下几个规则:
1) 最短路径原则:如果A对于依赖路径中有两个相同的jar包,那么选择路径短的那个包,路径最近者优先,上述会选X(2.0)。
2) 第一声明优先原则:如果A对于依赖路径中有两个相同的jar包,路径长度也相同,那么依赖写在前面的优先。例如:A->B->F(1.0),A->C->F(2.0),会选F(1.0)。
3) 可选依赖不会被传递,如A->B,B->C,B->D,A对B直接依赖,B对C和D是可选依赖,那么在A中不会引入C和D。可选依赖通过optional元素配置,true表示可选。如果要在A项目中使用C或者D则需要显式地声明C或者D依赖。
6.排除依赖
传递性依赖会给项目隐式的引入很多依赖,这极大的简化了项目依赖的管理,但是有些时候这种特性也会带来问题,它可能会把我们不需要的jar包也引入到了工程当中,使项目结构变得更复杂。或者你想替换掉默认的依赖换成自己想要的jar包,这时候就需要用到依赖排除。
例如:
1 <dependency> 2 <groupId>org.springframeworkgroupId> 3 <artifactId>spring-coreartifactId> 4 <version>3.2.8version> 5 <exclusions> 6 <exclusion> 7 <groupId>commons-logginggroupId> 8 <artifactId>commons-loggingartifactId> 9 exclusion> 10 exclusions> 11 dependency>
例子中spring-core包依赖了commons-logging包,我们使用exclusions元素声明排除依赖,exclusions可以包含一个或者多个exclusion子元素,因此可以排除一个或者多个传递性依赖。需要注意的是,声明exclusions的时候只需要groupId和artifactId,而不需要version元素,这是因为只需要groupId和artifactId就能唯一定位依赖图中的某个依赖。换句话说,Maven解析后的依赖中,不可能出现groupId和artifactId相同,但是version不同的两个依赖。
7.把依赖归为一类
在项目开发中往往会引入同一个项目中的多个jar包,比如最常见的spring,如果我们项目中用到很多关于Spring Framework的依赖,它们分别是spring-core-3.2.8.RELEASE, spring-beans-3.2.8.RELEASE,spring-context-3.2.8.RELEASE,它们都是来自同一项目的不同模块。因此,所有这些依赖的版本都是相同的,而且可以预见,如果将来需要升级Spring Framework,这些依赖的版本会一起升级。因此,我们应该在一个唯一的地方定义版本,并且在dependency声明引用这一版本,这一在Spring Framework升级的时候只需要修改一处即可。
首先使用properties元素定义Maven属性,实例中定义了一个
给大家一个完整的Maven配置实例,如果有在使用maven+spring+springMVC+Mybatis+Oracle数据库的朋友可以直接拿去改造成自己项目所需的父pom,配置如下:
1 <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"> 2 <modelVersion>4.0.0modelVersion> 3 4 <groupId>com.uidpgroupId> 5 <artifactId>UidpParentartifactId> 6 <version>0.0.1-SNAPSHOTversion> 7 <packaging>pompackaging> 8 9 <name>UidpParentname> 10 <url>http://maven.apache.orgurl> 11 12 <properties> 13 <project.build.sourceEncoding>UTF-8project.build.sourceEncoding> 14 15 <repository-url>http://192.168.0.70:8081/content/groups/public/repository-url> 16 17 <maven-compiler-plugin.version>3.1maven-compiler-plugin.version> 18 <maven-war-plugin.version>2.4maven-war-plugin.version> 19 <maven-javadoc-plugin.version>2.9.1maven-javadoc-plugin.version> 20 <maven-release-plugin.version>2.4.1maven-release-plugin.version> 21 <maven-deploy-plugin.version>2.7maven-deploy-plugin.version> 22 23 24 25 <junit.version>4.11junit.version> 26 <oracle.version>10.2.0.4oracle.version> 27 <springframework.version>3.2.8.RELEASEspringframework.version> 28 <mybatis.version>3.2.2mybatis.version> 29 <mybatis-spring.version>1.2.0mybatis-spring.version> 30 <mysql-driver.version>5.1.25mysql-driver.version> 31 <aspectjweaver.version>1.7.3aspectjweaver.version> 32 33 <commons-dbcp.version>1.4commons-dbcp.version> 34 <commons-pool.version>1.5.5commons-pool.version> 35 <commons-fileupload.version>1.2.2commons-fileupload.version> 36 37 <log4j.version>1.2.17log4j.version> 38 <slf4j-api.version>1.7.5slf4j-api.version> 39 <slf4j-log4j12.version>1.7.5slf4j-log4j12.version> 40 41 <freemarker.version>2.3.19freemarker.version> 42 43 <jackson-core.version>2.5.0jackson-core.version> 44 <jackson-mapper-asl.version>1.9.7jackson-mapper-asl.version> 45 46 <javax.servlet-api.version>3.0.1javax.servlet-api.version> 47 <jsp-api.version>2.2jsp-api.version> 48 <kryo.version>1.04kryo.version> 49 <snakeyaml.version>1.8snakeyaml.version> 50 <jedis.version>2.0.0jedis.version> 51 <commons-lang.version>2.6commons-lang.version> 52 53 54 <mockito-core.version>1.8.5mockito-core.version> 55 <powermock-core.version>1.4.9powermock-core.version> 56 <powermock-api-mockito.version>1.4.9powermock-api-mockito.version> 57 <powermock-module-junit4.version>1.4.9powermock-module-junit4.version> 58 59 60 properties> 61 62 <dependencyManagement> 63 <dependencies> 64 65 <dependency> 66 <groupId>junitgroupId> 67 <artifactId>junitartifactId> 68 <version>${junit.version}version> 69 <scope>testscope> 70 dependency> 71 72 73 <dependency> 74 <groupId>org.springframeworkgroupId> 75 <artifactId>spring-webartifactId> 76 <version>${springframework.version}version> 77 dependency> 78 79 <dependency> 80 <groupId>org.springframeworkgroupId> 81 <artifactId>spring-webmvcartifactId> 82 <version>${springframework.version}version> 83 dependency> 84 85 <dependency> 86 <groupId>org.springframeworkgroupId> 87 <artifactId>spring-beansartifactId> 88 <version>${springframework.version}version> 89 dependency> 90 91 <dependency> 92 <groupId>org.springframeworkgroupId> 93 <artifactId>spring-contextartifactId> 94 <version>${springframework.version}version> 95 dependency> 96 97 <dependency> 98 <groupId>org.springframeworkgroupId> 99 <artifactId>spring-context-supportartifactId> 100 <version>${springframework.version}version> 101 dependency> 102 103 <dependency> 104 <groupId>org.springframeworkgroupId> 105 <artifactId>spring-coreartifactId> 106 <version>${springframework.version}version> 107 dependency> 108 109 <dependency> 110 <groupId>org.springframeworkgroupId> 111 <artifactId>spring-jdbcartifactId> 112 <version>${springframework.version}version> 113 dependency> 114 115 <dependency> 116 <groupId>org.springframeworkgroupId> 117 <artifactId>spring-txartifactId> 118 <version>${springframework.version}version> 119 dependency> 120 121 <dependency> 122 <groupId>org.springframeworkgroupId> 123 <artifactId>spring-testartifactId> 124 <version>${springframework.version}version> 125 dependency> 126 127 <dependency> 128 <groupId>org.springframeworkgroupId> 129 <artifactId>spring-expressionartifactId> 130 <version>${springframework.version}version> 131 dependency> 132 133 <dependency> 134 <groupId>org.springframeworkgroupId> 135 <artifactId>spring-aopartifactId> 136 <version>${springframework.version}version> 137 dependency> 138 139 140 <dependency> 141 <groupId>org.mybatisgroupId> 142 <artifactId>mybatisartifactId> 143 <version>${mybatis.version}version> 144 dependency> 145 146 <dependency> 147 <groupId>org.mybatisgroupId> 148 <artifactId>mybatis-springartifactId> 149 <version>${mybatis-spring.version}version> 150 dependency> 151 152 <dependency> 153 <groupId>mysqlgroupId> 154 <artifactId>mysql-connector-javaartifactId> 155 <version>${mysql-driver.version}version> 156 dependency> 157 158 <dependency> 159 <groupId>com.oraclegroupId> 160 <artifactId>ojdbc14artifactId> 161 <version>${oracle.version}version> 162 dependency> 163 164 <dependency> 165 <groupId>org.aspectjgroupId> 166 <artifactId>aspectjweaverartifactId> 167 <version>${aspectjweaver.version}version> 168 dependency> 169 170 171 <dependency> 172 <groupId>commons-dbcpgroupId> 173 <artifactId>commons-dbcpartifactId> 174 <version>${commons-dbcp.version}version> 175 dependency> 176 <dependency> 177 <groupId>commons-poolgroupId> 178 <artifactId>commons-poolartifactId> 179 <version>${commons-pool.version}version> 180 dependency> 181 <dependency> 182 <groupId>commons-fileuploadgroupId> 183 <artifactId>commons-fileuploadartifactId> 184 <version>${commons-fileupload.version}version> 185 dependency> 186 187 188 189 <dependency> 190 <groupId>log4jgroupId> 191 <artifactId>log4jartifactId> 192 <version>${log4j.version}version> 193 dependency> 194 <dependency> 195 <groupId>org.slf4jgroupId> 196 <artifactId>slf4j-apiartifactId> 197 <version>${slf4j-api.version}version> 198 dependency> 199 <dependency> 200 <groupId>org.slf4jgroupId> 201 <artifactId>slf4j-log4j12artifactId> 202 <version>${slf4j-log4j12.version}version> 203 dependency> 204 205 206 <dependency> 207 <groupId>org.freemarkergroupId> 208 <artifactId>freemarkerartifactId> 209 <version>${freemarker.version}version> 210 dependency> 211 212 213 214 <dependency> 215 <groupId>com.fasterxml.jackson.coregroupId> 216 <artifactId>jackson-coreartifactId> 217 <version>${jackson-core.version}version> 218 dependency> 219 <dependency> 220 <groupId>org.codehaus.jacksongroupId> 221 <artifactId>jackson-mapper-aslartifactId> 222 <version>${jackson-mapper-asl.version}version> 223 dependency> 224 225 <dependency> 226 <groupId>javax.servletgroupId> 227 <artifactId>javax.servlet-apiartifactId> 228 <version>${javax.servlet-api.version}version> 229 <scope>providedscope> 230 dependency> 231 232 <dependency> 233 <groupId>javax.servlet.jspgroupId> 234 <artifactId>jsp-apiartifactId> 235 <version>${jsp-api.version}version> 236 <scope>providedscope> 237 dependency> 238 239 <dependency> 240 <groupId>com.googlecodegroupId> 241 <artifactId>kryoartifactId> 242 <version>${kryo.version}version> 243 dependency> 244 245 <dependency> 246 <groupId>org.yamlgroupId> 247 <artifactId>snakeyamlartifactId> 248 <version>${snakeyaml.version}version> 249 dependency> 250 251 <dependency> 252 <groupId>redis.clientsgroupId> 253 <artifactId>jedisartifactId> 254 <version>${jedis.version}version> 255 dependency> 256 257 <dependency> 258 <groupId>commons-langgroupId> 259 <artifactId>commons-langartifactId> 260 <version>${commons-lang.version}version> 261 dependency> 262 263 264 <dependency> 265 <groupId>org.mockitogroupId> 266 <artifactId>mockito-coreartifactId> 267 <version>${mockito-core.version}version> 268 <scope>testscope> 269 dependency> 270 271 <dependency> 272 <groupId>org.powermockgroupId> 273 <artifactId>powermock-coreartifactId> 274 <version>${powermock-core.version}version> 275 <scope>testscope> 276 dependency> 277 278 <dependency> 279 <groupId>org.powermockgroupId> 280 <artifactId>powermock-api-mockitoartifactId> 281 <version>${powermock-api-mockito.version}version> 282 <scope>testscope> 283 dependency> 284 285 <dependency> 286 <groupId>org.powermockgroupId> 287 <artifactId>powermock-module-junit4artifactId> 288 <version>${powermock-module-junit4.version}version> 289 <scope>testscope> 290 dependency> 291 292 293 dependencies> 294 dependencyManagement> 295 296 <distributionManagement> 297 <repository> 298 <id>releasesid> 299 <name>publicname> 300 <url>http://59.50.95.66:8081/nexus/content/repositories/releasesurl> 301 repository> 302 <snapshotRepository> 303 <id>snapshotsid> 304 <name>Snapshotsname> 305 <url>http://59.50.95.66:8081/nexus/content/repositories/snapshotsurl> 306 snapshotRepository> 307 distributionManagement> 308 309 310 311 <build> 312 <plugins> 313 314 <plugin> 315 <groupId>org.apache.maven.pluginsgroupId> 316 <artifactId>maven-compiler-pluginartifactId> 317 <version>${maven-compiler-plugin.version}version> 318 <configuration> 319 <source>1.7source> 320 <target>1.7target> 321 configuration> 322 plugin> 323 324 <plugin> 325 <groupId>org.apache.maven.pluginsgroupId> 326 <artifactId>maven-javadoc-pluginartifactId> 327 <version>${maven-javadoc-plugin.version}version> 328 plugin> 329 330 331 <plugin> 332 <groupId>org.apache.maven.pluginsgroupId> 333 <artifactId>maven-release-pluginartifactId> 334 <version>${maven-release-plugin.version}version> 335 plugin> 336 337 <plugin> 338 <groupId>org.apache.maven.pluginsgroupId> 339 <artifactId>maven-deploy-pluginartifactId> 340 <version>${maven-deploy-plugin.version}version> 341 <configuration> 342 <updateReleaseInfo>trueupdateReleaseInfo> 343 configuration> 344 plugin> 345 346 347 348 plugins> 349 build> 350 351 352 <pluginRepositories> 353 <pluginRepository> 354 <id>nexusid> 355 <name>nexusname> 356 <url>${repository-url}url> 357 <releases> 358 <enabled>trueenabled> 359 releases> 360 <snapshots> 361 <enabled>trueenabled> 362 snapshots> 363 pluginRepository> 364 pluginRepositories> 365 366 367 project>
1.远程仓库的配置
在平时的开发中,我们往往不会使用默认的中央仓库,默认的中央仓库访问的速度比较慢,访问的人或许很多,有时候也无法满足我们项目的需求,可能项目需要的某些构件中央仓库中是没有的,而在其他远程仓库中有,如JBoss Maven仓库。这时,可以在pom.xml中配置该仓库,代码如下:
1 2 <repositories> 3 <repository> 4 <id>jbossid> 5 <name>JBoss Repositoryname> 6 <url>http://repository.jboss.com/maven2/url> 7 <releases> 8 <enabled>trueenabled> 9 <updatePolicy>dailyupdatePolicy> 10 releases> 11 <snapshots> 12 <enabled>falseenabled> 13 <checksumPolicy>warnchecksumPolicy> 14 snapshots> 15 <layout>defaultlayout> 16 repository> 17 repositories>
repository:在repositories元素下,可以使用repository子元素声明一个或者多个远程仓库。
id:仓库声明的唯一id,尤其需要注意的是,Maven自带的中央仓库使用的id为central,如果其他仓库声明也使用该id,就会覆盖中央仓库的配置。
name:仓库的名称,让我们直观方便的知道仓库是哪个,暂时没发现其他太大的含义。
url:指向了仓库的地址,一般来说,该地址都基于http协议,Maven用户都可以在浏览器中打开仓库地址浏览构件。
releases和snapshots:用来控制Maven对于发布版构件和快照版构件的下载权限。需要注意的是enabled子元素,该例中releases的enabled值为true,表示开启JBoss仓库的发布版本下载支持,而snapshots的enabled值为false,表示关闭JBoss仓库的快照版本的下载支持。根据该配置,Maven只会从JBoss仓库下载发布版的构件,而不会下载快照版的构件。
layout:元素值default表示仓库的布局是Maven2及Maven3的默认布局,而不是Maven1的布局。基本不会用到Maven1的布局。
其他:对于releases和snapshots来说,除了enabled,它们还包含另外两个子元素updatePolicy和checksumPolicy。
元素updatePolicy用来配置Maven从远处仓库检查更新的频率,默认值是daily,表示Maven每天检查一次。其他可用的值包括:never-从不检查更新;always-每次构建都检查更新;interval:X-每隔X分钟检查一次更新(X为任意整数)。
元素checksumPolicy用来配置Maven检查校验和文件的策略。当构建被部署到Maven仓库中时,会同时部署对应的检验和文件。在下载构件的时候,Maven会验证校验和文件,如果校验和验证失败,当checksumPolicy的值为默认的warn时,Maven会在执行构建时输出警告信息,其他可用的值包括:fail-Maven遇到校验和错误就让构建失败;ignore-使Maven完全忽略校验和错误。
2.远程仓库的认证
大部分公共的远程仓库无须认证就可以直接访问,但我们在平时的开发中往往会架设自己的Maven远程仓库,出于安全方面的考虑,我们需要提供认证信息才能访问这样的远程仓库。配置认证信息和配置远程仓库不同,远程仓库可以直接在pom.xml中配置,但是认证信息必须配置在settings.xml文件中。这是因为pom往往是被提交到代码仓库中供所有成员访问的,而settings.xml一般只存在于本机。因此,在settings.xml中配置认证信息更为安全。
1 <settings> 2 2 ... 3 3 4 4 <servers> 5 5 <server> 6 6 <id>releasesid> 7 7 <username>adminusername> 8 8 <password>admin123password> 9 9 server> 10 10 servers> 11 11 ... 12 12 settings>
上面代码我们配置了一个id为releases的远程仓库认证信息。Maven使用settings.xml文件中的servers元素及其子元素server配置仓库认证信息。认证用户名为admin,认证密码为admin123。这里的关键是id元素,settings.xml中server元素的id必须与pom.xml中需要认证的repository元素的id完全一致。正是这个id将认证信息与仓库配置联系在了一起。
3.部署构件至远程仓库
我们使用自己的远程仓库的目的就是在远程仓库中部署我们自己项目的构件以及一些无法从外部仓库直接获取的构件。这样才能在开发时,供其他对团队成员使用。
Maven除了能对项目进行编译、测试、打包之外,还能将项目生成的构件部署到远程仓库中。首先,需要编辑项目的pom.xml文件。配置distributionManagement元素,代码如下:
1 <distributionManagement> 2 <repository> 3 <id>releasesid> 4 <name>publicname> 5 <url>http://59.50.95.66:8081/nexus/content/repositories/releasesurl> 6 repository> 7 <snapshotRepository> 8 <id>snapshotsid> 9 <name>Snapshotsname> 10 <url>http://59.50.95.66:8081/nexus/content/repositories/snapshotsurl> 11 snapshotRepository> 12 distributionManagement>
distributionManagement包含repository和snapshotRepository子元素,前者表示发布版本(稳定版本)构件的仓库,后者表示快照版本(开发测试版本)的仓库。这两个元素都需要配置id、name和url,id为远程仓库的唯一标识,name是为了方便人阅读,关键的url表示该仓库的地址。
往远程仓库部署构件的时候,往往需要认证,配置认证的方式同上。
配置正确后,运行命令mvn clean deploy,Maven就会将项目构建输出的构件部署到配置对应的远程仓库,如果项目当前的版本是快照版本,则部署到快照版本的仓库地址,否则就部署到发布版本的仓库地址。
快照版本和发布版本的区别请自行上百度查阅资料。
4.配置远程仓库的镜像
如果仓库X可以提供仓库Y存储的所有内容,那么就可以认为X是Y的一个镜像。换句话说,任何一个可以从仓库Y获得的构件,都能够从它的镜像中获取。举个例子,http://maven.oschina.net/content/groups/public/ 是中央仓库http://repo1.maven.org/maven2/ 在中国的镜像,由于地理位置的因素,该镜像往往能够提供比中央仓库更快的服务。因此,可以配置Maven使用该镜像来替代中央仓库。编辑settings.xml,代码如下:
1 <mirrors> 2 <mirror> 3 <id>maven.oschina.netid> 4 <name>maven mirror in Chinaname> 5 <url>http://maven.oschina.net/content/groups/public/url> 6 <mirrorOf>centralmirrorOf> 7 mirror> 8 mirrors>
该例中,mirrorOf的值为central,表示该配置为中央仓库的镜像,任何对于中央仓库的请求都会转至该镜像,用户也可以使用同样的方法配置其他仓库的镜像。id表示镜像的唯一标识符,name表示镜像的名称,url表示镜像的地址。
关于镜像的一个更为常见的用法是结合私服。由于私服可以代理任何外部的公共仓库(包括中央仓库),因此,对于组织内部的Maven用户来说,使用一个私服地址就等于使用了所有需要的外部仓库,这可以将配置集中到私服,从而简化Maven本身的配置。在这种情况下,任何需要的构件都可以从私服获得,私服就是所有仓库的镜像。这时,可以配置这样的一个镜像:
1 2 <mirrors> 3 <mirror> 4 <id>nexusid> 5 <name>internal nexus repositoryname> 6 <url>http://183.238.2.182:8081/nexus/content/groups/public/url> 7 <mirrorOf>*mirrorOf> 8 mirror> 9 mirrors>
该例中
需要注意的是,由于镜像仓库完全屏蔽了被镜像仓库,当镜像仓库不稳定或者停止服务的时候,Maven仍将无法访问被镜像仓库,因而将无法下载构件。
5.可用的Maven镜像仓库
1 <mirror> 2 <id>repo2id> 3 <mirrorOf>centralmirrorOf> 4 <name>Human Readable Name for this Mirror.name> 5 <url>http://repo2.maven.org/maven2/url> 6 mirror> 7 8 <mirror> 9 <id>uiid> 10 <mirrorOf>centralmirrorOf> 11 <name>Human Readable Name for this Mirror.name> 12 <url>http://uk.maven.org/maven2/url> 13 mirror> 14 15 16 <mirror> 17 <id>ibiblioid> 18 <mirrorOf>centralmirrorOf> 19 <name>Human Readable Name for this Mirror.name> 20 <url>http://mirrors.ibiblio.org/pub/mirrors/maven2/url> 21 mirror> 22 23 <mirror> 24 <id>jboss-public-repository-groupid> 25 <mirrorOf>centralmirrorOf> 26 <name>JBoss Public Repository Groupname> 27 <url>http://repository.jboss.org/nexus/content/groups/publicurl> 28 mirror> 29 30 <mirror> 31 <id>JBossJBPMid> 32 <mirrorOf>centralmirrorOf> 33 <name>JBossJBPM Repositoryname> 34 <url>https://repository.jboss.org/nexus/content/repositories/releases/url> 35 mirror>
上面的仓库经过测试是可以访问的。
6.仓库搜索服务地址
Sonatype Nexus:https://repository.sonatype.org/
MVNrepository:http://mvnrepository.com/
关于依赖的搜索,个人觉得这两个是最好用的。
除了坐标、依赖以及仓库之外,Maven的另外两个核心概念是生命周期和插件。在有关Maven的日常使用中,命令行的输入往往就对应了生命周期,如mvn package就表示执行默认生命周期阶段package。Maven的生命周期是抽象的,其实际行为都由插件来完成,如package阶段的任务可能就会由maven-jar-plugin完成。生命周期和插件两者协同工作,密不可分。
1.Maven生命周期
我们在开发项目的时候,我们不断地在经历编译、测试、打包、部署等过程,maven的生命周期就是对所有这些过程的一个抽象与统一,她的生命周期包含项目的清理、初始化、编译、测试、打包、集成测试、验证、部署、站点生成等几乎所有的过程,而且maven的生命周期是及其灵活,她生命周期的每个阶段是通过插件来实现的,maven也内置了很多插件,所以我们在项目进行编译、测试、打包的过程是没有感觉到。像编译是通过maven-compile-plugin实现的、测试是通过maven-surefire-plugin实现的。
Maven有三套相互独立的生命周期,请注意这里说的是“三套”,而且“相互独立”,初学者容易将Maven的生命周期看成一个整体,其实不然。这三套生命周期分别是:
我再次强调一下它们是相互独立的,你可以仅仅调用clean来清理工作目录,仅仅调用site来生成站点。当然你也可以直接运行 mvn clean install site运行所有这三套生命周期。
知道了每套生命周期的大概用途和相互关系以后,来逐个详细看一下每套生命周期,Clean和Site相对比较简单,先解释一下:
每套生命周期都由一组阶段(Phase)组成,我们平时在命令行输入的命令总会对应于一个特定的阶段。比如,运行mvn clean,这个的clean是Clean生命周期的一个阶段。有点绕?要知道有Clean生命周期,也有clean阶段。
Clean生命周期一共包含了三个阶段:
mvn clean中的clean就是上面的clean,在一个生命周期中,运行某个阶段的时候,它之前的所有阶段都会被运行,也就是说,mvn clean等同于 mvn pre-clean clean,如果我们运行 mvn post-clean,那么 pre-clean、clean 都会被运行。这是Maven很重要的一个规则,可以大大简化命令行的输入。
下面看一下Site生命周期的各个阶段:
这里经常用到的是site阶段和site-deploy阶段,用以生成和发布Maven站点,这可是Maven相当强大的功能,Manager比较喜欢,文档及统计数据自动生成,很好看。
最后,来看一下Maven的最重要的Default生命周期,绝大部分工作都发生在这个生命周期中,这里,我只解释一些比较重要和常用的阶段:
基本上,根据名称我们就能猜出每个阶段的用途,关于阶段的详细解释以及其她阶段的解释,请参考 http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html 。
记住,运行任何一个阶段的时候,它前面的所有阶段都会被运行,这也就是为什么我们运行mvn install的时候,代码会被编译,测试,打包。
此外,Maven的插件机制是完全依赖Maven的生命周期的,因此理解生命周期至关重要,接下来我将会进一步解释Maven的插件机制。
2.命令行与生命周期
从命令行执行Maven任务的最主要方式就是调用Maven的生命周期阶段。需要注意的是,各个生命周期是相互独立的,而一个生命周期的阶段是有前后依赖关系的。下面以一些常见的Maven命令为例,解释其执行的生命周期阶段:
mvn clean:该命令调用clean生命周期的clean阶段。实际执行的阶段为clean生命周期的pre-clean和clean阶段。
mvn test:该命令调用default生命周期的test阶段。实际执行的阶段为default生命周期的validate、initialize等,直到test的所有阶段。这也解释了为什么在执行测试的时候,项目的代码能够自动得以编译。
mvn clean install:该命令调用clean生命周期的clean阶段和default生命周期的install阶段。实际执行的阶段为clean生命周期的pre-clean、clean阶段,以及default生命周期的从validate至install的所有阶段。该命令结合了两个生命周期,在执行正在的项目构建之前清理项目是一个很好的实践。
mvn clean deploy site-deploy:该命令调用clean生命周期的clean阶段、default生命周期的deploy阶段,以及site生命周期的site-deploy阶段。实际执行的阶段为clean生命周期的pre-clean、clean阶段,default生命周期的所有阶段,以及site生命周期的所有阶段。该命令结合了Maven所有三个生命周期,且deploy为default生命周期的最后一个阶段,site-deploy为site生命周期的最后一个阶段。
由于Maven中主要的生命周期阶段并不多,而常用的Maven命令实际都是基于这些阶段简单组合而成的,因此只要对Maven生命周期有一个基本的理解,读者就可以正确而熟练地使用Maven命令。
3.Maven插件机制
通过上面的生命周期我们可以了解到,不同的生命周期绑定不同的插件;同时我们知道,下载下来的maven核心的东西不过3-4M,它主要就是通过插件来完成这些工作的,一旦碰到没有的插件,它会跑到相应的地方下载,然后来完成整个过程。那么在我们的项目中如何使用插件呢?
打开http://maven.apache.org/plugins/index.html网址,我们可以看到apache下面的很多插件,apache下面的插件是比较正规的,它里面的信息非常详细。下面我们来看看里面有个source的插件的用法。
Source插件是对源代码进行打包的一个插件,默认情况下,它会将生成的源代码放在工程目录的target下面。
Source插件具有五个目标:
在我们的工程pom.xml中,在后面引入下面这段配置:
1 <build> 2 <plugins>3 <plugin>4 <groupId>org.apache.maven.pluginsgroupId>5 <artifactId>maven-source-pluginartifactId>6 <version>2.1.2version>7 plugin>8 plugins>9 build>
上面这段配置就是对源码进行打包的插件,我们运行source:jar-no-fork,那么在项目的目录底下的target会生成一个类似于user-core-0.0.1-SNAPSHOT-sources.jar这样的文件,即项目的源文件。那么如何将这个插件与特定的生命周期绑定呢?我们来看下面这段配置:
1 <build> 2 <plugins> 3 <plugin> 4 <groupId>org.apache.maven.pluginsgroupId> 5 <artifactId>maven-source-pluginartifactId> 6 <version>2.1.2version> 7 <executions> 8 <execution> 9 <phase>packagephase>10 <goals>11 <goal>jar-no-forkgoal>12 goals>13 execution>14 executions>15 plugin>16 plugins>17 build>
通过这段配置,大家可以用 mvn package 将项目打包的同时会将源代码进行打包。图示说明:
Apache Maven里面还有很多有用的插件,大家可以自己去试一下,里面说明很详细,大家只要按着官方文档进行配置,一般情况下是没问题的,如果大家想把插件用的非常熟练建议多请教请教大神,或者购买《Maven实战》书籍,书籍中对插件会介绍的更详细,然后再结合大神使用的经验,相信大家能够熟练地使用Maven插件机制。
这里给大家详细说一下Maven的运行机制,让大家不仅知其然,更知其所以然。
1.插件保存在哪里?
与我们所依赖的构件一样,插件也是基于坐标保存在我们的Maven仓库当中的。在用到插件的时候会先从本地仓库查找插件,如果本地仓库没有则从远程仓库查找插件并下载到本地仓库。
与普通的依赖构件不同的是,Maven会区别对待普通依赖的远程仓库与插件的远程仓库。前面提到的配置远程仓库只会对普通的依赖有效果。当Maven需要的插件在本地仓库不存在时是不会去我们以前配置的远程仓库查找插件的,而是需要有专门的插件远程仓库,我们来看看怎么配置插件远程仓库,在pom.xml加入如下内容:
1 <pluginRepositories> 2 <pluginRepository> 3 <id>nexusid> 4 <name>nexusname> 5 <url>http://192.168.0.70:8081/content/groups/public/url> 6 <releases> 7 <enabled>trueenabled> 8 releases> 9 <snapshots> 10 <enabled>trueenabled> 11 snapshots> 12 pluginRepository> 13 pluginRepositories>
大家可以发现,除了pluginRepositories和pluginRepository与以前配置远程仓库不同以外,其他的都是一样的,所代表的含义也是一样的。Maven的父POM中也是有内置一个插件仓库的,我现在用的电脑安装的是Maven 3.0.4版本,我们可以找到这个文件:${M2_HOME}/lib/maven-model-builder-3.0.4.jar,打开该文件,能找到超级父POM:\org\apache\maven\model\pom-4.0.0.xml,它是所有Maven POM的父POM,所有Maven项目都继承该配置。
我们来看看默认的远程插件仓库配置的是啥:
1 <pluginRepositories> 2 <pluginRepository> 3 <id>centralid> 4 <name>Central Repositoryname> 5 <url>http://repo.maven.apache.org/maven2url> 6 <layout>defaultlayout> 7 <snapshots> 8 <enabled>falseenabled> 9 snapshots> 10 <releases> 11 <updatePolicy>neverupdatePolicy> 12 releases> 13 pluginRepository> 14 pluginRepositories>
默认插件仓库的地址就是中央仓库咯,它关闭了对snapshots的支持,防止引入snapshots版本的插件而导致不稳定的构件。一般来说,中央仓库所包含的插件完全能够满足我们的需要,只有在少数情况下才要配置,比如项目的插件无法在中央仓库找到,或者自己编写了插件才会配置自己的远程插件仓库。
2.插件命令运行解析
我们来看这样一个命令:
mvn compiler:compiler
这个命令会调用maven-compiler-plugin插件并执行compiler目标,大家有木有觉得很神奇?我们在pom.xml中配置插件往往是这样:
1 <plugin> 2 <groupId>org.apache.maven.pluginsgroupId> 3 <artifactId>maven-compiler-pluginartifactId> 4 <version>3.1version> 5 <configuration> 6 <source>1.7source> 7 <target>1.7target> 8 configuration> 9 plugin>
maven-compiler-plugin插件默认执行的目标为compiler,那么命令的完整写法应该是:mvn org.apache.maven.plugins:maven-compiler-plugin:3.1:compiler才对啊,为什么mvn compiler:compiler也能完美的执行?
我们来看看Maven到底干了些神马来做到如此牛逼的功能:
①插件默认groupId
Maven默认以org.apache.maven.plugins作为groupId,到这里我们的命令应该是长这样的:
mvn org.apache.maven.plugins:compiler:compiler
我们也可以配置自己默认的groupId,在Maven的settings.xml中添加如下内容,前面提过最好将settings.xml放在用户目录的.m2下:
1 <pluginGroups> 2 6 <pluginGroup>com.your.pluginspluginGroup> 7 pluginGroups>
不过说实在的,没必要动他就别去动他了,我们用Maven只是解决一些刚需的问题,没必要的设置就尽量不去动他,别把Maven搞得太复杂,虽然Maven的却有点小复杂,跟大家扯这些只是希望大家能够对maven理解的更深入那么一点点,并不是建议大家一定要去使用某些东西,大家在平时的开发中要谨记这一点。
②我们来看看Maven插件远程仓库的元数据org/apache/maven/plugins/maven-metadata.xml,Maven默认的远程仓库是http://repo.maven.apache.org/maven2/,所有插件元数据路径则是:http://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-metadata.xml,我们找到compiler插件的元数据,如图:
这里会根据prefix指定的前缀找到对应的artifactId,到这里我们的命令应该长成了这样:
mvn org.apache.maven.plugins:maven-compiler-plugin:compiler
③我们再根据groupId和artifactId找到maven-compiler-plugin插件单个的元数据,路径为http://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-compiler-plugin/maven-metadata.xml,如图:
maven将所有的远程插件仓库及本地仓库元数据归并后,就能找到release的版本(maven3后为了保证项目构建的稳定性默认使用release版本),到这里命令就被扩展成为这样:
mvn org.apache.maven.plugins:maven-compiler-plugin:3.6.0:compiler
如果执行的是mvn compiler:compiler命令,由于maven-compiler-plugin的最新版本已经到了3.6.0,则默认会使用此版本。最后的compiler则是插件要执行的目标咯,看到这里大家应该明白mvn compiler:compiler命令为什么能够得到完美的运行了吧。
3.Maven超级POM
最后给大家把超级父POM贴出来,再次强调,如果我们没有在自己的pom.xml中配置相应的内容,则默认会使用超级父POM配置的内容。我现在用的电脑安装的是Maven 3.0.4版本,我们可以找到这个文件:${M2_HOME}/lib/maven-model-builder-3.0.4.jar,打开该文件,能找到超级父POM:\org\apache\maven\model\pom-4.0.0.xml,它是所有Maven POM的父POM,所有Maven项目都继承该配置。
1 xml version="1.0" encoding="UTF-8"?> 2 3 21 22 23 <project> 24 <modelVersion>4.0.0modelVersion> 25 26 <repositories> 27 <repository> 28 <id>centralid> 29 <name>Central Repositoryname> 30 <url>http://repo.maven.apache.org/maven2url> 31 <layout>defaultlayout> 32 <snapshots> 33 <enabled>falseenabled> 34 snapshots> 35 repository> 36 repositories> 37 38 <pluginRepositories> 39 <pluginRepository> 40 <id>centralid> 41 <name>Central Repositoryname> 42 <url>http://repo.maven.apache.org/maven2url> 43 <layout>defaultlayout> 44 <snapshots> 45 <enabled>falseenabled> 46 snapshots> 47 <releases> 48 <updatePolicy>neverupdatePolicy> 49 releases> 50 pluginRepository> 51 pluginRepositories> 52 53 <build> 54 <directory>${project.basedir}/targetdirectory> 55 <outputDirectory>${project.build.directory}/classesoutputDirectory> 56 <finalName>${project.artifactId}-${project.version}finalName> 57 <testOutputDirectory>${project.build.directory}/test-classestestOutputDirectory> 58 <sourceDirectory>${project.basedir}/src/main/javasourceDirectory> 59 <scriptSourceDirectory>src/main/scriptsscriptSourceDirectory> 60 <testSourceDirectory>${project.basedir}/src/test/javatestSourceDirectory> 61 <resources> 62 <resource> 63 <directory>${project.basedir}/src/main/resourcesdirectory> 64 resource> 65 resources> 66 <testResources> 67 <testResource> 68 <directory>${project.basedir}/src/test/resourcesdirectory> 69 testResource> 70 testResources> 71 <pluginManagement> 72 73 74 <plugins> 75 <plugin> 76 <artifactId>maven-antrun-pluginartifactId> 77 <version>1.3version> 78 plugin> 79 <plugin> 80 <artifactId>maven-assembly-pluginartifactId> 81 <version>2.2-beta-5version> 82 plugin> 83 <plugin> 84 <artifactId>maven-dependency-pluginartifactId> 85 <version>2.1version> 86 plugin> 87 <plugin> 88 <artifactId>maven-release-pluginartifactId> 89 <version>2.0version> 90 plugin> 91 plugins> 92 pluginManagement> 93 build> 94 95 <reporting> 96 <outputDirectory>${project.build.directory}/siteoutputDirectory> 97 reporting> 98 99 <profiles> 100 101 <profile> 102 <id>release-profileid> 103 104 <activation> 105 <property> 106 <name>performReleasename> 107 <value>truevalue> 108 property> 109 activation> 110 111 <build> 112 <plugins> 113 <plugin> 114 <inherited>trueinherited> 115 <artifactId>maven-source-pluginartifactId> 116 <executions> 117 <execution> 118 <id>attach-sourcesid> 119 <goals> 120 <goal>jargoal> 121 goals> 122 execution> 123 executions> 124 plugin> 125 <plugin> 126 <inherited>trueinherited> 127 <artifactId>maven-javadoc-pluginartifactId> 128 <executions> 129 <execution> 130 <id>attach-javadocsid> 131 <goals> 132 <goal>jargoal> 133 goals> 134 execution> 135 executions> 136 plugin> 137 <plugin> 138 <inherited>trueinherited> 139 <artifactId>maven-deploy-pluginartifactId> 140 <configuration> 141 <updateReleaseInfo>trueupdateReleaseInfo> 142 configuration> 143 plugin> 144 plugins> 145 build> 146 profile> 147 profiles> 148 149 project> 150
很多插件是超级父POM当中并没有配置的,如果用户使用某个插件时没有设定版本,那么则会根据我上述所说的规则去仓库中查找可用的版本,然后做出选择。在Maven2中,插件的版本会被解析至latest。也就是说,当用户使用某个非核心插件且没有声明版本的时候,Maven会将版本解析为所有可用仓库中的最新版本,latest表示的就是最新版本,而这个版本很有可能是快照版本。
当插件为快照版本时,就会出现潜在的问题。昨天还好好的,可能今天就出错了,其原因是这个快照版本发生了变化导致的。为了防止这类问题,Maven3调整了解析机制,当插件没有声明版本的时候,不再解析至latest,而是使用release。这样就避免了由于快照频繁更新而导致的不稳定问题。但是这样就好了吗?不写版本号其实是不推荐的做法,例如,我使用的插件发布了一个新版本,而这个release版本与之前的版本的行为发生了变化,这种变化依然可能导致我们项目的瘫痪。所以使用插件的时候,应该一直显式的设定版本,这也解释了Maven为什么要在超级父POM中为核心插件设定版本咯。
1.Maven聚合
我们在平时的开发中,项目往往会被划分为好几个模块,比如common公共模块、system系统模块、log日志模块、reports统计模块、monitor监控模块等等。这时我们肯定会出现这么一个需要,我们需要一次构件多个模块,而不用每个模块都去mvn clean install一次,Maven聚合就是用来实现这个需求的。
我们需要构建另外一个模块,假设是UidpWeb,然后通过该模块来构件整个项目的所有模块,POM结构如下:
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/maven-v4_0_0.xsd"> 3 <modelVersion>4.0.0modelVersion> 4 5 <groupId>com.uidpgroupId> 6 <artifactId>UidpWebartifactId> 7 <packaging>pompackaging> 8 <version>0.0.1-SNAPSHOTversion> 9 <name>UidpWebname> 10 <url>http://maven.apache.orgurl> 11 12 <modules> 13 14 15 <module>parentmodule> 16 17 18 <module>ThirdPartymodule> 19 20 21 <module>commonmodule> 22 23 24 <module>log/pom-pack.xmlmodule> 25 26 27 <module>biz/pom-pack.xmlmodule> 28 29 30 <module>customer/pom-pack.xmlmodule> 31 32 33 <module>strategy/pom-pack.xmlmodule> 34 35 36 <module>reports/pom-pack.xmlmodule> 37 38 39 <module>monitor/pom-pack.xmlmodule> 40 41 42 <module>sysmgr/pom-pack.xmlmodule> 43 44 45 <module>/pom-app.xmlmodule> 46 47 modules> 48 49 project>
注释:
为了方便用户构建项目,通常将聚合模块放在项目目录的最顶层,其他模块则作为聚合模块的子目录存在,这时聚合的时候便可如我这般指定路径:
parent
log/pom-pack.xml
这就表示聚合模块下面的parent目录,聚合模块下面的log目录下的pom-pack.xml。
聚合模块下的内容只需要POM文件,它不像其他模块那样有src/main/java、src/test/java等目录。他只是用来帮助聚合其他模块构建,他本身并不会有过多的实质内容。
关于目录结构要注意的是,聚合模块既可以作为其他模块的父目录,也可以与其他模块处于平行的目录,如图:
如果使用平行目录,聚合模块的POM要做相应的修改,以指向正确的模块目录:
../parent
../log/pom-pack.xml
最后运行mvn clean install命令,Maven会分析聚合模块的POM、分析要构建的模块、并计算出一个反应堆构建顺序,然后根据这个顺序依次构建各个模块,这样便可以一次性构建所有聚合的模块。
2.Maven继承
如果多个模块出现相同的依赖包,这样在pom.xml文件的内容出现了冗余、重复的内容,解决这个问题其实使用Maven的继承机制即可,就像Java的继承一样,父类就像一个模板,子类继承自父类,那么有些通用的方法、变量都不必在子类中再重复声明了。Maven的继承机制类似,在一个父级别的Maven的pom文件中定义了相关的常量、依赖、插件等等配置后,实际项目模块可以继承此父项目 的pom文件,重复的项不必显示的再声明一遍了,相当于父Maven项目就是个模板,等着其他子模块去继承。不过父Maven项目要高度抽象,高度提取公共的部分(交集),做到一处声明,多处使用。
与聚合一样我们需要构建另外一个模块,假设是parent,在聚合模块UidpWeb下面创建parent模块,然后通过该模块来作为所有模块的父POM,POM结构如下:
1 <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"> 2 <modelVersion>4.0.0modelVersion> 3 4 <groupId>com.uidpgroupId> 5 <artifactId>UidpParentartifactId> 6 <version>0.0.1-SNAPSHOTversion> 7 <packaging>pompackaging> 8 9 <name>UidpParentname> 10 <url>http://maven.apache.orgurl> 11 12 <properties> 13 <project.build.sourceEncoding>UTF-8project.build.sourceEncoding> 14 15 <repository-url>http://192.168.0.70:8081/content/groups/public/repository-url> 16 17 <maven-compiler-plugin.version>3.1maven-compiler-plugin.version> 18 <maven-war-plugin.version>2.4maven-war-plugin.version> 19 <maven-javadoc-plugin.version>2.9.1maven-javadoc-plugin.version> 20 <maven-release-plugin.version>2.4.1maven-release-plugin.version> 21 <maven-deploy-plugin.version>2.7maven-deploy-plugin.version> 22 23 24 25 <junit.version>4.11junit.version> 26 <oracle.version>10.2.0.4oracle.version> 27 <springframework.version>3.2.8.RELEASEspringframework.version> 28 <mybatis.version>3.2.2mybatis.version> 29 <mybatis-spring.version>1.2.0mybatis-spring.version> 30 <mysql-driver.version>5.1.25mysql-driver.version> 31 <aspectjweaver.version>1.7.3aspectjweaver.version> 32 33 <commons-dbcp.version>1.4commons-dbcp.version> 34 <commons-pool.version>1.5.5commons-pool.version> 35 <commons-fileupload.version>1.2.2commons-fileupload.version> 36 37 <log4j.version>1.2.17log4j.version> 38 <slf4j-api.version>1.7.5slf4j-api.version> 39 <slf4j-log4j12.version>1.7.5slf4j-log4j12.version> 40 41 <freemarker.version>2.3.19freemarker.version> 42 43 <jackson-core.version>2.5.0jackson-core.version> 44 <jackson-mapper-asl.version>1.9.7jackson-mapper-asl.version> 45 46 <javax.servlet-api.version>3.0.1javax.servlet-api.version> 47 <jsp-api.version>2.2jsp-api.version> 48 <kryo.version>1.04kryo.version> 49 <snakeyaml.version>1.8snakeyaml.version> 50 <jedis.version>2.0.0jedis.version> 51 <commons-lang.version>2.6commons-lang.version> 52 53 54 <mockito-core.version>1.8.5mockito-core.version> 55 <powermock-core.version>1.4.9powermock-core.version> 56 <powermock-api-mockito.version>1.4.9powermock-api-mockito.version> 57 <powermock-module-junit4.version>1.4.9powermock-module-junit4.version> 58 59 60 properties> 61 62 <dependencyManagement> 63 <dependencies> 64 65 <dependency> 66 <groupId>junitgroupId> 67 <artifactId>junitartifactId> 68 <version>${junit.version}version> 69 <scope>testscope> 70 dependency> 71 72 73 <dependency> 74 <groupId>org.springframeworkgroupId> 75 <artifactId>spring-webartifactId> 76 <version>${springframework.version}version> 77 dependency> 78 79 <dependency> 80 <groupId>org.springframeworkgroupId> 81 <artifactId>spring-webmvcartifactId> 82 <version>${springframework.version}version> 83 dependency> 84 85 <dependency> 86 <groupId>org.springframeworkgroupId> 87 <artifactId>spring-beansartifactId> 88 <version>${springframework.version}version> 89 dependency> 90 91 <dependency> 92 <groupId>org.springframeworkgroupId> 93 <artifactId>spring-contextartifactId> 94 <version>${springframework.version}version> 95 dependency> 96 97 <dependency> 98 <groupId>org.springframeworkgroupId> 99 <artifactId>spring-context-supportartifactId> 100 <version>${springframework.version}version> 101 dependency> 102 103 <dependency> 104 <groupId>org.springframeworkgroupId> 105 <artifactId>spring-coreartifactId> 106 <version>${springframework.version}version> 107 dependency> 108 109 <dependency> 110 <groupId>org.springframeworkgroupId> 111 <artifactId>spring-jdbcartifactId> 112 <version>${springframework.version}version> 113 dependency> 114 115 <dependency> 116 <groupId>org.springframeworkgroupId> 117 <artifactId>spring-txartifactId> 118 <version>${springframework.version}version> 119 dependency> 120 121 <dependency> 122 <groupId>org.springframeworkgroupId> 123 <artifactId>spring-testartifactId> 124 <version>${springframework.version}version> 125 dependency> 126 127 <dependency> 128 <groupId>org.springframeworkgroupId> 129 <artifactId>spring-expressionartifactId> 130 <version>${springframework.version}version> 131 dependency> 132 133 <dependency> 134 <groupId>org.springframeworkgroupId> 135 <artifactId>spring-aopartifactId> 136 <version>${springframework.version}version> 137 dependency> 138 139 140 <dependency> 141 <groupId>org.mybatisgroupId> 142 <artifactId>mybatisartifactId> 143 <version>${mybatis.version}version> 144 dependency> 145 146 <dependency> 147 <groupId>org.mybatisgroupId> 148 <artifactId>mybatis-springartifactId> 149 <version>${mybatis-spring.version}version> 150 dependency> 151 152 <dependency> 153 <groupId>mysqlgroupId> 154 <artifactId>mysql-connector-javaartifactId> 155 <version>${mysql-driver.version}version> 156 dependency> 157 158 <dependency> 159 <groupId>com.oraclegroupId> 160 <artifactId>ojdbc14artifactId> 161 <version>${oracle.version}version> 162 dependency> 163 164 <dependency> 165 <groupId>org.aspectjgroupId> 166 <artifactId>aspectjweaverartifactId> 167 <version>${aspectjweaver.version}version> 168 dependency> 169 170 171 <dependency> 172 <groupId>commons-dbcpgroupId> 173 <artifactId>commons-dbcpartifactId> 174 <version>${commons-dbcp.version}version> 175 dependency> 176 <dependency> 177 <groupId>commons-poolgroupId> 178 <artifactId>commons-poolartifactId> 179 <version>${commons-pool.version}version> 180 dependency> 181 <dependency> 182 <groupId>commons-fileuploadgroupId> 183 <artifactId>commons-fileuploadartifactId> 184 <version>${commons-fileupload.version}version> 185 dependency> 186 187 188 189 <dependency> 190 <groupId>log4jgroupId> 191 <artifactId>log4jartifactId> 192 <version>${log4j.version}version> 193 dependency> 194 <dependency> 195 <groupId>org.slf4jgroupId> 196 <artifactId>slf4j-apiartifactId> 197 <version>${slf4j-api.version}version> 198 dependency> 199 <dependency> 200 <groupId>org.slf4jgroupId> 201 <artifactId>slf4j-log4j12artifactId> 202 <version>${slf4j-log4j12.version}version> 203 dependency> 204 205 206 <dependency> 207 <groupId>org.freemarkergroupId> 208 <artifactId>freemarkerartifactId> 209 <version>${freemarker.version}version> 210 dependency> 211 212 213 214 <dependency> 215 <groupId>com.fasterxml.jackson.coregroupId> 216 <artifactId>jackson-coreartifactId> 217 <version>${jackson-core.version}version> 218 dependency> 219 <dependency> 220 <groupId>org.codehaus.jacksongroupId> 221 <artifactId>jackson-mapper-aslartifactId> 222 <version>${jackson-mapper-asl.version}version> 223 dependency> 224 225 <dependency> 226 <groupId>javax.servletgroupId> 227 <artifactId>javax.servlet-apiartifactId> 228 <version>${javax.servlet-api.version}version> 229 <scope>providedscope> 230 dependency> 231 232 <dependency> 233 <groupId>javax.servlet.jspgroupId> 234 <artifactId>jsp-apiartifactId> 235 <version>${jsp-api.version}version> 236 <scope>providedscope> 237 dependency> 238 239 <dependency> 240 <groupId>com.googlecodegroupId> 241 <artifactId>kryoartifactId> 242 <version>${kryo.version}version> 243 dependency> 244 245 <dependency> 246 <groupId>org.yamlgroupId> 247 <artifactId>snakeyamlartifactId> 248 <version>${snakeyaml.version}version> 249 dependency> 250 251 <dependency> 252 <groupId>redis.clientsgroupId> 253 <artifactId>jedisartifactId> 254 <version>${jedis.version}version> 255 dependency> 256 257 <dependency> 258 <groupId>commons-langgroupId> 259 <artifactId>commons-langartifactId> 260 <version>${commons-lang.version}version> 261 dependency> 262 263 264 <dependency> 265 <groupId>org.mockitogroupId> 266 <artifactId>mockito-coreartifactId> 267 <version>${mockito-core.version}version> 268 <scope>testscope> 269 dependency> 270 271 <dependency> 272 <groupId>org.powermockgroupId> 273 <artifactId>powermock-coreartifactId> 274 <version>${powermock-core.version}version> 275 <scope>testscope> 276 dependency> 277 278 <dependency> 279 <groupId>org.powermockgroupId> 280 <artifactId>powermock-api-mockitoartifactId> 281 <version>${powermock-api-mockito.version}version> 282 <scope>testscope> 283 dependency> 284 285 <dependency> 286 <groupId>org.powermockgroupId> 287 <artifactId>powermock-module-junit4artifactId> 288 <version>${powermock-module-junit4.version}version> 289 <scope>testscope> 290 dependency> 291 292 293 dependencies> 294 dependencyManagement> 295 296 <distributionManagement> 297 <repository> 298 <id>releasesid> 299 <name>publicname> 300 <url>http://59.50.95.66:8081/nexus/content/repositories/releasesurl> 301 repository> 302 <snapshotRepository> 303 <id>snapshotsid> 304 <name>Snapshotsname> 305 <url>http://59.50.95.66:8081/nexus/content/repositories/snapshotsurl> 306 snapshotRepository> 307 distributionManagement> 308 309 310 311 <build> 312 <plugins> 313 314 <plugin> 315 <groupId>org.apache.maven.pluginsgroupId> 316 <artifactId>maven-compiler-pluginartifactId> 317 <version>${maven-compiler-plugin.version}version> 318 <configuration> 319 <source>1.7source> 320 <target>1.7target> 321 configuration> 322 plugin> 323 324 <plugin> 325 <groupId>org.apache.maven.pluginsgroupId> 326 <artifactId>maven-javadoc-pluginartifactId> 327 <version>${maven-javadoc-plugin.version}version> 328 plugin> 329 330 331 <plugin> 332 <groupId>org.apache.maven.pluginsgroupId> 333 <artifactId>maven-release-pluginartifactId> 334 <version>${maven-release-plugin.version}version> 335 plugin> 336 337 <plugin> 338 <groupId>org.apache.maven.pluginsgroupId> 339 <artifactId>maven-deploy-pluginartifactId> 340 <version>${maven-deploy-plugin.version}version> 341 <configuration> 342 <updateReleaseInfo>trueupdateReleaseInfo> 343 configuration> 344 plugin> 345 346 347 348 plugins> 349 build> 350 351 352 <pluginRepositories> 353 <pluginRepository> 354 <id>nexusid> 355 <name>nexusname> 356 <url>http://192.168.0.70:8081/content/groups/public/url> 357 <releases> 358 <enabled>trueenabled> 359 releases> 360 <snapshots> 361 <enabled>trueenabled> 362 snapshots> 363 pluginRepository> 364 pluginRepositories> 365 366 367 project>
需要注意的是,他的packaging和聚合一样为pom,作为父模块的pom,其打包类型必须为pom。父模块只是为了帮助消除配置的重复,因此他本身不包含除POM的项目文件,也就不需要src/main/java之类的文件夹了。
有了父模块,就需要让其他模块来继承它,我们来看个实际的例子:
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/maven-v4_0_0.xsd"> 3 <modelVersion>4.0.0modelVersion> 4 5 <parent> 6 <groupId>com.uidpgroupId> 7 <artifactId>UidpParentartifactId> 8 <version>0.0.1-SNAPSHOTversion> 9 parent> 10 11 <groupId>com.uidpgroupId> 12 <artifactId>logartifactId> 13 <packaging>warpackaging> 14 <version>0.0.1-SNAPSHOTversion> 15 <name>logname> 16 <url>http://maven.apache.orgurl> 17 18 <dependencies> 19 20 <dependency> 21 <artifactId>ThirdPartyartifactId> 22 <version>0.0.1-SNAPSHOTversion> 23 <groupId>${project.parent.groupId}groupId> 24 <type>wartype> 25 dependency> 26 27 <dependency> 28 <groupId>com.uidpgroupId> 29 <artifactId>WebCommonartifactId> 30 <version>0.0.1-SNAPSHOTversion> 31 dependency> 32 33 <dependency> 34 <groupId>junitgroupId> 35 <artifactId>junitartifactId> 36 <scope>testscope> 37 dependency> 38 39 <dependency> 40 <groupId>org.aspectjgroupId> 41 <artifactId>aspectjweaverartifactId> 42 dependency> 43 44 45 <dependency> 46 <groupId>org.springframeworkgroupId> 47 <artifactId>spring-webartifactId> 48 dependency> 49 <dependency> 50 <groupId>org.springframeworkgroupId> 51 <artifactId>spring-webmvcartifactId> 52 dependency> 53 <dependency> 54 <groupId>org.springframeworkgroupId> 55 <artifactId>spring-beansartifactId> 56 dependency> 57 <dependency> 58 <groupId>org.springframeworkgroupId> 59 <artifactId>spring-contextartifactId> 60 dependency> 61 <dependency> 62 <groupId>org.springframeworkgroupId> 63 <artifactId>spring-context-supportartifactId> 64 dependency> 65 <dependency> 66 <groupId>org.springframeworkgroupId> 67 <artifactId>spring-coreartifactId> 68 dependency> 69 <dependency> 70 <groupId>org.springframeworkgroupId> 71 <artifactId>spring-jdbcartifactId> 72 dependency> 73 <dependency> 74 <groupId>org.springframeworkgroupId> 75 <artifactId>spring-txartifactId> 76 dependency> 77 <dependency> 78 <groupId>org.springframeworkgroupId> 79 <artifactId>spring-testartifactId> 80 dependency> 81 <dependency> 82 <groupId>org.springframeworkgroupId> 83 <artifactId>spring-expressionartifactId> 84 dependency> 85 <dependency> 86 <groupId>org.springframeworkgroupId> 87 <artifactId>spring-aopartifactId> 88 dependency> 89 90 91 92 <dependency> 93 <groupId>org.quartz-schedulergroupId> 94 <artifactId>quartzartifactId> 95 <version>1.8.6version> 96 dependency> 97 98 99 <dependency> 100 <groupId>org.mybatisgroupId> 101 <artifactId>mybatisartifactId> 102 dependency> 103 104 <dependency> 105 <groupId>org.mybatisgroupId> 106 <artifactId>mybatis-springartifactId> 107 dependency> 108 109 110 <dependency> 111 <groupId>mysqlgroupId> 112 <artifactId>mysql-connector-javaartifactId> 113 dependency> 114 115 116 <dependency> 117 <groupId>commons-dbcpgroupId> 118 <artifactId>commons-dbcpartifactId> 119 dependency> 120 <dependency> 121 <groupId>commons-poolgroupId&g