前言

这次来说说maven这玩意,同样还是那句话,maven对我而言只是工具,一些常规操作已经足够了,有空有兴趣才会去深入研究它。接下来会记录下自己使用maven时需要注意和理解的地方,至于那些基本概念和环境配置的问题,相信大家都懂。

仓库

maven仓库可分为本地仓库和远程仓库。

如果公司自己有搭建maven私服,那么还可以细分为本地仓库、私服仓库(内网)、中央仓库(外网)。

私服是指公司内网搭建的maven仓库,可供公司内部人员使用。

pom.xml里依赖jar包的寻找流程:

  • 本地仓库找,找到直接用,不需要联网。
  • 本地找不到,私服仓库找,找到就下载到本地,以供下次直接使用。
  • 私服找不到,会直接去中央仓库找,然后下载到私服、本地,以供下次直接使用。

没私服的话,本地仓库找不到就直接去中央仓库找。

构建过程

maven构建过程的各个环节,代表maven工作流程的某个阶段

  1. 清理:将以前编译得到的旧的class字节码文件删除,为下一次编译做准备。
  2. 编译:将Java源程序编译成class字节码
  3. 测试:自动测试,自动调用junit程序
  4. 报告:测试程序执行的结果。
  5. 打包:动态Web工程打war包,java工程打jar包
  6. 安装:将打好的包安装到本地仓库中,以便其他的项目可以调用。
  7. 发布:拷贝最终的工程包到远程仓库,以供其他开发人员使用。

maven实际工作时,顺序不一定从上到下。几个阶段是重要阶段,并不是maven的全部阶段。具体执行什么阶段,执行顺序是啥,依赖于它的生命周期。

生命周期

三套相互独立的生命周期,互不影响,定义了构建环节的执行顺序。

  1. clean生命周期:构建之前进行一些清理工作。
  2. default生命周期:常用且核心,包括编译、测试、打包、安装、发布等
  3. site生命周期:生成项目报告、站点。发布站点。

依赖上述的构建过程和生命周期,maven执行任何一个阶段的时候,它前面的所有阶段都会执行

例如我们执行 mvn install 的时候,代码会被编译,测试,打包。但不会clean(清理),因为install和clean是在不同的生命周期里,但我们可以结合使用,如:mvn clean install

idea内置maven界面也说明这一点,点击生命周期的某一个阶段,maven会把前面到此阶段都执行下,不信你可以试试。

maven命令

除了通过idea的界面操作maven,我们也可以手打命令,不然在linux系统上你怎么搞?

  • 清理 mvn clean
  • 编译 mvn compile
  • 测试 mvn test
  • 打包 mvn package
  • 安装 mvn install
  • 发布 mvn deploy

执行maven构建命令,必须在pom.xml所在的目录


根据maven生命周期,当你执行mvn install时, compile、test、package、intall会依次执行,mvn deploy同理。

实际开发中,我都是直接敲命令编译打包安装,用得最多的是

mvn clean install -Dmaven.test.skip=true -U

加上clean是先把文件清理干净,100%确保install后是最新修改的文件。

如果当前项目并不需要被任何其他项目依赖,就没必要install了,执行mvn clean package即可

mvn命令支持带参数

  • -U :该参数能强制让Maven检查所有SNAPSHOT依赖更新,确保集成基于最新的状态。
  • -Dmaven.test.skip=true :不执行测试用例,也不编译测试用例类。
  • -DskipTests :不执行测试用例,但编译测试用例类生成相应的class文件至target/test-classes下。
  • -P : 多环境打包(后面会说)

插件

maven仓库除了保存jar包,还有插件。核心程序仅定义了抽象的生命周期,具体工作还是得由特定的插件来完成。

一般我使用maven-compiler-plugin 插件来编译,定义的jdk版本一定要跟你开发使用的jdk版本一致,不然后续打包会出错等各种奇怪问题。

pom.xml的build节点里

<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin></plugins>
</build>

依赖范围

限制jar包的使用范围。

<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.3</version><scope>compile</scope>
</dependency>
  • compile:编译、测试、部署运行都要参与
  • test:仅参与测试,包括测试代码的编译、运行
  • provided:可以参与编译、测试,但打包不会引入

一张表格来总结

上述3个比较常见,还有另外3个不常见的

  • runtime:无需参与编译、后期测试和运行周期需参与,一般用于数据库驱动jar包
  • system:jar包从本地磁盘路径拿,不用在maven仓库,一般加个systemPath节点表示具体路径
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.3</version><scope>system</scope><systemPath>../xx/xx.jar</systemPath>
</dependency>
  • import:导入另一jar包的东西,仅支持在<dependencyManagement>中定义(后续有例子)

打包方式

packaging节点里

