打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
其实很多人,对Maven理解的并不深

作者:代堂鸣

       Maven是每一位Java工程师每天都会接触的工具,但据我了解,其实很多应用开发人员对Maven理解的并不深。他们会告诉你,Maven就是一个依赖管理工具,平台组都会配置好,不用管。得到的回答,仅仅是一个小小的局部,管中窥豹那般的视角。

       对想在这个领域里有所建树的人,先得热爱行业,才能沉浸在其中,面对艰难困苦的挑战也乐此不疲、不觉得苦;其次要有目标,管理好自己的一亩三分地之后,要想办法看到整个系统是怎么运转的。

       当然也可以每天得过且过,或是每天费尽心力的去研究业务、看懂那些“变态”的代码。可能刚开始两者看起来没有区别,但每过5年左右的时间,量变都产生质变,就会发现两种人之间已经形成了巨大的差距。前者的路越走越宽阔,后者还是一成不变,也许渐渐地开始为工作发愁。

       现在很多面试在问面试者项目经验的时候,经常会先让面试者先介绍项目背景、整体技术和业务结构,最后才会进入到自己真正负责的内容。所以只关注自己这一块是不行的,我们需要转变态度、提升眼界。有点说远了。

本文分五个部分来谈:

一、什么是Maven、有什么用

二、Maven安装、配置与运行

三、Maven的坐标与依赖说明

四、Maven仓库与私服的介绍

五、Maven的生命周期与插件

一、什么是Maven、有什么用

Maven这个单词来自于犹太语,意为知识的积累,最初在Jakata Turbine项目中用来简化构建过程。根据Maven的创立者Jason Van Zyl的介绍,最早的原型代码是在2001年提交的,2003年它成为了Apache的顶级项目。2010年10月Maven3正式发布,这时几乎成了Java构建的事实标准。

Maven被中国程序员接受应该是始于2008年,随后得到了越来越多的拥护者,现在也仍是一个被广泛使用的项目构建工具,通过将项目开发和管理过程抽象成一个项目对象模型(POM),然后将配置信息定义在pom.xml文件中。

那怎么通过pom.xml的配置就能获取到jar包、pom.xml配置文件从何而来等等,后面会介绍。

1.1 什么是Maven

官方解释是这么说的,“Maven是apache软件基金会组织维护的一款自动化构建工具,专注服务于Java平台的项目构建和依赖管理”。

通俗的说,Maven就是一个由Java语言编写的开源项目管理管理工具,主要用于管理Java依赖,还可以用于编译、打包以及发布。

特点列举如下: 

  1. 跨平台:无论是在Windows上,还是在Linux或Mac上,都可以使用同样的命令,接触过一些项目的朋友会有更深的体会。

  2. 易扩展:Maven命令都是以插件的形式集成进来的,可以将自己开发一些maven插件给其他人使用,非常方便开发发布项目。

1.2 Maven有什么用

Maven的基本原理很简单,采用远程仓库和本地仓库以及一个核心的配置文件pom.xml,pom.xml中定义的jar文件从远程仓库下载到本地仓库,各个项目使用同一个本地仓库的jar,同一个版本的jar只需下载一次,而且避免每个应用都去拷贝jar。

也不用手动去添加jar包(最早的时候都是手动导入jar,使用Ant之类的编译java项目),同时它采用了插件体系架构,所以maven的核心非常小,只有几兆大小的文件,在执行maven任务时,才会自动下载需要的插件。

那Maven解决了啥痛点,有啥好处呢?

(1)统一集中管理好所有的依赖包

传统项目中要升级包的时候,必须将原来的包找出来删掉,然后到官网下载,再把新的包放进去。过程中有可能出现下载的版本并不是想要的,又得重新找。

不仅浪费了查找下载和导入包的时间成本,还极大的增加了学习成本。

借助Maven只需要改一下pom文件中相应的版本即可,不用自己下载jar包 ,pom文件会自动下载并管理jar包,省去了手工劳动。在需要的时候,可直接通过简单的描述文件告诉 Maven,它会自动帮助程序员找出来,集成到项目中。

