- 浏览: 1588547 次
- 性别:
- 来自: 苏州
文章分类
最新评论
-
payton321:
dao,util,servie,基础模块应该是maven项目, ...
Maven最佳实践:划分模块 -
AdrainHuang:
深有体会,我这边已经 给项目坑死了,依赖关系太复杂,基本没人敢 ...
Maven最佳实践:管理依赖 -
远方_张涛:
赞赞赞,生动有趣还说明问题
Maven最佳实践:版本管理 -
smartdog:
新的网站访问不了啊~~博主快更新
再见JavaEye -
smartdog:
言简意赅,厉害
Maven最佳实践:遵循约定
"If I have seen further it is by standing on the shoulders of Giants" —— Isaac Newton (1642-1727)
有人认为Maven是一个依赖管理工具,当然这种想法是错误的(确切的说Maven是一个项目管理工具,贯穿了整个项目生命周期,编译,测试,打包,发布...),但Maven给人造成这种错误的印象也是有原因的,因为Maven的依赖管理十分强大,用好了Maven,你不再需要面对一大堆jar感到头大,依赖冲突,无用依赖等问题也能够得到有效的防止和解决。本节介绍如何用好Maven的依赖管理。
最简单的依赖
依赖是使用Maven坐标来定位的,而Maven坐标主要由GAV(groupId, artifactId, version)构成。因此,使用任何一个依赖之间,你都需要知道它的Maven坐标,关于如何寻找Maven坐标,《搜索Maven仓库》 一文可以帮助你。
最简单的依赖如:
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.4</version> </dependency>
上例中我们声明了一个对junit的依赖,它的groupId是junit, artifactId是junit, version是4.4。这一组GAV构成了一个Maven坐标,基于此,Maven就能在本地或者远程仓库中找到对应的junit-4.4.jar文件。
依赖归类
随着项目的增大,你的依赖越来越多,比如说你依赖了一堆spring的jar,有org.spring.framework:spring-core, org.spring.framework:beans, org.spring.framework:spring-web, org.spring.framework:spring-mock。它们的groupId是相同的,artifactId不同。为了管理其版本,你对它们进行过统一的升级,逐个的将version改成了最新版。但是,显然,当POM很大的时候你说不定会犯错误,而当版本不一致的时候,一些诡异的兼容性问题就可能出现。
对此,Maven有它的解决方案:
<dependencies> <dependency> <groupId>org.spring.framework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.spring.framework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.spring.framework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.spring.framework</groupId> <artifactId>spring-mock</artifactId> <version>${spring.version}</version> </dependency> </dependencies> <properties> <spring.version>2.5</spring.version> </properties>
这里我们定义了一个Maven属性,其名称为spring.version,值是2.5。在这个POM中,我们就能用${spring.version}的方式来引用该属性。我们看到,所有spring相关的依赖的version元素现在都成了${spring.version},当Maven运行的时候,它会自动用值2.5来替换这个引用。
当我们需要升级spring的时候,只要更改一个地方便可,而且,你现在能很高的保证所有的spring依赖包都是同一个版本。
依赖范围(scope)
本文的第一个例子其实是有漏洞的,对于Junit,一般来说你只有在运行测试的时候需要它,也就是说,它对于src/main/java的classpath没什么意义,并且,将Junit的jar文件打入最终的发布包也不是好事,这无谓的增加了发布包的大小。
其实我们应该这样做:
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.4</version> <scope>test</test> </dependency>
于是,junit对于主源码classpath不可用,对于测试源码classpath可用,不会被打包。
再举个例子,在开发javaee应用的时候我们一定会用到servlet-api,它对于主源码和测试源码都是必要的,因为我们的代码中会引入servlet-api的包。但是,在打包的时候,将其放入WAR包就会有问题,因为web容器会提供servlet-api,如果我们再将其打包就会造成依赖冲突,解决方案如下:
<dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.4</version> <scope>provided</scope> </dependency>
将依赖范围设置成provided,就意味着该依赖对于主源码classpath,以及测试classpath可用,但不会被打包。这正是servlet-api所需要的。
这里归纳一下主要的依赖范围以及作用:
依赖范围(scope) | 主源码classpath可用 | 测试源码classpath可用 | 会被打包 |
compile 缺省值 | TRUE | TRUE | TRUE |
test | FALSE | TRUE | FALSE |
runtime | FALSE | TRUE | TRUE |
provided | TRUE | TRUE | FALSE |
需要注意的是,当我们没有声明依赖范围的时候,其默认的依赖范围是compile。
分类器(classifer)
GAV是Maven坐标最基本最重要的组成部分,但GAV不是全部。还有一个元素叫做分类器(classifier),90%的情况你不会用到它,但有些时候,分类器非常不可或缺。
举个简单的例子,当我们需要依赖TestNG的时候,简单的声明GAV会出错,因为TestNG强制需要你提供分类器,以区别jdk14和jdk15,我们需要这样声明对TestNG的依赖:
<dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>5.7</version> <classifier>jdk15</classifier> </dependency>
你会注意到maven下载了一个名为testng-5.7-jdk15.jar的文件。其命名模式实际上是<artifactId>-<version>-<classifier>.<packaging>。理解了这个模式以后,你就会发现很多文件其实都是默认构件的分类器扩展,如 myapp-1.0-test.jar, myapp-1.0-sources.jar。
分类器还有一个非常有用的用途是:我们可以用它来声明对test构件的依赖,比如,我们在一个核心模块的src/test/java中声明了一些基础类,然后我们发现这些测试基础类对于很多其它模块的测试类都有用。没有分类器,我们是没有办法去依赖src/test/java中的内容的,因为这些内容不会被打包到主构件中,它们单独的被打包成一个模式为<artifactId>-<version>-test.jar的文件。
我们可以使用分类器来依赖这样的test构件:
<dependency> <groupId>org.myorg.myapp</groupId> <artifactId>core</artifactId> <version>${project.version}</version> <classifier>test</classifier> </dependency>
理解了分类器,那么可供依赖的资源就变得更加丰富。
依赖管理(dependencyManagement)
当你只有一个Maven模块的时候,你完全不需要看这个部分。但你心里应该清楚,只有一个Maven模块的项目基本上只是个玩具。
实际的项目中,你会有一大把的Maven模块,而且你往往发现这些模块有很多依赖是完全项目的,A模块有个对spring的依赖,B模块也有,它们的依赖配置一模一样,同样的groupId, artifactId, version,或者还有exclusions, classifer。细心的分会发现这是一种重复,重复就意味着潜在的问题,Maven提供的dependencyManagement就是用来消除这种重复的。
正确的做法是:
1. 在父模块中使用dependencyManagement配置依赖
2. 在子模块中使用dependencies添加依赖
dependencyManagement实际上不会真正引入任何依赖,dependencies才会。但是,当父模块中配置了某个依赖之后,子模块只需使用简单groupId和artifactId就能自动继承相应的父模块依赖配置。
这里是一个来自于《Maven权威指南》的例子:
父模块中如此声明:
<project> <modelVersion>4.0.0</modelVersion> <groupId>org.sonatype.mavenbook</groupId> <artifactId>a-parent</artifactId> <version>1.0.0</version> ... <dependencyManagement> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.2</version> </dependency> ... <dependencies> </dependencyManagement>
子模块中如此声明:
<project> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.sonatype.mavenbook</groupId> <artifactId>a-parent</artifactId> <version>1.0.0</version> </parent> <artifactId>project-a</artifactId> ... <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies> </project>
你依赖配置越复杂,依赖管理所起到的作用就越大,它不仅能够帮助你简化配置,它还能够帮你巩固依赖配置,也就是说,在整个项目中,对于某个构件(如mysql)的依赖配置只有一种,这样就能避免引入不同版本的依赖,避免依赖冲突。
小结
本文讲述了一些Maven依赖中重要的概念,并通过样例提供了一些最佳实践,如依赖归类,依赖范围,分类器,以及依赖管理。我的目的是通过浅显的例子讲述那些你实际工作中会需要了解的80%的内容,如果你需要更深入的了解,请参考《Maven权威指南》 。
评论
<dependencySet>
<includes>
<include>apache-log4j:log4j:jar:1.2.13</include>
</includes>
<outputDirectory>
local/3rdParty/log4j/1_2_13
</outputDirectory>
<outputFileNameMapping>log4j.jar</outputFileNameMapping>
</dependencySet>
只在版本号和输出路径上有所区别,但是只下载了高版本的,请问如何 解决呢?
发表评论
-
我的书《Maven实战》
2010-11-12 13:09 69935我本来已经决定停止更新该博客了,但是为了推广下我的新书《Mav ... -
m2eclipse 0.10.0发布
2010-02-22 17:34 7953本文译自 http://www.sonatyp ... -
按需构建多模块,玩转Maven反应堆
2010-01-07 19:57 29447在多模块Maven项目中,反应堆(Reactor)是一个包含了 ... -
Maven仓库的布局
2009-12-14 08:54 11844注:本文节选自我正在 ... -
Maven3初窥
2009-11-10 16:28 20651Maven3的开发已经完成大半,本周末将发布alpha-3(T ... -
Nexus 1.4.0 发布
2009-10-29 17:22 6120新完成的用户故事: [ NEXUS-463] - ... -
archtype:generate出错?
2009-10-12 00:10 8088我们常常会使用mvn archet ... -
你最常用的构建和发布管理工具是什么?
2009-09-13 15:03 12917最近Eclipse社区进行了一项调查,关注社区如何使用Ecli ... -
策划编写《Maven实战》——初步目录
2009-09-09 03:42 81422010-08-27更新 关注 ... -
Maven最佳实践:持续集成
2009-08-21 17:14 0test -
Maven最佳实践:集成web容器
2009-08-21 17:13 0test -
《Maven权威指南》完整发布,带官方PDF
2009-07-06 00:45 673782010/04/29更新 :我已 ... -
Nexus Indexer 2.0:增量下载
2009-05-14 16:33 10209原文:http://www.sonatype.com/peop ... -
Maven最佳实践:版本管理
2009-04-29 00:04 124610什么是版本管理 首先,这里说的版本管理(version ma ... -
Maven最佳实践:Maven仓库
2009-04-01 17:42 110744什么是Maven仓库 在不用M ... -
Maven中央仓库的中国镜像
2009-03-31 22:53 45875(2011-01-27更新,由于私人原因,该镜像已关闭,在此致 ... -
Nexus入门指南(图文)
2009-03-15 23:07 147399Nexus介绍 Nexus 是Maven仓 ... -
“第十七章 编写插件” 发布
2009-03-09 17:16 3856又是漫长的一章内容,但如同本书的任何一章一样,由于原作者都是M ... -
m2e:为Eclipse引入Maven(下)
2009-02-04 16:19 30283译自:http://www.sonatype.co ... -
m2e:为Eclipse引入Maven(上)
2009-02-04 14:10 12680译自:http://www.sonatype.co ...
相关推荐
附件为在阅读Maven实战时为依赖的最佳实践进行总结而输出的博客。一面加深理解,也希望能帮助需要的人
何为Maven 构建,依赖管理,项目信息聚合 Maven核心概念 坐标,依赖,仓库,生命周期,插件 Maven最佳实践 创建、打包、发布、版本管理 项目实战 Nexus(Todo…) M2eclipse(Todo…)
dependencyManagement 是表⽰依赖 jar 包的声明,即你在项⽬中的 dependencyManagement 下声明了依赖,maven 不会加 载该依赖,dependencyManagement 声明可以被继承。 dependencyManagement 的⼀个使⽤案例是当有⽗...
今天小编就为大家分享一篇关于Maven最佳实践之一个好的parent依赖基础,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
此外,课程还将介绍Maven的高级主题,包括多模块项目的构建、构建配置的定制化、以及集成到持续集成/持续部署(CI/CD)流程中的最佳实践。通过本课程的学习,学员将能够熟练运用Maven进行项目开发,掌握Maven在不同...
第5章:坐标和依赖/5.9 最佳实践/5.9.2 依赖属性使用变量 第5章:坐标和依赖/5.9 最佳实践/5.9.3 依赖关系查看 第6章:仓库/6.1 何为Maven仓库 第6章:仓库/6.2 仓库的布局 第6章:仓库/6.3 仓库的分类 第6章:仓库/...
除此之外,"简化工作,使用业界公认的最佳实践"也是是 Maven2 的另一大主题,其他的新特性无处不在体现 Maven2 为简化工作而做出的努力。 2. 更少的配置文件 Maven1 和 Maven2 主要配置文件的对比: • Maven1:...
作为apache组织中的一个颇为成功的开源项目,maven主要服务于基于 java平台的项目构建、依赖管理和项目信息管理。 maven能干什么 使项目构建构成更容易; 提供统一构建系统(编译、测试、持续整合...); 提供高质量...
POM最佳实践 9.6.1. 依赖归类 9.6.2. 多模块 vs. 继承 9.6.2.1. 简单项目 9.6.2.2. 多模块企业级项目 9.6.2.3. 原型父项目 10. 构建生命周期 10.1. 简介 10.1.1. 清理生命周期 (clean) 10.1.2. 默认...
HOME2.3.2 ~/.m22.4 设置http代理2.5 安装m2eclipse2.6 安装netbeans maven插件2.7 maven安装最佳实践2.7.1 设置maven_opts环境变量2.7.2 配置用户范围settings?xml2.7.3 不要使用ide内嵌的maven2.8 小结第...
•最佳实践:代码结构| @Configuration | @EnableAutoConfiguration | Beans和依赖注入 •运行代码: IDE |打包| Maven | Gradle •包装应用程序: 生产jar •Spring Boot CLI: 使用CLI •核心特性: SpringApplication ...
Apache Maven 是一个软件项目管理和依赖管理工具。基于项目对象模型(POM:Project Object Model)的概念,Maven 可以从一个中心信息块管理项目的构建、报告和文档。 无论是小型的开源类库项目,还是大型的企业级...
基于Spring Boot的医药管理系统是一个针对药店或...总之,该医药管理系统通过整合现代Java开发的最佳实践,提供了一个健壮、可扩展且易于维护的解决方案,适用于毕业设计项目,能够展示学生在软件开发方面的综合能力。
docker-maven-plugin:直接生成Dockerfile(本地需更换成阿里云层叠,速度和成功率会提升很多) H2:内存式数据库,减少数据库依赖(正式环境时,可以直接切换至MYSQL) spring cloud eureka:用于服务注册发现 ...
掌握快速开发、前端界面设计和数据库操作,学习最佳实践和定制扩展。提供实用项目基础,培养综合能力。适合学习和实践,助力我们快速构建高效后台管理系统。 运行环境 Jdk8+IntelliJ IDEA+Maven 项目技术(必填) ...
Maven的主要功能:1、遵循最佳实践的简单项目设置-数秒内即可启动新项目或模块。2、所有项目的用法一致-意味着新开发人员无需花更多时间来参与项目。3、高级依赖性管理,包括自动更新,依赖性关闭(也称为传递依赖性...
REST JAX-RS CXF Spring 最佳实践模板。 描述 从非持久内存数据存储中添加、检索和删除存储的示例应用程序。 PUT - 使用客户端提供的 ID 添加或更新存储 GET - 获取商店 DELETE - 删除存储 特征 多模块maven项目 ...
java二手书交易源码最佳性能实践 Hibernate 5/6 和 Spring Boot 2 Hibernate 和 Spring Boot 示例 说明:此应用程序是如何在 UTC 时区中存储日期、时间和时间戳的示例。 第二个设置useLegacyDatetimeCode只有 MySQL ...
通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源...