<groupId>com.goku</groupId>
<artifactId>goku-manage</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
  • pom:依赖文件打包,打包后可以作为其他项目的maven依赖,子工程继承父工程,子工程可直接使用父工程的配置,一般用在聚合工程来做jar包的版本控制。
  • jar:普通项目打包,开发时要引用通用类,打成jar包便于存放管理。SpringBoot内置tomcat,打成jar包可直接运行。
  • war:web项目打包,打成war包部署到服务器。

聚合与继承

聚合工程里有多个pom.xml

父工程通过modules聚合子工程,该工程执行maven命令时,2个子工程也会执行

<modules><module>goku-user</module><module>goku-order</module>
</modules>

子工程通过parent标签继承父工程,可直接引用父工程的配置项

<parent><groupId>com.goku</groupId><artifactId>goku-manage</artifactId><version>1.0-SNAPSHOT</version>
</parent>

至于聚合模块的好处有很多,真真切切让我感受到的有其二

  • 依赖包划分合理,职责结构清晰,不存在一个庞大的pom.xml。
  • 内部代码改动后只需要编译当前工程,耗时减少。特别适合分布式项目。

统一版本号

聚合工程里,版本号可以统一配置,统一管理。同个公司的不同项目,所有依赖包版本最好相同。

有些公司会单独建一个工程,只用来统一版本号,打包成pom形式,给公司内部各个项目继承。

顶层父工程的pom文件里的properties节点

<properties><java.version>1.8</java.version><plugin.jdk.version>1.8</plugin.jdk.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring-boot.version>2.1.3.RELEASE</spring-boot.version><fasterjson.version>1.2.12</fasterjson.version>
</properties>

dependency的version引用配置好的版本号

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>${spring-boot.version}</version>
</dependency>

dependencyManagement统一管理版本

请注意<scope>import</scope>

<dependencyManagement><dependencies><dependency><!-- Import dependency management from Spring Boot --><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.0.0.RELEASE</version><type>pom</type><!--导入spring-boot-dependencies里的配置,一定程度上解决了单继承问题。--><scope>import</scope></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>${slf4j.version}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fasterjson.version}</version></dependency></dependencies></dependencyManagement>

说明:

  • dependencyManagement只是声明依赖,不会引入依赖。子模块不会继承父模块中
  • dependencyManagement所有预定义的depandency,若想使用还需引入需要的依赖,只不过不需要加version节点了。
  • 据说在父模块中严禁直接使用dependencies预定义依赖,应该做到按需引入。

使用import scope解决maven继承(单)问题

测试环境 maven 3.3.9

想必大家在做SpringBoot应用的时候,都会有如下代码:

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.3.3.RELEASE</version>
</parent>

继承一个父模块,然后再引入相应的依赖

假如说,我不想继承,或者我想继承多个,怎么做?

我们知道Maven的继承和Java的继承一样,是无法实现多重继承的,如果10个、20个甚至更多模块继承自同一个模块,那么按照我们之前的做法,这个父模块的dependencyManagement会包含大量的依赖。如果你想把这些依赖分类以更清晰的管理,那就不可能了,import scope依赖能解决这个问题。你可以把dependencyManagement放到单独的专门用来管理依赖的pom中,然后在需要使用依赖的模块中通过import scope依赖,就可以引入dependencyManagement。例如可以写这样一个用于依赖管理的pom:

<project><modelVersion>4.0.0</modelVersion><groupId>com.test.sample</groupId><artifactId>base-parent1</artifactId><packaging>pom</packaging><version>1.0.0-SNAPSHOT</version><dependencyManagement><dependencies><dependency><groupId>junit</groupId><artifactid>junit</artifactId><version>4.8.2</version></dependency><dependency><groupId>log4j</groupId><artifactid>log4j</artifactId><version>1.2.16</version></dependency></dependencies></dependencyManagement>
</project>

然后我就可以通过非继承的方式来引入这段依赖管理配置

<dependencyManagement><dependencies><dependency><groupId>com.test.sample</groupId><artifactid>base-parent1</artifactId><version>1.0.0-SNAPSHOT</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement><dependency><groupId>junit</groupId><artifactid>junit</artifactId>
</dependency>
<dependency><groupId>log4j</groupId><artifactid>log4j</artifactId>
</dependency>

注意:import scope只能用在dependencyManagement里面

这样,父模块的pom就会非常干净,由专门的packaging为pom来管理依赖,也契合的面向对象设计中的单一职责原则。此外,我们还能够创建多个这样的依赖管理pom,以更细化的方式管理依赖。这种做法与面向对象设计中使用组合而非继承也有点相似的味道。

那么,如何用这个方法来解决SpringBoot的那个继承问题呢?

配置如下:

<dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>1.3.3.RELEASE</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
</dependencies>

这样配置的话,自己的项目里面就不需要继承SpringBoot的module了,而可以继承自己项目的module了。

