Java-Maven详解
Apache Maven是一个软件项目管理的综合工具。基于项目对象模型(POM)的概念,提供了帮助管理构建、文档、报告、依赖、发布等方法,Maven简化和标准化项目建设过程。处理编译,分配,文档,团队协作和其他任务的无缝连接。 Maven增加可重用性并负责建立相关的任务。
- 可以将项目过程规范化、自动化、高效化以及强大的可扩展性,利用maven自身及其插件还可以获得代码检查报告、单元测试覆盖率、实现持续集成等等。
- 使得项目的管理变得容易,构建项目的速度更快,由于Maven提供了仓库的概念去管理jar包,所以用git或者svn的时候,存储构建的项目体积会更小。
管理项目的构建、文档生成、报告、依赖、SCMs(software configuration Management)、分布、分发、邮件列表。
采用远程仓库和本地仓库以及一个核心的配置文件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。
官网地址:http://maven.apache.org/Maven下载地址:http://maven.apache.org/download.cgi
这里我两个环境的版本都下载,分别在我本机和linux虚拟机安装。
Maven根目录文件介绍:
- bin:Maven的运行脚本。bin\\mvn.cmd是基于windows的脚本。在cmd中每输入一条mvn的命令都是在调用并执行这些脚本。
- boot:该项目只有一个文件plexus-classworlds-2.5.2.jar。他是一个类加载器的框架,相当于对JDK中的类的加载器,提供了丰富的语法以此用来方便配置,Maven使用该框架加载自己的类库。
- conf:该目录包含了一个非常重要的文件setting.xml。配置该文件就可以在Project中定制Maven的行为。
- lib:包含了所有Maven运行时需要的Java类库以及用到的第三方类库。
- LICENSE:软件许可
- NOTICE:软件引用的三方软件
- README.txt:包含了Maven的简介
- 依赖Java,需要配置JAVA_HOME,没有装jdk的还得先装jdk
- 设置Maven自身自身的运行环境,需要配置MAVEN_HOME
- 配置完JAVA_HOME和MAVEN_HOME,还得配置Path,在Path加上:%JAVA_HOME%\\bin和%MAVEN_HOME%\\bin
先查找默认的配置,在lib目录下随便找个jar包用解压工具打开-》再回到上层目录-》ctrl+F搜索pom.找到pom-4.0.0.xml-》把这个文件拖出来打开
但是注意不是去修改jar包里面的这个配置,还是回到conf/setting.xml这个配置文件,修改这个配置文件。
默认git bash是没有tree命令的,这里提供下载地址:官网下载地址:http://gnuwin32.sourceforge.net/packages/tree.htm百度云下载地址:链接:https://pan.baidu.com/s/17fc79rQUQSnBhWzej9xd9g提取码:6666把tree.exe放到git安装目录下的usr/bin/目录下
发现编译报错了:
【问题】 [ERROR] 不再支持源选项 5。请使用 7 或更高版本。[ERROR] 不再支持目标选项 5。请使用 7 或更高版本。
- 【解决方案一】修改全局,修改maven安装目录下conf/setting.xml文件,配置jdk,内容如下:
- 【解决方案二】修改局部,修改项目目录下的 pom.xml文件,配置jdk,内容如下:
这里我采用【解决方案一】修改全局的配置
再编译,编译成功
【温馨提示】这里只打包编译好的源程序(xxx.class文件)
【温馨提示】这里groupid决定放在仓库的哪个文件下,配置<groupId>com.hello</groupId>,所以生成的包就会放在仓库目录的com/hello目录下。
会经历编译(compile)-》测试(test)-》打包(package) -》安装(install)的过程。
模板:
mvn archetype:generate-DgroupId={project-packaging}-DartifactId={project-name}-DarchetypeArtifactId=maven-archetype-quickstart-DinteractiveMode=false
示例:
目录结构
目录结构
【温馨提示】IDEA官网下载地址:https://www.jetbrains.com/idea/
File->Settings,把默认配置自带的maven修改上面下载的版本
配置编译
配置清理
右上角就有两个运行的快捷选项了
会默认创建一个org.example的demo,可以删掉
发现main和test里面都没创建resources,下面我们手动创建
如果创建的是普通目录,则可以右键目录修改目录属性
在maven库中搜索tomcat:https://mvnrepository.com/
这里使用2.1版本的
【温馨提示】默认端口是8080,上面配置的80
发现报错了严重: Error configuring application listener of class org.springframework.web.context.ContextLoaderListenerjava.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
【原因&解决】是因为默认创建的web.xml配置文件里有spring的配置,先把这些配置删掉就行。最后web.xml只保留如下内容:
再运行
依赖指当前项目运行所需的jar包,一个项目可以设置多个依赖,示例如下:
依赖具有传递性:
- 间接依赖:在当前项目中通过依赖配置建立的依赖关系
- 直接依赖:被资源的资源如果依赖其它资源,当前项目间接依赖其它资源
- 路径优先:当前依赖中出现相同的资源时,层级越深,优先级越低,层级越浅,优先级越高。
- 声明优先:当资源在相同层级被依赖时,配置顺序靠前的覆盖配置顺序靠后的。
- 特殊优先:当同级配置了相同资源的不同版本,后配置的覆盖先配置的。
可选依赖指对外隐藏当前所依赖的资源—-不透明
排除依赖指主动断开依赖的资源,被排除的资源无需指定版本—-不需要
- 依赖的jar默认情况可以在任何地方使用,可以通过scope标签设定起作用范围
- 作用范围主程序范围有效(main文件夹范围内)测试程序范围有效(test文件夹范围内)是否参与打包(package指令范围内)
带有依赖范围的资源在进行传递时,作用范围将受到影响
Maven构建生命周期描述的是一次构建过程经历了多少的事件
- clean:清理工作
- default:核心工作,例如编译、测试、打包、部署等。
- site:产生报告,发布站点等。
- pre-clean:执行一些需要在clean之前完成的工作
- clean:移除所有上一次构建生成的文件
- post-clean:执行一些需要在clean之后立刻完成的工作
- validate (校验):校验项目是否正确并且所有必要的信息可以完成项目的构建过程。
- initialize (初始化):初始化构建状态,比如设置属性值。
- generate-sources (生成源代码):生成包含在编译阶段中的任何源代码。
- process-sources (处理源代码):处理源代码,比如说,过滤任意值。
- generate-resources (资源文件):生成将会包含在项目包中的资源文件。
- process-resources (处理资源文件):复制和处理资源到目标目录,为打包阶段最好准备。
- compile (编译):编译项目的源代码。
- process-classes (处理类文件):处理编译生成的文件,比如说对Java class文件做字节码改善优化。
- generate-test-sources (生成测试源代码):生成包含在编译阶段中的任何测试源代码。
- process-test-sources (处理测试源代码):处理测试源代码,比如说,过滤任意值。
- generate-test-resources (生成测试资源文件):为测试创建资源文件。
- process-test-resources (处理测试资源文件):复制和处理测试资源到目标目录。
- test-compile (编译测试源码):编译测试源代码到测试目标目录。
- process-test-classes (处理测试类文件):处理测试源码编译生成的文件。
- test (测试):使用合适的单元测试框架运行测试(Juint是其中之一)。
- prepare-package (准备打包):在实际打包之前,执行任何的必要的操作为打包做准备。
- package (打包):将编译后的代码打包成可分发格式的文件,比如JAR、WAR或者EA件。
- pre-integration-test (集成测试前):在执行集成测试前进行必要的动作。比如说,搭建需要的环境。
- integration-test (集成测试):处理和部署项目到可以运行集成测试环境中。
- post-integration-test (集成测试后):在执行集成测试完成后进行必要的动作。比如说,清理集成测试环境。
- verify (验证):运行任意的检直来验证项目包有效达到质量标准。
- install (安装):安装项目包到本地仓库,这样项目包可以用作其他本地项目的依赖。
- deploy (部署):将最终的项目包复制到远程仓库中与其他开发者和项目共享。
【温馨提示】:像compile、test、test-compile、package、install等,排在它们前面的步骤都会执行。图示如下:
- pre-site:执行一些需要在生成站点文档之前完成的工作
- site:生成项目的站点文档
- post-site:执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
- site-deploy:将生成的站点文档部署到特殊的服务器上
插件与生命周期内的阶段绑定,在执行到对应生命周期时执行对应的插件功能,默认maven在各个生命周期上绑定有预设的功能,通过插件可以自定义其他功能。
- SNAPSHOT (快照版本)
项目开发过程中,为方便团队成员合作,解决模块间相互依赖和时时更新的问题,开发者对每个模块进行构建的时候,输出的临时性版本叫快照版本(测试阶段版本),快照版本会随着开发的进展不断更新。
- RELEASE (发布版本)
项目开发到进入阶段里程碑后,向团队外部发布较为稳定的版本,这种版本所对应的构件文件是稳定的,即便进行功能的后续开发,也不会改变当前发布版本内容,这种版本称为发布版本。
工程版本号约定规范:
【版本格式】<主版本>.< 次版本>.<i曾量版本 >.<里程碑版本>
- 主版本:表示项目重大架构的变更,如:spring5相较于spring4的迭代
- 次版本:表示有较大的功能增加和变化,或者全面系统地修复漏洞
- 增量版本:表示有重大漏洞的修复
- 里程碑版本:表明一个版本的里程碑(版本内部)。这样的版本同下一个正式版本相比,相对来说不是很稳定,有待更多的测试。
【范例】
5.1.9.RELEASE或5.1.9-RELEASE
一般公司至少有三套环境(开发、测试、生产),如果每次把程序打包好上传到对应的环境之前就得更改一下配置,是很烦的操作,所以就有了这里的多环境资源配置了。
示例:
通过命令加载指定环境
【调用格式】mvn 指令 -P 环境定义id
【示例】
- 整体模块功能未开发
- 模块中某个功能未开发完毕
- 单个功能更新调试导致其他功能失败
- 快速打包
- 使用命令跳过测试
【调用格式】mvn 指令 –D skipTests
- 使用配置跳过测试
Java界使用最广的依赖管理工具:Maven快速上手教程
Maven是Java界使用最广泛的依赖管理工具,几乎所有的Java类库和项目都使用Maven的项目模型。可以说Maven是学习Java必要的一个知识点。那么就让我们来看看如何使用Maven吧。
Maven的安装非常简单,访问下面的网页,选择zip包下载。下载完成后,放到合适的位置解压,然后将文件夹中的bin目录添加到环境变量中,以便可以在命令行中运行Maven。
选择zip包下载即可
或者如果你使用chocolatery或者scoop这样的包管理器,也可以直接使用命令行方式安装Maven。命令行方式安装Maven有一个好处就是包管理器会帮我们配置好环境变量,不需要手动配置。
Maven安装成功以后,打开一个cmd或者powershell窗口,运行以下命令,如果成功显示出Maven的版本号,说明Maven安装成功了。
命令的输出如图所示
安装好了Maven,先不要着急使用。默认情况下Maven会连接国外的仓库,下载速度非常慢。为了加快下载速度,最好先修改Maven配置文件。默认配置文件的位置是~/.m2/settings.xml。如果没有改文件夹,需要先创建一下。注意Windows系统无法直接创建以小数点开头的文件名,因此需要在powershell命令行中运行。
然后复制下面文件的内容。如果你不想让Maven将类库缓存放到用户目录下。可以取消localRepository标签的注释,然后设置你喜欢的目录。另外如果你使用的JDK版本不是11的话,就将profile标签中的java.version版本改成自己的。
完成后保存即可。这样一来,Maven就会使用国内的阿里云镜像,下载速度会非常快。
接下来就可以使用Maven创建项目了,平时我们一般都是直接用IDE的创建项目功能,很少用Maven的创建项目命令。不过还是有必要了解一下Maven的创建项目命令:
该命令会以交互式方式运行,接下来会询问你要创建的项目模板,选择默认的7即可;然后输入groupId、artifactId、版本号、包名等信息。前三者唯一标识了一个Maven包,不管是我们自己开发项目,还是引用项目都需要明确指定这三个参数。全部选择完毕之后,一个新的项目文件夹就生成了。
生成了新的项目
使用合适的IDE打开项目,可以看到项目具有类似下面的结构。简单介绍一下这个结构:src目录下是所有的源代码;main目录下是项目主要的代码;test目录下是项目的测试代码;pom.xml文件非常重要,它是Maven的核心描述文件,定义了Maven项目的所有重要信息。
那么再来看看pom.xml文件内容是什么样的吧。它是一个XML格式的文件,前面一部分定义了项目的信息,也就是我们在创建项目时候指定的groupId等。dependencies定义了项目要使用的各种依赖项,也就是第三方类库。
这里默认的junit类库比较旧,我们可以将版本号修改为4.13,这是目前最新的junit4版本。然后输入下面的命令重新编译项目,Maven会检查依赖项,如果发现本地不存在的依赖项就会先把它下载下来。因为我们用了阿里云镜像,所以下载和编译过程应该很快就可以完成了。
接下来就可以运行项目了,这样一个成功的Maven项目就创建完毕了。
我使用的是Intellij IDEA,社区版也支持maven,完全够用了
那么Maven是怎样让我们更方便的开发项目的呢?如你所见,我们只要将项目需要的依赖项添加到pom.xml中,Maven就可以自动下载和配置依赖的类路径。之后项目就可以直接运行了,简直和变魔术一样!如果你还在使用原始的复制粘贴jar包的方式,我建议你马上切换到Maven上来,享受它的便利功能。
默认情况下,Maven会将包下载到配置文件指定的localRepository,默认路径是~/.m2/repository。每个包会按照包名分类存放,搜索和查找也很方便。
默认的包保存位置
依赖项还有作用域这个特性,默认的作用域是compile,也就是包在编译和运行的时候都可见,大部分依赖也都使用这个作用域。test作用域只在test的时候可见,打包的时候不会包括,测试用的依赖会使用这个作用域。还有个provided作用域,指定一些开发时候需要、但是部署时不需要的包,一般用于开发servlet项目,servlet依赖是我们开发时必须的,但是部署项目的时候,会由servlet容器提供这些依赖。
要搜索依赖的话,可以使用Jetbrains新推出的Package Search网站,利用它可以搜索各种依赖项。地址如下:
Jetbrains 包搜索功能
例如我们搜索一下junit,然后点进来看看,包搜索功能将依赖项的各种信息都聚合到了一起。在左边可以查看项目的源码地址,右边列出了Maven和Gradle的依赖代码块,可以直接复制粘贴到项目中。
依赖详细信息
再举个例子,我们在项目中添加Gson的依赖,注意要添加到dependencies,和其他dependency平级。
然后将Main代码修改成类似下面这样的:
然后再次maven compile,并运行一下项目,可以发现,Maven已经帮我们下载并配置好了项目依赖,这次依然可以完美运行。这就是Maven强大的依赖管理功能。
Maven项目结构中还专门为代码测试留了一个专门的文件夹,用Maven进行单元测试也同样方便。将测试代码修改成类似下面的样子:
然后运行下面的命令即可使用Maven执行单元测试。假如有多个测试的话,Maven会执行所有这些测试。如果出现失败的测试,Maven也会给出相应的提示信息。
利用这一功能,我们可以放心的编写大量的测试用例,使用Maven一键帮我们执行测试。Maven的这一特性也可以方便的集成到持续集成系统中:推送项目代码以后自动测试,测试通过后自动发布,极大简化开发流程。
好了,相信大家看了本文也了解了Maven的一些核心功能,希望本文对大家有所帮助。如果有什么问题,也可以在评论区留言,大家一起交流学习!
我把公司 10 年老系统改造 Maven,真香
公司有几个老古董项目,应该是 10 年前开发的了,有一个是 JSP + Servlet,有一个还用的 SSH 框架,打包用的 Ant,是有多老啊,我想在座的各位很多都没听过吧。
为了持续集成、持续部署的需要,需要把这些老古董项目全改造成 Maven 管理,下面开搞。
快速创建一个 Maven 项目Maven Archetype 介绍
如何快速创建一个 Maven 项目,可以通过 Maven 的 Archetype 来进行创建,Archetype 是 Maven 提供的各种各样的工程模板,通过这些模板可以生成不同的 Maven 项目结构。
Maven 提供的 Archetype 列表如下:
http://maven.apache.org/archetypes/index.html
这里我们选择 maven-archetype-quickstart 这个模板进行快速创建,因为它提供了一个标准的项目结构,基于这个基本项目结构可以进行后续扩展。
生成 Maven 项目
1)通过 Maven 命令
Maven 提供了命令快速创建 Maven 项目:
命令中指定我们前面所说的 Maven Archetype:maven-archetype-quickstart 信息。
运行过程中会提示让你输入项目的 Naven 坐标信息,直到创建完成。基础部分这里不撰述了,需要完整 Maven 教程的点击文末的了解更多链接关注Java技术栈在后台回复”mvn”获取。
2)通过 IDEs
通过 IDE 也能快速创建 Maven 项目,现在 Java IDEs 都支持 Maven 或者自带 Maven 插件,下面以 Intellij IDEA 为例进行创建。
选择 maven-archetype-quickstart:
输入项目的 Naven 坐标信息:
选择 Maven 及仓库设置信息:
等待项目构建完成,如下所示:
Maven 项目重构Maven 项目配置
项目生成后,我们就可以把原系统的文件移到新的 Maven 项目了,因生成的项目结构比较简单,Maven 提供的 maven-archetype-webapp 模板也不符合要求:
我们的项目性质又是后台系统,涉及到方方面面,所以还需要再完善其他资源目录的创建:
这是一个比较标准的 Maven Web 项目结构,我把它弄成了一个基础脚手架,还集成了各种现成的插件和功能,后面其他项目转 Maven 可以直接拿来套用。
已经上传到了 Github:
https://github.com/javastacks/maven-demo-project
主要目录结构介绍:
目录说明src/main/java源代码目录src/main/resources资源目录src/main/filters多环境配置过滤目录src/main/webappWeb应用文件目src/test/java测试代码目录src/test/resources测试资源目录
所有目录创建完后,再根据文件性质把原系统所有除了(*.jar)文件移到对应的目录,这里没什么难度。
配置 Maven 环境信息:
Maven 依赖转换
依赖转换就是要把所有原系统的(*.jar)依赖包全部转换为 Maven 依赖管理,这里是难点,要解决编译、启动、运行时遇到的 jar 包冲突、版本冲突等异常。
我的思路是先把一些核心框架的依赖进行转换,再进行一些比较独立的公共工具包的转换,最后就是一些不熟悉的依赖转换。
引入 Maven 依赖的时候,看下其所有附属的所有依赖,再逐渐从 lib 目录删除,直到全部删除完成即转换完成。
在找对应依赖的时候,如果中央仓库找不到,其他远程仓库能找到的,就在公司私库中添加该包所在的远程仓库代理配置。
如果中央仓库或者其他远程仓库都找不到的,比如第三方的 SDK 包,就上传到公司私库。怎么上传到私库,点击这里阅读,更多 Maven 教程在文末了解更多链接中关注Java技术栈回复maven进行阅读。
根据 JAR 包找 Maven 依赖的时候,可能有多个名称一样的依赖,不知道引用哪个,这时候需要去原始 JAR 包中看下包名,根据包名就大概知道坐标信息了。
依赖传递:
在依赖转换过程中,如果一个依赖又依赖了其他依赖,可以直接引用父依赖即可,如在老项目中存在:poi、poi-ooxm、poi-ooxml-schemas 这三个依赖:
但在 POI 依赖体系中,poi-ooxml 包又需要依赖其他两个包,所以只需要引入 poi-ooxml 依赖即可:
这样就把这个包需要依赖的其他包都引进来了,这就是 Maven 管理依赖的好处,不会出现多包少包的情况,也能尽量避免依赖冲突。
依赖范围:
在老项目中,所有 jar 包都在 web-inf/lib 目录下,如:Servlet、JUnit,这些包在打完生产包之后也还在目录下,没有生命周期的管理。
在 Maven 中就能控制它们的生命周期:
Servlet 只需要编译时用到,JUnit 只需要测试时用到,控制好每个包的依赖范围,做到每个包的作用范围最小化。
解决冲突:
当传递的依赖版本不符合,或者是同一个包出现不同版本导致冲突的时候要学会使用排除:
或者强制指定包版本:
有的时候,还要根据需要使用 classifier 指定不同 JDK 的版本:
如源代码编译报错,不知道引用的哪个 JAR 包、或者哪个版本,可以到原始项目中点对应的类引用进去看就知道了。
整个改造过程比较顺利,就是编译和运行时需要解决一些 JAR 包冲突导致的问题,根据上面的种种方法直至编译、启动正常。
以后可以舒舒服服用 Maven 咯。
整理了半天,无私分享给大家,希望你们能有收获,觉得不错,欢迎点赞、转发哟~
本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com
文章为作者独立观点不代本网立场,未经允许不得转载。