比如,用到了a-1.0.jar,而a-1.0.jar依赖于b-1.1.jar和c-1.5.jar,当我们通过Maven把a-1.0.jar引入之后,b-1.1.jar和c-1.5.jar会自动被引入进来。

(2)能够自动解决重复和冲突问题

同样的jar包重复的出现在不同的项目工程中,需要不停的复制粘贴。通过Maven能够自动解决重复,并为绝大部分的构建任务提供了已实现的插件,不再需要定义过程,甚至不需要再去实现这些过程中的一些任务。

再如,使用Maven关联jar就可以配置引用jar的版本,避免冲突,同时让开发人员的工作更轻松。

(3)可以统一每个项目的构建过程

对于非常庞大的项目,如银行核心系统可以分为存款、贷款、公共等,通常不使用package来划分模块,而是每一个模块对应一个工程,利于分工协作,而且模块之间还是可以发送消息的。

借助于Maven可以通过将一个项目拆分成多个工程,实现不同项目的兼容性管理。

除了这些,Maven还有以下作用:

  1. 集成编译,测试,打包,发布,部署,等一条龙服务。

  2. 开发项目不依赖开发工具,可随意挑选支持Maven的IDE。

  3. 采用同一种项目结构,比如:Java文件、资源文件、测试用例、静态资源、编译之后的class、打包之后jar的位置等等各种文件的位置。

总体来说,Maven算是所有开发者的福音。

二、Maven安装、配置与运行

我们要在自己的PC上架设大型机的z/OS(MVS)系统、写COBOL程序,需要安装仿真软件HercGUI和PCOMM,配置CONF文件等。写Java代码也类似,需要先安装jdk,要使用Maven,那么就需要在PC上安装Maven,然后了解Maven命令的执行过程,再进行相关配置。

问:系统运行java或者其他外部命令的时候,系统是如何找到这些命令的?

答:window中有个系统变量PATH,这个PATH的值是由很多目录的地址组成的,当我们执行一个命令的之后,系统会去PATH对应的所有目录中寻找我们运行的命令,找到了就可以直接运行,比如想快速启动其他的一些软件,可以将这些软件的设置到PATH变量中,就能在cmd命令中快速启动了。

2.1 maven安装

Eclipse自带的Maven通常会比较新,但不一定很稳定,而且往往也和在命令行使用的Maven不是同一个版本。比如常见的jar包下载不全或者是install打包报错等等。

主要是因为较新版本的Maven存在很多不稳定因素,容易造成一些难以理解的问题;其次,除了IDE,也经常还会使用命令行的Maven,如果版本不一致,容易造成构建行为的不一致,这是我们所不希望看到的。

所以应该在IDE中配置Maven插件时使用与命令行一致的Maven,最好就是不要用自带的maven,改为我们自己安装的Maven。

步骤如下:

  1. 检查,当前系统JAVA_HOME的环境变量

  2. 安装,下载并解压至非中文无空格路径下

  3. 配置,环境变量(MAVEN_HOME,Path)

  4. 验证,mvn -v 命令查maven版本信息

2.2 maven目录结构

  • bin:存放可以执行的文件

  • boot:含plexus-classworlds类加载器框架(不必关心)

  • conf:存放maven的配置文件(settings.xml)

  • lib:第三方的jar包,这些jar包位于lib中


settings.xml中有个localRepository标签,主要是配置本地仓库的路径,即本地下载的jar存放路径。当maven从远程仓库下载下来的插件,以及以后所有所用到的jar包都会放在这个目录中。

推荐采取用户范围的settings.xml,即系统用户目录.m2下的settings.xml,主要是为了避免无意识地影响到系统中的其他用户,其次为了方便升级,升级时不需要触动settings.xml文件。

在Eclipse环境中,点击菜单栏中的Window,然后选择Preferences,在弹出的对话框中展开左边的Maven项,选择User Settings子项,在右边的面板中,单击Browse...按钮,然后选择对应的settings.xml文件,设置完毕之后点击OK按钮。

