学习笔记——Maven实战(二)POM重构之增还是删
重构是广大开发者再熟悉不过的技术,在Martin Fowler的《重构——改善既有代码的设计》一书中,其定义为“重构(名词):对软件内部结构的一种调整,目的是在不改变软件之可察行为前提下,提高其可理解性,降低其修改成本.”以及“重构(动词):使用一系列重构准则(手法),在不改变软件之可察行为前提下,调整其结构.”。重构能够改善软件设计,使代码更易读,更容易找出bug,并帮助你更快速地编码。较之于一般的代码来说,Maven的POM简单很多,不过随着项目的成长,模块的增多,POM的内容也会变多,这个时候,我们可以对POM进行重构,在保持构建成功的前提下,简化POM内容,使其更简洁易懂。
前提
大家都知道,如果没有单元测试为前提,对代码进行重构是非常危险的。同样,在重构POM之前,项目应该有足够的自动化测试保证POM重构不会破坏构建。例如,重构POM的时候可能会删除或添加依赖,造成依赖版本变化,依赖范围变化,插件版本变化等等,这些变化可能会导致项目编译失败,或者测试失败。在自动化测试及构建的基础上,最好能够有持续集成环境,以保证POM的修改可能造成的问题能够及时的被发现和修复。笔者目前工作的项目有一个对应的持续集成任务,该任务基于Hudson,每10分钟检查一次SCM,如果发现变更则构建项目,并反馈结果。这样,我就不用担心自己修改POM会引入潜在的问题。
增还是删
有时候这个答案是很显然的,当你的POM中存在一些依赖或者插件配置,但实际代码没有用到这些配置的时候,应该尽早删掉它们以免给人带来困惑。
还有一种常见的情况,我们可以删掉一些POM的元素,例如POM中配置了继承,当前模块与父模块使用同样的groupId和version时,就可以将<groupId>和<version>元素删除,因为它们可以从父模块继承而来,重复配置没有什么意义。
<project>
<modelVersion>4.0.</modelVersion>
<parent>
<groupId>com.juvenxu.sample</groupId>
<artifactId>sample-parent</artifactId>
<version>0.0.-SNAPSHOT</version>
</parent>
<artifactId>sample-foo</artifactId>
<packaging>jar</packaging>
...
</project>
上述配置就sample-foo就没有groupId和version,需要注意的是,artifactId是不能被删除的,因为该元素不能也不应该被继承,父子模块应当使用不同的artifactId值。
除了删之外,有些时候我们还需要在POM中增加一些XML元素,目的是为了让POM更清晰易读,且保证Maven构建的稳定性。考虑如下的插件配置:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
虽然没有groupId及version,但这段配置是完全合法的。当插件没有groupId配置的时候,Maven会认为它是官方插件而自动使用org.apache.maven.plugins作为groupId,当插件没有version配置的时候,Maven则会使用最新的版本(Maven 2会使用最新的版本,包括SNAPSHOT,而Maven 3则只使用最新的非SNAPSHOT版本)。这段配置有两个问题,首先,如果让一个不熟悉Maven的开发者来看这段配置,他会感到费解,groupId和version究竟是什么呢?这与不清晰的代码是一个意思,有时候一些程序员为了让代码更短,会采用一些奇怪的语法和变量名,虽然代码量是少了,但沟通成本增加了,得不偿失。其次,让Maven猜测版本会有潜在的风险,因为插件的最新版本可能会变化,而这种变化对于Maven使用者来说通常是隐藏的,特别是在Maven 2中,甚至可能引入SNAPSHOT版本的插件,这是非常危险的。基于这两个原因,使用插件的时候,我们应当配置清楚groupId和version,如:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
基于类似的原因,在配置项目依赖的时候,我们也应当一直显式地写明依赖版本,以避免Maven在不同的时刻引入不同版本的依赖而导致项目构建的不稳定。
除了上面提到的增删点之外,Maven官方还提供了一个非常有用的Maven Dependency Plugin来帮助我们分析项目中哪些依赖配置应该删除,那些依赖配置应该增加。Maven Dependency Plugin的analyze目标能够帮助分析项目依赖,例如运行命令 mvn dependency:analyze ,可以看到如下输出:
[INFO] --- maven-dependency-plugin:2.1:analyze (default-cli) @ sample-bar ---
[WARNING] Used undeclared dependencies found:
[WARNING] org.springframework:spring-context:jar:2.5.:compile
[WARNING] Unused declared dependencies found:
[WARNING] org.springframework:spring-core:jar:2.5.:compile
[WARNING] org.springframework:spring-beans:jar:2.5.:compile
[INFO] ------------------------------------------------------------------------
这里的 Used undeclared dependencies 是指那些在项目中直接使用到的,但没有在POM中配置的依赖。例如该例中可能项目中的一些类有关于spring-context的Java import声明,但spring-context这个依赖实际是通过传递性依赖进入classpath的,这就意味者潜在的风险。一般来说我们对直接依赖的版本变化会比较清楚,因为那是我们自己直接配置的,但对于传递性依赖的版本变化,就会比较模糊,当这种变化造成构建失败的时候,就很难找到原因。因此我们应当增加这些 Used undeclared dependencies 。
依赖分析还提供了 Unused declared dependencies 供我们参考,这表示那些我们配置了,但并未直接使用的依赖。需要注意的时,对于这些依赖,我们不该直接简单地删除。由于dependency:analyze只分析编译主代码和测试代码使用的依赖,一些执行测试和运行时的依赖它发现不了,因此还需要人工分析。通常情况,Unused declared dependencies 还是能帮助我们发现一些无用的依赖配置。
最后,还一些重要的POM内容通常被大多数项目所忽略,这些内容不会影响项目的构建,但能方便信息的沟通,它们包括项目URL,开发者信息,SCM信息,持续集成服务器信息等等,这些信息对于开源项目来说尤其重要。对于那些想了解项目的人来说,这些信息能他们帮助找到想要的信息,基于这些信息生成的Maven站点也更有价值。相关的POM配置很简单,如:
<project>
<description>...</description>
<url>...</url>
<licenses>...</licenses>
<organization>...</organization>
<developers>...</developers>
<issueManagement>...</issueManagement>
<ciManagement>...</ciManagement>
<mailingLists>...</mailingLists>
<scm>...</scm>
</project>
小结
无论是对POM内容进行增还是删,其目的都是一样的,就是为了让POM更清晰易懂且让构建更稳定。从这点来说,POM重构与一般的代码重构是类似的。需要谨记的是,重构的前提是完善的自动化测试和持续集成。本文介绍的单个POM规模的重构,下篇文章笔者会介绍多模块项目的POM重构等内容。
关于作者
许晓斌(Juven Xu),国内社区公认的Maven技术专家、Maven中文用户组创始人、Maven技术的先驱和积极推动者。对Maven有深刻的认识,实战经验丰富,不仅撰写了大量关于Maven的技术文章,而且还翻译了开源书籍《Maven权威指南》,对Maven技术在国内的普及和发展做出了很大的贡献。就职于Maven之父的公司,负责维护Maven中央仓库,是Maven仓库管理器Nexus(著名开源软件)的核心开发者之一,曾多次受邀到淘宝等大型企业开展Maven方面的培训。此外,他还是开源技术的积极倡导者和推动者,擅长Java开发和敏捷开发实践。他的个人网站是:http://www.juvenxu.com。
来源:http://www.infoq.com/cn/news/2010/12/xxb-maven-2-pom
学习笔记——Maven实战(二)POM重构之增还是删的更多相关文章
- 学习笔记——Maven实战(三)多模块项目的POM重构
重复,还是重复 程序员应该有狗一般的嗅觉,要能嗅到重复这一最常见的坏味道,不管重复披着怎样的外衣,一旦发现,都应该毫不留情地彻底地将其干掉.不要因为POM不是产品代码而纵容重复在这里发酵,例如这样一段 ...
- 学习笔记——Maven实战(六)Gradle,构建工具的未来?
Maven面临的挑战 软件行业新旧交替的速度之快往往令人咂舌,不用多少时间,你就会发现曾经大红大紫的技术已经成为了昨日黄花,当然,Maven也不会例外.虽然目前它基本上是Java构建的事实标准,但我们 ...
- 学习笔记——Maven实战(七)常用Maven插件介绍(上)
我们都知道Maven本质上是一个插件框架,它的核心并不执行任何具体的构建任务,所有这些任务都交给插件来完成,例如编译源代码是由maven-compiler-plugin完成的.进一步说,每个任务对应了 ...
- 学习笔记-[Maven实战]-第三章:Maven使用入门(1)
说明:[Maven实战]一书还介绍了怎么样手工创建Maven工程,学习这本书是为了能尽快在工作中使用,就忽略了手工建工程的部分 如果想了解这部分的内容,可以自己看看书 开始: 1.新建一个maven工 ...
- 学习笔记——Maven实战(四)基于Maven的持续集成实践
Martin的<持续集成> 相信很多读者和我一样,最早接触到持续集成的概念是来自Martin的著名文章<持续集成>,该文最早发布于2000年9月,之后在2006年进行了一次修订 ...
- 学习笔记——Maven实战(八)常用Maven插件介绍(下)
我们都知道Maven本质上是一个插件框架,它的核心并不执行任何具体的构建任务,所有这些任务都交给插件来完成,例如编译源代码是由maven- compiler-plugin完成的.进一步说,每个任务对应 ...
- 【EF6学习笔记】(二)操练 CRUD 增删改查
本篇原文链接: Implementing Basic CRUD Functionality 说明:学习笔记参考原文中的流程,为了增加实际操作性,并能够深入理解,部分地方根据实际情况做了一些调整:并且根 ...
- 学习笔记——Maven实战(一)坐标规划
坐标是什么?为什么要规划? 坐标是Maven最基本的概念,它就像每个构件的身份证号码,有了它我们就可以在数以千万计的构件中定位任何一个我们感兴趣的构件.举个最简单的例子,如果没有坐标,使用JUnit的 ...
- 学习笔记——Maven实战(五)自动化Web应用集成测试
自动化集成测试的角色 本专栏的上一篇文章讲述了Maven与持续集成的一些关系及具体实践,我们都知道,自动化测试是持续集成必不可少的一部分,基本上,没有自动化测试的持续集成,都很难称之为真正的持续集成. ...
随机推荐
- 深入PHP内核之in_array
无意中看到一段代码 1.a.php <?php $y="12"; $x = array(); for($j=0;$j<50000;$j++){ $x[]= " ...
- GDI学习之俄罗斯方块续
当前方块对象 #region 定义砖块int[i,j,y,x] Tricks:i为那块砖,j为状态,y为列,x为行 private int[, , ,] Tricks = {{ { {,,,}, {, ...
- 更改ubuntu下mysql的密码
1.首先,进入环境中去,即 mysql -u root -p ,然后输入原始密码 2.此时会出现 mysql > 3.开始修改密码: mysql > use mysql ; ...
- 手机远程调试工具spy-debugger
关于spy-debugger 1.一站式页面调试工具,远程调试任何手机浏览器页面,任何手机移动端webview(如:微信,HybirdApp等)HTTP/HTTPS.2.spy-debugger内 ...
- php写守护进程(Daemon)
守护进程(Daemon)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.守护进程是一种很有用的进程.php也可以实现守护进程的功能. 1.基本概念 进程 ...
- TC79
/* INSERT INTO TC79(PatientID,AdmissionDate,DischargeDate,Cost) SELECT * FROM ( SELECT 709,TO_DATE(' ...
- dipole antenna simulation by CST
CST偶极子天线仿真,半波振子天线 一.本文使用CST仿真频率为1GHz的偶极子天线,使用2013版本.仿真的步骤为 1.选择一个CST的天线工程模板 2.设置好默认的单位 3.设置背景的材料(空气腔 ...
- ZOJ 3967 Colorful Rainbows --栈的应用
题意:给出n条y=ai*x+bi的直线.对于这些直线,如果存在x使得该直线y大于其他任意一直线,那么这条直线可以被看见,问有多少条直线可以被看见. 做法什么的不讲了,参见:http://blog.cs ...
- [转] Android实时抓包分析 : 善用adb调试桥
Android实时抓包分析 : 善用adb调试桥 谈到android网络抓包,很多人都能想到牛逼轰轰的神器tcpdump.方法就是在android机器上面安装tcpdump,然后通过-w参数把抓包 ...
- 注解与反射 ---Spring与Mybatis等框架的实现原理
Java中各大框架,无论是AOP 还是 IoC 其基本实现思路都是源自Java 运行时支撑的反射功能, 而反射最基本的一点就是 任何一个类 其在JVM环境中,都有一个对象的Class对象,这个对象提供 ...