什么是版本管理
首先,这里说的版本管理(version management)不是指版本控制(version control),但是本文假设你拥有基本的版本控制的知识,了解subversion的基本用法。版本管理中说得版本是指构件(artifact)的版 本,而非源码的版本(如subversion中常见的rXXX,或者git中一次提交都有个sha1的commit号)。
比如我有一个项目,其artifactId为myapp,随着项目的进展,我们会生成这样一些jar:myapp-1.0- SNAPSHOT.jar,myapp-1.0.jar,myapp-1.1-SNAPSHOT.jar,myapp-1.0.1.jar等等。你可能会 说,这很简单啊,我在POM中改个version,mvn clean install不就完了?但这只是表面,本文我将讲述,snapshot和release版本的区别,如何自动化版本发布(如果你的项目有几十个 module,你就会觉得手工改POM来升级版本是很痛苦的事情),结合自动化发布的过程,这里还会介绍maven-release-plugin。此 外,一些scm概念也会被涉及到,比如tag和branch。
前提:版本控制
不管怎样,我们都需要建立一个项目并提交到SCM中,这里我以subversion为例。你得有一个配置好的subversion repository,这里我建立了一个空的svn仓库,其地址为:https://192.168.1.100:8443/svn/myapp/ 现在,该目录下只有三个空的典型的子目录:/trunk/, branches/, tags/。分别用来存放主干,分支,以及标签。
接着将项目导入到svn仓库中,到项目根目录,运行如下命令:
svn import -m 'project initialization' https://192.168.1.100:8443/svn/myapp/trunk
(注意,这么做你会将目录下所有文件导入到svn库中,但是这其中某些目录和文件是不应该被导入的,如/target目录,以及eclipse相关的项目文件)
目前,我们将项目的版本设置为1.0-SNAPSHOT。
为什么用SNAPSHOT?
我先说说如果没有SNAPSHOT会是什么样子。假设你的项目有2个模块,A,B,其中A依赖B。这三个模块分别由甲,乙两个个人负责开发。在开发 过程中,因为A是依赖于B的,因此乙每次做一个改动都会影响到甲,于是,乙提交了一些更改后,需要让甲看到。这个时候,怎么做呢?乙对甲说,“你签出我的 代码,build一下就OK了”,甲有点不情愿,但还是照做了,签出代码,svn clean install,然后,发现build出错了,有个测试没有pass。甲郁闷了,对乙说,“你的代码根本不能用,我不想build,你build好了给 我”,乙看了看确实自己的代码build不过,于是回去解决了,然后打了个jar包,扔给甲,甲对了对groupId,artifactId,放到了自己 的.m2/repository/目录下,OK,能用了。
于是乙每次更新都这样做,打包,复制,然后甲粘贴,使用……渐渐的,大家发现这是个很笨的办法,这是纯手工劳动阿,程序员最BS的就是重复劳动。一 天,甲对乙说,“你知道nexus么?你把你的jar发布到nexus上就可以了,我要用就自动去下载,这多棒!”乙说“哦?有这好东西,我去看看”于是 乙发现了nexus这块新大陆,并成功的发布了B到nexus上。(见,Nexus入门指南,(图文) )。
但是,请注意,我们这里的一切都假设没有SNAPSHOT,因此如果乙不更改版本,甲下载一次如B-1.0.jar之后,maven认为它已经有了 正确的B的版本,就不会再重新下载。甲发现了这个问题,对乙说“你的更新我看不到,你更新了么?”乙说“不可能!我看看”,于是检查一下甲下载的C- 1.0.jar,发现那是几天前的。乙一拍脑袋,说“这简单,我更新一下我的版本就好了,我发布个B-1.1.jar上去,你更新下依赖版本”,甲照做 了,似乎这么做是可行的。
这里有一个问题,一次提交就更新一个版本,这明显不是正确的管理办法,此外,乙得不停的通知甲更新对B的依赖版本,累不累阿?1.0,或者说1.1,2.0,都代表了稳定,这样随随便便的改版本,能稳定么?
所以Maven有SNAPSHOT版本的概念,它与release版本对应,后者是指1.0,1.1,2.0这样稳定的发布版本。
现在乙可以将B的版本设置成1.0-SNAPSHOT,每次更改后,都mvn deploy到nexus中,每次deploy,maven都会将SNAPSHOT改成一个当前时间的timestamp,比如B-1.0- SNAPSHOT.jar到nexus中后,会成为这个样子:B-1.0-20081017-020325-13.jar。Maven在处理A中对于B的 SNAPSHOT依赖时,会根据这样的timestamp下载最新的jar,默认Maven每天 更新一次,如果你想让Maven强制更新,可以使用-U参数,如:mvn clean install -U 。
现在事情简化成了这个样子:乙做更改,然后mvn deploy,甲用最简单的maven命令就能得到最新的B。
从1.0-SNAPSHOT到1.0到1.1-SNAPSHOT
SNAPSHOT是快照的意思,项目到一个阶段后,就需要发布一个正式的版本(release版本)。一次正式的发布需要这样一些工作:
- 在trunk中,更新pom版本从1.0-SNAPSHOT到1.0
- 对1.0打一个svn tag
- 针对tag进行mvn deploy,发布正式版本
- 更新trunk从1.0到1.1-SNAPSHOT
你可以手工一步步的做这些事情,无非就是一些svn操作,一些pom编辑,还有一些mvn操作。但是你应该明白,手工做这些事情,一来繁琐,而来容易出错。因此这里我介绍使用maven插件来自动化这一系列动作。
SCM
首先我们需要在POM中加入scm信息,这样Maven才能够替你完成svn操作,这里我的配置如下:
- <scm>
- <connection>scm:svn:http://192.168.1.100:8443/svn/myapp/trunk/</connection>
- <developerConnection>scm:svn:https://192.168.1.100:8443/svn/myapp/trunk/</developerConnection>
- </scm>
需要注意的是,很多windows使用的tortoiseSVN客户端,而没有svn命令行客户端,这会导致Maven所有svn相关的工作失败,因此,你首先确保svn --version能够运行。
分发仓库
想要让Maven帮我们自动发布,首先我们需要配置好分发仓库。关于这一点,见Maven最佳实践:Maven仓库——分发构件至远程仓库。
maven-release-plugin
紧接着,我们需要配置maven-release-plugin,这个插件会帮助我们升级pom版本,提交,打tag,然后再升级版本,再提交,等等。基本配置如下:
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-release-plugin</artifactId>
- <version>2.0-beta-7</version>
- <configuration>
- <tagBase>https://192.168.1.100:8443/svn/myapp/tags/</tagBase>
- </configuration>
- </plugin>
GAV我就不多解释了,这里我们需要注意的是configuration元素下的tagBase元素,它代表了我们svn中的tag目录,也就是 说,maven-release-plugin帮我们打tag的时候,其基础目录是什么。这里,我填写了svn仓库中的标准的tags目录。
提交代码
接着,确保你的所有代码都提交了,如果你有未提交代码,release插件会报错,既然你要发布版本了,就表示代码是稳定的,所以要么要么把代码提交了,要么把本地的更改抛弃了。
开始工作
现在,屏住呼吸,执行:
mvn release:prepare
执行过程中,你会遇到这样的提示:
What is the release version for "Unnamed - org.myorg:myapp:jar:1.0-SNAPSHOT"? (org.myorg:myapp) 1.0: :
——“你想将1.0-SNAPSHOT发布为什么版本?默认是1.0。”我要的就是1.0,直接回车。
What is SCM release tag or label for "Unnamed - org.myorg:myapp:jar:1.0-SNAPSHOT"? (org.myorg:myapp) myapp-1.0: :
——“发布的tag标签名称是什么?默认为myapp-1.0。”我还是要默认值,直接回车。
What is the new development version for "Unnamed - org.myorg:myapp:jar:1.0-SNAPSHOT"? (org.myorg:myapp) 1.1-SNAPSHOT: :
——“主干上新的版本是什么?默认为1.1-SNAPSHOT。”哈,release插件会自动帮我更新版本到1.1-SNAPSHOT,很好,直接回车。
然后屏幕刷阿刷,maven在build我们的项目,并进行了一些svn操作,你可以仔细查看下日志。
那么结果是什么呢?你可以浏览下svn仓库:
- 我们多了一个tag:https://192.168.1.100:8443/svn/myapp/tags/myapp-1.0/,这就是需要发布的版本1.0。
- 再看看trunk中的POM,其版本自动升级成了1.1-SNAPSHOT。
这不正是我们想要的么?等等,好像缺了点什么,对了,1.0还没有发布到仓库中呢。
再一次屏住呼吸,执行:
mvn release:perform
maven-release-plugin会自动帮我们签出刚才打的tag,然后打包,分发到远程Maven仓库中,至此,整个版本的升级,打标签,发布等工作全部完成。我们可以在远程Maven仓库中看到正式发布的1.0版本。
这可是自动化的 ,正式的 版本发布!
Maven的版本规则
前面我们提到了SNAPSHOT和Release版本的区别,现在看一下,为什么要有1.0,1.1,1.1.1这样的版本,这里的规则是什么。
Maven主要是这样定义版本规则的:
<主版本>.<次版本>.<增量版本>
比如说1.2.3,主版本是1,次版本是2,增量版本是3。
主版本一般来说代表了项目的重大的架构变更,比如说Maven 1和Maven 2,在架构上已经两样了,将来的Maven 3和Maven 2也会有很大的变化。次版本一般代表了一些功能的增加或变化,但没有架构的变化,比如说Nexus 1.3较之于Nexus 1.2来说,增加了一系列新的或者改进的功能(仓库镜像支持,改进的仓库管理界面等等),但从大的架构上来说,1.3和1.2没什么区别。至于增量版本, 一般是一些小的bug fix,不会有重大的功能变化。
一般来说,在我们发布一次重要的版本之后,随之会开发新的版本,比如说,myapp-1.1发布之后,就着手开发myapp-1.2了。由于 myapp-1.2有新的主要功能的添加和变化,在发布测试前,它会变得不稳定,而myapp-1.1是一个比较稳定的版本,现在的问题是,我们在 myapp-1.1中发现了一些bug(当然在1.2中也存在),为了能够在段时间内修复bug并仍然发布稳定的版本,我们就会用到分支 (branch),我们基于1.1开启一个分支1.1.1,在这个分支中修复bug,并快速发布。这既保证了版本的稳定,也能够使bug得到快速修复,也 不同停止1.2的开发。只是,每次修复分支1.1.1中的bug后,需要merge代码到1.2(主干)中。
上面讲的就是我们为什么要用增量版本。
实战分支
目前我们trunk的版本是1.1-SNAPSHOT,其实按照前面解释的版本规则,应该是1.1.0-SNAPSHOT。
现在我们想要发布1.1.0,然后将主干升级为1.2.0-SNAPSHOT,同时开启一个1.1.x的分支,用来修复1.1.0中的bug。
首先,在发布1.1.0之前,我们创建1.1.x分支,运行如下命令:
mvn release:branch -DbranchName=1.1.x -DupdateBranchVersions=true -DupdateWorkingCopyVersions=false
这是maven-release-plugin的branch目标,我们指定branch的名称为1.1.x,表示这里会有版本1.1.1, 1.1.2等等。updateBranchVersions=true的意思是在分支中更新版本,而 updateWorkingCopyVersions=false是指不更改当前工作目录(这里是trunk)的版本。
在运行该命令后,我们会遇到这样的提示:
What is the branch version for "Unnamed - org.myorg:myapp:jar:1.1-SNAPSHOT"? (org.myorg:myapp) 1.1-SNAPSHOT: :
——"分支中的版本号是多少?默认为1.1-SNAPSHOT" 这时我们想要的版本是1.1.1-SNAPSHOT,因此输入1.1.1-SNAPSHOT,回车,maven继续执行直至结束。
接着,我们浏览svn仓库,会看到这样的目录:https://192.168.1.100:8443/svn/myapp/branches/1.1.x/,打开其中的POM文件,其版本已经是1.1.1-SNAPSHOT。
分支创建好了,就可以使用release:prepare和release:perform为1.1.0打标签,升级trunk至1.2.0-SNAPSHOT,然后分发1.1.0。
至此,一切OK。
小结
本文讲述了如何使用Maven结合svn进行版本管理。解释了Maven中SNAPSHOT版本的来由,以及Maven管理版本的规则。并结合 SCM的tag和branch概念展示了如何使用maven-release-plugin发布版本,以及创建分支。本文涉及的内容比较多,且略显复杂, 不过掌握版本管理的技巧对于项目的正规化管理来说十分重要。Maven为我们提供了一些一套比较成熟的机制,值得掌握。
所有用Maven管理的真实的项目都应该是分模块的,每个模块都对应着一个pom.xml。它们之间通过继承和聚合(也称作多模块,multi- module)相互关联。那么,为什么要这么做呢?我们明明在开发一个项目,划分模块后,导入Eclipse变成了N个项目,这会带来复杂度,给开发带来 不便。
为了解释原因,假设有这样一个项目,很常见的Java Web应用。在这个应用中,我们分了几层:
- Dao层负责数据库交互,封装了Hibernate交互的类。
- Service层处理业务逻辑,放一些Service接口和实现相关的Bean。
- Web层负责与客户端交互,主要有一些Structs的Action类。
对应的,在一个项目中,我们会看到一些包名:
- org.myorg.app.dao
- org.myorg.app.service
- org.myorg.app.web
- org.myorg.app.util
这样整个项目的框架就清晰了,但随着项目的进行,你可能会遇到如下问题:
- 这个应用可能需要有一个前台和一个后台管理端(web或者swing),你发现大部分dao,一些service,和大部分util是在两个应用中可。这样的问题,你一周内遇到了好几次。
- pom.xml中的依赖列表越来越长以重用的,但是,由于目前只有一个项目(WAR),你不得不新建一个项目依赖这个WAR,这变得非常的恶心, 因为在Maven中配置对WAR的依赖远不如依赖JAR那样简单明了,而且你根本不需要org.myorg.app.web。有人修改了dao,提交到 svn并且不小心导致build失败了,你在编写service的代码,发现编译不过,只能等那人把dao修复了,你才能继续进行,很多人都在修改,到后 来你根本就不清楚哪个依赖是谁需要的,渐渐的,很多不必要的依赖被引入。甚至出现了一个依赖有多个版本存在。
- build整个项目的时间越来越长,尽管你只是一直在web层工作,但你不得不build整个项目。
- 某个模块,比如util,你只想让一些经验丰富的人来维护,可是,现在这种情况,每个开发者都能修改,这导致关键模块的代码质量不能达到你的要求。
我们会发现,其实这里实际上没有遵守一个设计模式原则:“高内聚,低耦合”。虽然我们通过包名划分了层次,并且你还会说,这些包的依赖都是单向的,没有包的环依赖。这很好,但还不够,因为就构建层次来说,所有东西都被耦合在一起了。因此我们需要使用Maven划分模块。
一个简单的Maven模块结构是这样的:
---- app-parent
|-- pom.xml (pom)
|
|-- app-util
| |-- pom.xml (jar)
|
|-- app-dao
| |-- pom.xml (jar)
|
|-- app-service
| |-- pom.xml (jar)
|
|-- app-web
|-- pom.xml (war)
上述简单示意图中,有一个父项目(app-parent)聚合很多子项目(app-util, app-dao, app-service, app-web)。每个项目,不管是父子,都含有一个pom.xml文件。而且要注意的是,小括号中标出了每个项目的打包类型。父项目是pom,也只能是 pom。子项目有jar,或者war。根据它包含的内容具体考虑。
这些模块的依赖关系如下:
app-dao --> app-util
app-service --> app-dao
app-web --> app-service
注意依赖的传递性(大部分情况是传递的,除非你配置了特殊的依赖scope),app-dao依赖于app-util,app-service依赖 于app-dao,于是app-service也依赖于app-util。同理,app-web依赖于app-dao,app-util。
用项目层次的划分替代包层次的划分能给我们带来如下好处:
- 方便重用,如果你有一个新的swing项目需要用到app-dao和app-service,添加对它们的依赖即可,你不再需要去依赖一个WAR。而有些模块,如app-util,完全可以渐渐进化成公司的一份基础工具类库,供所有项目使用。这是模块化最重要的一个目的。
- 由于你现在划分了模块,每个模块的配置都在各自的pom.xml里,不用再到一个混乱的纷繁复杂的总的POM中寻找自己的配置。
- 如果你只是在app-dao上工作,你不再需要build整个项目,只要在app-dao目录运行mvn命令进行build即可,这样可以节省时间,尤其是当项目越来越复杂,build越来越耗时后。
- 某些模块,如app-util被所有人依赖,但你不想给所有人修改,现在你完全可以从这个项目结构出来,做成另外一个项目,svn只给特定的人访问,但仍提供jar给别人使用。
- 多模块的Maven项目结构支持一些Maven的更有趣的特性(如DepencencyManagement),这留作以后讨论。
接下来讨论一下POM配置细节,实际上非常简单,先看app-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/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.myorg.myapp</groupId>
- <artifactId>app-parent</artifactId>
- <packaging>pom</packaging>
- <version>1.0-SNAPSHOT</version>
- <modules>
- <module>app-util</module>
- <module>app-dao</module>
- <module>app-service</module>
- <module>app-web</module>
- </modules>
- </project>
Maven的坐标GAV(groupId, artifactId, version)在这里进行配置,这些都是必须的。特殊的地方在于,这里的packaging为pom。所有带有子模块的项目的packaging都为 pom。packaging如果不进行配置,它的默认值是jar,代表Maven会将项目打成一个jar包。
该配置重要的地方在于modules,例子中包含的子模块有app-util, app-dao, app-service, app-war。在Maven build app-parent的时候,它会根据子模块的相互依赖关系整理一个build顺序,然后依次build。
这就是一个父模块大概需要的配置,接下来看一下子模块符合配置继承父模块。、
- <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">
- <parent>
- <artifactId>app-parent</artifactId>
- <groupId>org.myorg.myapp</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>app-util</artifactId>
- <dependencies>
- <dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- <version>2.4</version>
- </dependency>
- </dependencies>
- </project>
app-util模块继承了app-parent父模块,因此这个POM的一开始就声明了对app-parent的引用,该引用是通过Maven坐 标GAV实现的。而关于项目app-util本身,它却没有声明完整GAV,这里我们只看到了artifactId。这个POM并没有错,groupId 和version默认从父模块继承了。实际上子模块从父模块继承一切东西,包括依赖,插件配置等等。
此外app-util配置了一个对于commons-lang的简单依赖,这是最简单的依赖配置形式。大部分情况,也是通过GAV引用的。
再看一下app-dao,它也是继承于app-parent,同时依赖于app-util:
- <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">
- <parent>
- <artifactId>app-parent</artifactId>
- <groupId>org.myorg.myapp</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>app-dao</artifactId>
- <dependencies>
- <dependency>
- <groupId>org.myorg.myapp</groupId>
- <artifactId>app-util</artifactId>
- <version>${project.version}</version>
- </dependency>
- </dependencies>
- </project>
该配置和app-util的配置几乎没什么差别,不同的地方在于,依赖变化了,app-dao依赖于app-util。这里要注意的是 version的值为${project.version},这个值是一个属性引用,指向了POM的project/version的值,也就是这个 POM对应的version。由于app-dao的version继承于app-parent,因此它的值就是1.0-SNAPSHOT。而app- util也继承了这个值,因此在所有这些项目中,我们做到了保持版本一致。
这里还需要注意的是,app-dao依赖于app-util,而app-util又依赖于commons-lang,根据传递性,app-dao也拥有了对于commons-lang的依赖。
app-service我们跳过不谈,它依赖于app-dao。我们最后看一下app-web:
- <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">
- <parent>
- <artifactId>app-parent</artifactId>
- <groupId>org.myorg.myapp</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>app-web</artifactId>
- <packaging>war</packaging>
- <dependencies>
- <dependency>
- <groupId>org.myorg.myapp</groupId>
- <artifactId>app-service</artifactId>
- <version>${project.version}</version>
- </dependency>
- </dependencies>
- </project>
app-web依赖于app-service,因此配置了对其的依赖。
由于app-web是我们最终要部署的应用,因此它的packaging是war。为此,你需要有一个目录src/main/webapp。并在这 个目录下拥有web应用需要的文件,如/WEB-INF/web.xml。没有web.xml,Maven会报告build失败,此外你可能还会有这样一 些子目录:/js, /img, /css ... 。
看看Maven是如何build整个项目的,我们在 app-parent 根目录中运行 mvn clean install ,输出的末尾会有大致这样的内容:
...
...
[INFO] [war:war]
[INFO] Packaging webapp
[INFO] Assembling webapp[app-web] in [/home/juven/workspaces/ws-others/myapp/app-web/target/app-web-1.0-SNAPSHOT]
[INFO] Processing war project
[INFO] Webapp assembled in[50 msecs]
[INFO] Building war: /home/juven/workspaces/ws-others/myapp/app-web/target/app-web-1.0-SNAPSHOT.war
[INFO] [install:install]
[INFO] Installing /home/juven/workspaces/ws-others/myapp/app-web/target/app-web-1.0-SNAPSHOT.war to /home/juven/.m2/repository/org/myorg/myapp/app-web/1.0-SNAPSHOT/app-web-1.0-SNAPSHOT.war
[INFO]
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] ------------------------------------------------------------------------
[INFO] app-parent ............................................ SUCCESS [1.191s]
[INFO] app-util .............................................. SUCCESS [1.274s]
[INFO] app-dao ............................................... SUCCESS [0.583s]
[INFO] app-service ........................................... SUCCESS [0.593s]
[INFO] app-web ............................................... SUCCESS [0.976s]
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4 seconds
[INFO] Finished at: Sat Dec 27 08:20:18 PST 2008
[INFO] Final Memory: 3M/17M
[INFO] ------------------------------------------------------------------------
注意Reactor Summary,整个项目根据我们希望的顺序进行build。Maven根据我们的依赖配置,智能的安排了顺序,app-util, app-dao, app-service, app-web。
最后,你可以在 app-web/target 目录下找到文件 app-web-1.0-SNAPSHOT.war ,打开这个war包,在 /WEB-INF/lib 目录看到了 commons-lang-2.4.jar,以及对应的app-util, app-dao, app-service 的jar包。Maven自动帮你处理了打包的事情,并且根据你的依赖配置帮你引入了相应的jar文件。
使用多模块的Maven配置,可以帮助项目划分模块,鼓励重用,防止POM变得过于庞大,方便某个模块的构建,而不用每次都构建整个项目,并且使得针对某个模块的特殊控制更为方便。本文同时给出了一个实际的配置样例,展示了如何使用Maven配置多模块项目。
相关推荐
【MAVEN使用最佳实践】 Maven 是一个强大的项目管理和构建工具,它简化了Java应用程序的构建过程,通过一套约定优于配置的原则,使得项目构建、依赖管理和文档生成等工作变得标准化。以下是一些在使用Maven时可以...
### 六、最佳实践与注意事项 1. **避免压缩库文件**:第三方库通常已经过优化,不需要再压缩,因此在`excludes`中排除这些库文件。 2. **版本控制**:确保将原始未压缩文件纳入版本控制系统,以便于调试和更新。 3....
10. 使用Maven仓库的最佳实践: - 保持pom.xml文件的整洁,避免引入不必要的依赖。 - 对于公司内部的项目,推荐使用私有仓库托管,以防止版本冲突和敏感信息泄露。 - 定期更新依赖,以获取最新的安全修复和功能...
### Maven的最佳实践 - 保持POM简洁清晰,避免过度配置。 - 使用统一的命名规则和版本控制策略。 - 利用Maven的 profiles 功能为不同的环境(如开发、测试、生产)创建不同的配置。 - 使用Maven的依赖管理,避免...
- **版本控制**:archetype 可以随着项目需求的变化而更新,新版本的 archetype 会包含最新的最佳实践和依赖。 ### Maven Archetype 的配置文件 每个 archetype 都有一个配置文件,通常是 `archetype-metadata.xml...
最佳实践 smart-doc+形成业界领先的文档生成与管理解决方案,使用smart-doc完成Java源代码分析并提取注解生成API文档无侵入,自动推送文档至Torna企业级接口文档管理平台. 入门 添加插件 <groupId>...
何为Maven 构建,依赖管理,项目信息聚合 Maven核心概念 坐标,依赖,仓库,生命周期,插件 Maven最佳实践 创建、打包、发布、版本管理 项目实战 Nexus(Todo…) M2eclipse(Todo…)
** Maven 3:最佳实践与全面指南 ** Maven 是一个强大的项目管理和构建工具,尤其在Java开发领域中被广泛使用。"最好用的maven3"这一标题表明了Maven 3版本因其高效和易用性而备受推崇。本文将深入探讨Maven 3的...
**3.6 POM 最佳实践** - **3.6.1 依赖分组**:将相关的依赖放在一起,方便管理和查找。 - **3.6.2 多模块与继承** - **3.6.2.1 简单项目**:对于较小的项目,可以使用单一的 POM 文件来管理整个项目。 - **3.6....
### Maven最佳实践 - **保持POM简洁**:避免在POM中添加不必要的配置,尽量利用Maven的默认设置。 - **使用父POM**:多个项目共享相同配置时,可以创建一个父POM来统一管理。 - **版本管理**:遵循 Semantic ...
**四、最佳实践** 1. **保持POM简洁**: 避免在POM中直接引入整个依赖树,尽可能精确地声明直接依赖。 2. **版本管理**: 使用`<version>`标签管理项目版本,遵循语义化版本规则。 3. **使用版本范围(Version Ranges...
这个"maven-parent"主要被Apache的各个子项目引用,为它们提供一致性和最佳实践。 标题 "maven-parent:Apache Maven项目父POM" 指出这个压缩包包含的是与Maven的父POM相关的源代码和配置。这个父POM包含了各种默认...
**Maven版的JPA最佳实践** 在Java开发中,Maven作为项目构建工具,而JPA(Java Persistence API)则是用于对象关系映射(ORM)的标准,它们结合使用能够帮助开发者更高效地管理和操作数据库。本文将深入探讨在Maven...
1. Maven最佳实践:提供了一些实际项目中如何有效使用Maven的经验和建议。 2. 敏捷开发与持续集成:讲解如何利用Maven与敏捷开发方法(如Scrum、XP)结合,以及如何与持续集成工具(如Jenkins、Hudson)集成。 3. ...
5. **社区支持**:在开发者论坛或邮件列表中寻求帮助,询问关于过时插件的最佳实践。 总之,对于Java和Maven的使用者来说,保持插件的更新和选择官方推荐的插件是保证项目顺利构建和长期维护的关键。当遇到不建议...
- **Maven**:文档和社区支持同样丰富,而且由于其标准化的构建模型,更容易找到官方推荐的解决方案和最佳实践。 #### 实战案例分析 1. **错误配置示例**: - **问题描述**:在使用Maven的J2EE项目中,配置`...
- 指导开发:Maven提供了Java项目的最佳实践,通过预设的项目结构,自动生成项目骨架。 - 自动编译:Maven不仅能自动编译源码,还能执行测试、打包、部署、文档生成等一系列任务。 - 依赖管理:Maven通过仓库管理...
通过深入学习这份"Maven帮助文档",开发者不仅可以掌握Maven的基本操作,还能理解其背后的原理和最佳实践,从而提升项目构建的效率和质量。无论你是初学者还是经验丰富的开发者,这份文档都将是你宝贵的参考资料。