2.3 mvn命令的执行过程

  1. 运行mvn命令a后,系统会到环境变量PATH对应的所有目录中寻找mvn命令,会在bin中找到可执行的mvn文件

  2. 执行mvn命令,并查找mvnsetting.xml文件,若在C:\Users\用户\.m2中没找到则到conf中查到并执行maven程序

  3. maven会到本地仓库的路径下,查找是否存在a插件,若没有则到中央仓库[repo.maven.apache.org]下载插件

  4. 运行插件,若系统找不到插件则会报错。

2.4 mvn常用命令说明

  • mvn clean:清理(默认为target文件夹)

  • mvn clean compile:清理并编译源代码至target文件夹

  • mvn clean test:运行清理和测试编译的源代码

  • mvn clean package:运行清理和打包

  • mvn clean install:运行清理并将打好的包安装到本地仓库

  • mvn clean deploy:运行清理和发布(部署)


上面的命令大部分都是连写的,也可以拆分分别执行,主要看个人喜好和使用需求,Eclipse Run as对maven项目会提供常用的命令。

三、Maven的坐标与依赖说明

3.1 Maven的坐标

在数学中,以平面直角坐标系为例,x轴通常画成水平方向,y轴通常画出竖直方向。坐标(x,y)表示这个点距离x轴为y,距离y轴为x的一点,任何一个坐标都能唯一标识该平面中的一点。

在生活中,地址位置也可以看成一种坐标。比如网购时需要填写地址信息,包括省、市、区、村/街道、小区名、楼号、单元号、门牌号等,那么快递小哥就会根据填写的具体地址派件。

(1)什么是坐标(Coordinates)?

在Maven中,坐标就好比每一个Java构件的身份证,通过坐标元素在仓库中进行唯一标识。 坐标元素包括groupId、artifactId、version、packaging、classfier。其中groupId、artifactId、version是必须要定义的,packaging是可选的(默认为jar),而classfier是不能直接定义的,需要结合插件使用。

坐标元素如下:

  • groupId:组id,机构名,公司名

  • artifactId:构件id,产品名,模块名

  • artifactId:版本号,例如1.0.0

  • package:构件的打包方式,如jar、war

(2)为什么使用坐标?

Maven中的Java构件非常多,如果Maven中没有坐标的概念,那么就无法来区分这些构件。不然使用了spring,去spring的官网下载jar包;使用hibernate,去hibernate的官网下载Jar包;使用Log4j,去log4j的官网下载jar包…..

有了Maven之后,只要我们提供正确的坐标元素,Maven就能找到对应的构件,先查找本地仓库,找不到再到远程仓库下载,如果没有配置远程仓库,会默认从中央仓库地址下载构件。

所以在项目中,对maven创建每一个项目、项目中的构建标注其坐标信息,算是强制性要求。只有这样,其他项目才能引用该项目的构件。

理解了Maven坐标,接下来就可以开始学习Maven的依赖管理,学习之前我们先看看Maven项目的核心 pom文件。

(3)pom文件介绍

POM(Project Object Model,项目对象模型)是Maven工程的核心配置文件,是一个XML文件,定义了项目的基本信息,用于描述项目如何构建,声明项目依赖,版本号,等等。

定义的POM稳定后,日常的Java代码开发工作中基本不会涉及到POM的修改,它能让项目对象模型最大程度地与实际代码相独立,可以称之为解耦。接着来,看看pom.xml文件主要标签的含义(坐标元素已介绍):

  • project:pom.xml文件中的顶层元素

  • modelVersion:指明POM使用的对象模型的版本(很少改)

  • name:项目的显示名称,通常用于maven产生的文档中

  • url:指定项目站点,通常用于maven产生的文档中

  • description:描述此项目,通常用于maven产生的文档中

  • properties:pom文件中的配置信息,可以配置全局变量

  • dependencies:依赖配置集,里面可以添加需要的jar的依赖信息

3.2 依赖说明

比如你要过河,没有桥怎么办,可以去借一条小船渡过去。那你与小船的关系仅仅是使用(借用)的关系。表现在代码上,可以理解为需要依赖一些东西才能实现相应的功能。