我在工作中是这样使用Maven相关推荐

  1. 2013年工作中遇到的20个问题:181-200

    每个人在工作中遇到的问题,很多都是类似的.了解别人遇到的问题,自己遇到的时候就可以很快地解决它. 很多人不屑于这种"细节问题",但我想说,掌握这些细节问题一次可能只能帮你节省1s的 ...

  2. 2013年工作中遇到的20个问题:241-260

    2019独角兽企业重金招聘Python工程师标准>>> 241.DAO层很多代码都是重复的. 分页:记录列表,多少条记录: 是否授权:授权的,没授权的. 一定要写一个功能强大的高度复 ...

  3. 工作中使用到的单词(软件开发)_2022-02-26_备份

    ■原文 工作中使用到的单词(软件开发)_sun0322-CSDN博客 目录 ■常用链接 ■2020/03/15  (最初整理  242个单词) 2020 6/28 整理 2020 6/29 整理 20 ...

  4. idea中为啥要用maven

    maven是啥?Maven是一个项目管理和综合工具.就是项目管理工具呀!那和svn  git有区别吗?是一样的呀!联想,在什么都不知道的情况下,瞎想. 了解下svn  git是项目代码的管理工具.对项 ...

  5. 工作中遇到的问题汇总

    最近在工作中遇到了很多小问题,决定在这里把他们一一整理出来,以供以后遇到了方便查阅. 1.最近在做一个练手项目,用到了spring,用maven管理jar,在运行测试代码的时候总会报这样一个错误: N ...

  6. 工作中使用到的单词(软件开发)_2021-12-26_备份

    ■原文 工作中使用到的单词(软件开发)_sun0322-CSDN博客 目录 ■常用链接 2020 6/28 整理 2020 6/29 整理 2020 7/6 整理 ■2020/10/07 以降整理 ■ ...

  7. 阿里面试官:你在工作中是如何做代码重构的?

    我是猿人,一个热爱技术.热爱编程的IT猿.技术是开源的,知识是共享的! 写作是对自己学习的总结和记录,如果您对 Java.分布式.微服务.中间件.Spring Boot.Spring Cloud等技术 ...

  8. 工作中使用到的单词(软件开发)_2023_0316备份

    原文: 工作中使用到的单词(软件开发)_http://42.62.43.136:8081/_sun0322的博客-CSDN博客 目录 ■Java学习汇总 ■常用链接 ■2020/03/15  (最初整 ...

  9. 工作中遇到的问题(DS)

    我是目录 Jpa的criteriaBuilder.in 使用 @RequestParam用法(非必填)加与不加的区别 关于postman测试报400/405错误 网页调试打断点 Java返回一个不占内 ...

最新文章

  1. 【收藏】Oracle存储过程读写文件
  2. 【MM模块】Contract 采购合同简介
  3. 身份验证错误错误指定的句柄无效_基于 Web 端的人脸识别身份验证「实践」
  4. ionic android 本地存储,ionic2/3本地数据存储storage
  5. 【HTML5】HTML5基础语法汇总
  6. PyQt5学习--基本窗口控件--加载文件-QFileDialog
  7. 【干货】python正则表达式应用笔记
  8. HBase MemStore和Compaction剖析
  9. c#遍历匹配串口(向每个串口发数据,根据返回数据确定是否为所需串口)
  10. 小米路由器挂php,小米路由器mini 安装openWrt+更新源+挂载U盘+安装python
  11. Pattern 模式器: Matcher 匹配器
  12. 计算机显示程序错误,电脑老是提示应用程序错误怎么办
  13. 上级对下级用通知合适吗_【判断题】通知只能作为下行文使用,下级对上级不能使用通知。 ( )...
  14. 谷歌浏览器chorme,wap浏览器,字…
  15. JS验证邮箱 身份证 VISA 卡[转]
  16. 中国轨道交通设备行业建设投资规模及十四五产量趋势研究报告2021-2027年版
  17. 将孤独视作挑战,倾听内心,自我对话
  18. server多笔记录拼接字符串 sql_第四章、SQL Server数据库查询大全(单表查询、多表连接查询、嵌套查询、关联子查询、拼sql字符串的查询、交叉查询)...
  19. 心理健康咨询问卷数据集
  20. mysql秒退原因_解决MySql客户端秒退问题(找不到my.ini)

热门文章

  1. java for 面试题_Java面试题整理
  2. 企业的培训体系:145页企业培训年度规划和培训体系的建立
  3. AD维护管理工具详解(一)dcdiag
  4. Redis学习总结(18)——Redis 常见面试题复习
  5. Java基础学习总结(110)——Java主要技术点总结
  6. Rpc框架dubbo-client(v2.6.3) 源码阅读(二)
  7. node js、npm、homebrew、cocoapod、git、hexo
  8. 阿里影业宣布新战略:“新基础设施”赋能电影产业
  9. RxJS 系列之一 - Functional Programming 简介
  10. hdu 5964:平行四边形 【计算几何】