(1)什么是依赖?

在银行核心项目开发中也是同理,比如“存款”模块的交易需要查询客户信息,那么就依赖“客户”模块,再如“存款”模块的交易需要记账,那么就依赖“会计”模块。这就是所谓的依赖关系。

前文也提到了,这是maven的好处之一,仓库里面有各种各样的包,需要什么在pom.xml中通过坐标信息,添加依赖就好了,然后将这些信息放入pom.xml文件中的dependencies元素中即可。

(注:如果依赖的是自己或者团队开发的maven工程,需要先使用 install命令把被依赖的 maven工程的 jar包导入到本地仓库中)

根元素下project下的dependencies可以包含一个或者多个dependency元素,以声明一个或者多个项目依赖。大部分依赖声明只用包含基本坐标(groupId、artifactId、version),但在一些特殊情况下,其他元素至关重要:

  • type:依赖的类型,对应于项目坐标定义的packaging(默认jar)

  • scope:依赖的范围,下文会详解

  • optional:标记依赖是否可选

  • exclusions:排除传递性依赖,下文会详解

(2)依赖范围

依赖范围是用于决定pom.xml加载进来的jar包,在什么范围内使用生效,范围包括编译,运行,测试等场景。

比如,junit的jar包只有在测试的时候会用到,在项目部署的时候,用不到这个包;再如tomcat中自带了servlet-api,项目编译的时候会用到这个包,而项目发布的时候就不会用到这个包。

所以为了减少包导入时可能出现的冲突,maven引入了依赖范围这个概念,即我们上面提到的scope来解决这个问题。Maven中有主要有以下几种依赖范围:

  • compile:编译,测试,运行三种classpath都有效,会随着项目一起发布(如hibernate jar包)

  • test:测试范围有效,在编译打包、运行时都不会使用这个依赖(如junit jar包)

  • provided:编译和测试有效,最后不会随项目发布(如servlet-api)

  • runtime:测试和运行时依赖(如JDBC驱动)

  • system:测试和运行时依赖(如systemPath)

  • import :仅在类型为pom的依赖关系支持在部分

(注:关于间接依赖问题,依赖的jar包必须是compile范围,若是test范围,则发布的jar包不会包含test范围依赖的jar包和依赖关系。)

(3)传递性依赖

Maven的依赖是具有传递性的,能够自动加载我们引入的依赖包的依赖,而不必去手动指定,从而减少冲突,不用的功能不传递。

比如A->B,B->C,那么A间接的依赖于C,这就是依赖的传递性,其中A对于B是第一直接依赖,B对于C是第二直接依赖,C为A的传递性依赖。对于传递性依赖,依赖的范围如下表:

上图中可以发现一些规律。例如,第一直接依赖范围是Test,第二直接依赖范围是Compile,那么传递性依赖的范围就是Test;再如,第二直接依赖的范围是provided的时候,只传递第一直接依赖的范围也为provided的依赖,且传递性依赖的范围同样为provided。

(4)依赖版本的原则

依赖版本的原则,也称为依赖调节原则,是maven解决传递依赖时jar包冲突问题的方法。共有三种方法:

  1. optional:在dependency元素下的optional设置,是一个boolean值,true表示可选依赖不会被传递。如A->B,B->C,B->D,A对B直接依赖,B对C和D是可选依赖,那么在A中不会引入C和D。

  2. 最短路径原则:现实中可能存在这样的情况,如A->B->C->D->Z(1.0),E->D->Z(2.0),此时Z出现了2个版本,maven会使用Z(2.0),因为其路径更近。

  3. 最先声明原则:如果路径相同,maven 默认配置在前面的优先使用,如A->B->Z(1.0),E->D->Z(2.0),则使用Z(1.0),因为Z(1.0)最先声明。

(5)排除依赖

传递性依赖极大的简化了项目依赖的管理,但有些时候这种特性也会带来问题,它可能会把我们不需要或过时且不安全的jar包,也引入到了工程当中,导致项目结构变得更复杂。因此,就需要使用依赖排除,解决jar冲突问题。

可以先在依赖这个项目的pom.xml中去除想排除的依赖,再添加指定版本的依赖。需要指明所包含坐标和排除依赖包中所包含的依赖关系,即groupId和artifactId。(注:不需要添加 version)

例如:

例子中使用exclusions元素排除了B->C依赖的传递,也就是B->C不会被传递到A中。如果想要排除多个,可以先然后再添加 <exclusion>。

四、Maven仓库与私服的介绍

4.1 Maven仓库

前面聊“mvn命令的执行过程”就有提到仓库,简单的说,Maven仓库就是存放依赖包的地方。Maven仓库可简单分为本地仓库和远程仓库两类:

  • 本地仓库:指存于本机的仓库,默认地址为/C:\Users\用户\.m2,在setting.xml中的仓库目录位置指定,其中还包含了镜像、插件、代理等配置。

  • 远程仓库:远程仓库又可以分为中央仓库和私服。中央仓库架设在Internet上,是一个大而全的包仓库,包含了世界上绝大多数流行的开源Java包,以及源码等信息。

4.2 私服的介绍

打游戏时经常会听到私服,在Maven中不一样,一般指公司内部的私服,或是使用者自己搭建的maven仓库。它设在局域网内,通过代理广域网上的远程仓库,供局域网内的用户使用。主要用于缓解频繁从外网下载jar包资源的压力、加速Maven构建等,从而高效的使用Maven,而且使用私库作为缓存层,也相对安全一些。

比如,成本上千的项目团队,都从远程仓库中把需要依赖的构件下载到本地仓库,那对公司的网络要求也比较高;再如,自己开发的一些jar包给其他组使用,如果没有私服,可能需要手动发给别人或者上传到共享机器中,管理起来不是很方便。

◎没有使用私服的仓库构件下载

建立自己的私服,有三种开源的专用于Maven仓库管理软件,可以用来帮助我们建立私服:

  1. Apache基金会的Archiva

  2. JFrog的Artifactory

  3. Sonatype的Nexus(该款最流行)

◎使用私服的仓库构件下载

本地构建发布到私服,常见的方式如下:

  1. 使用maven部署构件至nexus私服

  2. 手动部署第三方构件至nexus私服(如短信发送商的jar包,这个包远程仓库是不存在的,我们要将这个包上传到私服供所有开发使用)

五、Maven的生命周期与插件

在Maven中有五大核心概念,除了前文已经总结过的坐标、依赖以及仓库之外,还有生命周期和插件。掌握了这些,也就基本上把握了Maven的命脉,其它Maven的知识主要是具体场景的应用,大体上都离不开这五大核心概念。

5.1 Maven的生命周期

人的生命周期有生、老、病、死;金融产品有潜在、兴起、成长、成熟和衰退;maven也不例外,它的生命周期包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署、站点生成等几乎所有的项目构建过程,而且易扩展、更规范。

maven的生命周期是抽象的,其实际行为都是由插件来完成的,因此maven的生命周期和插件两者协同工作,密不可分。这也正是maven的强大之处,这种思想与设计模式中的“模板方法”非常相似,既保证了Maven整体框架的轻便,也最大程度的扩展性。

maven有三套相互独立的生命周期,“相互独立”,其生命周期并不是一个整体。分别是cleandefaultsite

  • clean:清理项目

  • default:构建项目(如编译,测试,打包等)

  • site:建立项目站点,发布站点。

5.2 生命周期详解

知道了每套生命周期的大概用途和相互关系以后,接下来逐个详细看一下每套生命周期。每套生命周期里包含一些阶段(phase),与日常中命令行的输入往往相对应。

以clean生命周期为例,它包含的阶段有pre-cleancleanpost-clean。当我们调用pre-clean的时候,只有pre-clean阶段后执行;当我们调用clean的时候,pre-clean和clean阶段会按顺序执行;当我们调用post-clean的时候,pre-clean、clean和post-clean都会按顺序执行。

clean生命周期包含了三个阶段:

  1. pre-clean:执行需要在clean前完成的工作

  2. clean:移除所有上一次构建生成的文件

  3. post-clean:执行需要在clean后立刻完成的工作

site生命周期包含了以下阶段:

  1. pre-site:执行些需要在生成站点文档之前完成的工作

  2. site:生成项目的站点文档

  3. post-site:执行需要在生成站点文档之后完成的工作,并且为部署做准备

  4. site-deploy:将生成的站点文档部署到特定的服务器上

default是maven中最重要的部分,它构建的核心功能,绝大部分工作都发生在这个生命周期中。生命周期包含了以下阶段:

  1. validate

  2. generate-sources

  3. process-sources

  4. generate-resources

  5. process-resources 复制并处理资源文件至目标目录,准备打包

  6. compile 编译项目的源代码

  7. process-classes

  8. generate-test-sources

  9. process-test-sources

  10. generate-test-resources

  11. process-test-resources 复制并处理资源文件至目标测试目录

  12. test-compile 编译测试源代码

  13. process-test-classes

  14. test 使用合适的单元测试框架运行测试。测试代码不会被打包或部署

  15. prepare-package

  16. package 接受编译好的代码,打包成可发布的格式,如JAR

  17. pre-integration-test

  18. integration-test

  19. post-integration-test

  20. verify

  21. install 将包安装至本地仓库,以让其它项目依赖

  22. deploy 将最终的包复制到远程的仓库,以让其它开发人员与项目共享

(注:运行任何一个阶段的时候,它前面的所有阶段都会被运行,如 mvn clean调用clean生命周期的clean阶段。实际执行的阶段为clean生命周期的pre-clean和clean阶段。这也就是为什么我们运行mvn install的时候,代码会被编译,测试,打包)

5.3 Maven的插件

通过上面的生命周期我们可以了解到,生命周期中处理都是插件完成的,插件可以和maven生命周期的阶段进行绑定,也可以通过mvn命令的方式调用直接运行。总之,Maven中插件非常重要,必不可少。如下图:

maven中的插件以jar的方式存在于仓库中,和其他构件是一样的,也是通过坐标进行访问,插件中的每个功能就叫做插件的目标(Plugin Goal),每个插件中可能包含一个或者多个插件目标,即上图的每一个功能对应一个目标。

maven插件的安装机制就不细聊了,官方文档或文章有很多,这里就提一提插件绑定。插件绑定主要分为内置绑定和自定义绑定两大类。

  1. 内置绑定:指为了让maven开箱即用,maven开发了很多默认的插件来完成每个生命周期对于阶段的一些工作。(有兴趣的朋友可以去看源码,借鉴他们的设计思路,开发自己的插件)

  2. 自定义绑定:指为了完成更多个性化的任务,maven社区的大牛开发了很多的插件,比如自动打包并且发布到服务器然后重启服务器的插件;或者自动打包自动运行打包好的构件等。

以往在日常工作中,使用maven只是机械的执行配置或命令,对其中的原理与过程并无了解。近日接触了一帮刚做Java的兄弟,遇到问题后被问到一些细节答不上来。所以整理学习了下,希望对想要了解的maven的朋友们有所帮助。如果大家想全面掌握maven,推荐大家去看许晓斌写得《maven实战》。

参考书籍或文献:

1.许晓斌.《maven实战》,2011年

2.许晓斌.Maven十年,来认识下》,2011年

3.AlanLee.《Maven系列文章》,2016年

4.路人甲.《Maven系列文章》,2018年

5.果冻想.《Maven系列文章》,2019年

点击查看近期推送

 

“不动户/久悬户”的悬疑故事

银行卡业务介绍解析

独孤木--结案之后

银行核心系统之错账处理

核心银行系统 之十一 存款(一)

银行系统 - [账户体系]解析与关键点

核心银行系统 之九 贷款(四)

古建筑与今天的金融科技

分布式和集中式的对比

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
五分钟快速掌握Maven的核心概念
IDEA中Maven Project视图用法
Maven和Ant对比
Maven系列 - 需要先了解什么
[转]Maven与nexus关系
Maven学习 (四) 使用Nexus搭建Maven私服
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服