我在工作中是这样使用Maven
前言
这次来说说maven这玩意,同样还是那句话,maven对我而言只是工具,一些常规操作已经足够了,有空有兴趣才会去深入研究它。接下来会记录下自己使用maven时需要注意和理解的地方,至于那些基本概念和环境配置的问题,相信大家都懂。
仓库
maven仓库可分为本地仓库和远程仓库。
如果公司自己有搭建maven私服,那么还可以细分为本地仓库、私服仓库(内网)、中央仓库(外网)。
私服是指公司内网搭建的maven仓库,可供公司内部人员使用。
pom.xml里依赖jar包的寻找流程:
- 本地仓库找,找到直接用,不需要联网。
- 本地找不到,私服仓库找,找到就下载到本地,以供下次直接使用。
- 私服找不到,会直接去中央仓库找,然后下载到私服、本地,以供下次直接使用。
没私服的话,本地仓库找不到就直接去中央仓库找。
构建过程
maven构建过程的各个环节,代表maven工作流程的某个阶段
- 清理:将以前编译得到的
旧的class字节码文件删除
,为下一次编译做准备。 - 编译:将Java源程序
编译成class字节码
。 - 测试:自动测试,
自动调用junit程序
。 - 报告:测试程序执行的结果。
- 打包:动态Web工程
打war包
,java工程打jar包
。 - 安装:
将打好的包安装到本地仓库中
,以便其他的项目可以调用。 - 发布:
拷贝最终的工程包到远程仓库
,以供其他开发人员使用。
maven实际工作时,顺序不一定从上到下。几个阶段是重要阶段,并不是maven的全部阶段。具体执行什么阶段,执行顺序是啥,依赖于它的生命周期。
生命周期
三套相互独立的生命周期,互不影响,定义了构建环节的执行顺序。
- clean生命周期:构建之前进行一些清理工作。
- default生命周期:常用且核心,包括编译、测试、打包、安装、发布等
- 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相关推荐
- 2013年工作中遇到的20个问题:181-200
每个人在工作中遇到的问题,很多都是类似的.了解别人遇到的问题,自己遇到的时候就可以很快地解决它. 很多人不屑于这种"细节问题",但我想说,掌握这些细节问题一次可能只能帮你节省1s的 ...
- 2013年工作中遇到的20个问题:241-260
2019独角兽企业重金招聘Python工程师标准>>> 241.DAO层很多代码都是重复的. 分页:记录列表,多少条记录: 是否授权:授权的,没授权的. 一定要写一个功能强大的高度复 ...
- 工作中使用到的单词(软件开发)_2022-02-26_备份
■原文 工作中使用到的单词(软件开发)_sun0322-CSDN博客 目录 ■常用链接 ■2020/03/15 (最初整理 242个单词) 2020 6/28 整理 2020 6/29 整理 20 ...
- idea中为啥要用maven
maven是啥?Maven是一个项目管理和综合工具.就是项目管理工具呀!那和svn git有区别吗?是一样的呀!联想,在什么都不知道的情况下,瞎想. 了解下svn git是项目代码的管理工具.对项 ...
- 工作中遇到的问题汇总
最近在工作中遇到了很多小问题,决定在这里把他们一一整理出来,以供以后遇到了方便查阅. 1.最近在做一个练手项目,用到了spring,用maven管理jar,在运行测试代码的时候总会报这样一个错误: N ...
- 工作中使用到的单词(软件开发)_2021-12-26_备份
■原文 工作中使用到的单词(软件开发)_sun0322-CSDN博客 目录 ■常用链接 2020 6/28 整理 2020 6/29 整理 2020 7/6 整理 ■2020/10/07 以降整理 ■ ...
- 阿里面试官:你在工作中是如何做代码重构的?
我是猿人,一个热爱技术.热爱编程的IT猿.技术是开源的,知识是共享的! 写作是对自己学习的总结和记录,如果您对 Java.分布式.微服务.中间件.Spring Boot.Spring Cloud等技术 ...
- 工作中使用到的单词(软件开发)_2023_0316备份
原文: 工作中使用到的单词(软件开发)_http://42.62.43.136:8081/_sun0322的博客-CSDN博客 目录 ■Java学习汇总 ■常用链接 ■2020/03/15 (最初整 ...
- 工作中遇到的问题(DS)
我是目录 Jpa的criteriaBuilder.in 使用 @RequestParam用法(非必填)加与不加的区别 关于postman测试报400/405错误 网页调试打断点 Java返回一个不占内 ...
最新文章
- 【收藏】Oracle存储过程读写文件
- 【MM模块】Contract 采购合同简介
- 身份验证错误错误指定的句柄无效_基于 Web 端的人脸识别身份验证「实践」
- ionic android 本地存储,ionic2/3本地数据存储storage
- 【HTML5】HTML5基础语法汇总
- PyQt5学习--基本窗口控件--加载文件-QFileDialog
- 【干货】python正则表达式应用笔记
- HBase MemStore和Compaction剖析
- c#遍历匹配串口(向每个串口发数据,根据返回数据确定是否为所需串口)
- 小米路由器挂php,小米路由器mini 安装openWrt+更新源+挂载U盘+安装python
- Pattern 模式器: Matcher 匹配器
- 计算机显示程序错误,电脑老是提示应用程序错误怎么办
- 上级对下级用通知合适吗_【判断题】通知只能作为下行文使用,下级对上级不能使用通知。 ( )...
- 谷歌浏览器chorme,wap浏览器,字…
- JS验证邮箱 身份证 VISA 卡[转]
- 中国轨道交通设备行业建设投资规模及十四五产量趋势研究报告2021-2027年版
- 将孤独视作挑战,倾听内心,自我对话
- server多笔记录拼接字符串 sql_第四章、SQL Server数据库查询大全(单表查询、多表连接查询、嵌套查询、关联子查询、拼sql字符串的查询、交叉查询)...
- 心理健康咨询问卷数据集
- mysql秒退原因_解决MySql客户端秒退问题(找不到my.ini)
热门文章
- java for 面试题_Java面试题整理
- 企业的培训体系:145页企业培训年度规划和培训体系的建立
- AD维护管理工具详解(一)dcdiag
- Redis学习总结(18)——Redis 常见面试题复习
- Java基础学习总结(110)——Java主要技术点总结
- Rpc框架dubbo-client(v2.6.3) 源码阅读(二)
- node js、npm、homebrew、cocoapod、git、hexo
- 阿里影业宣布新战略:“新基础设施”赋能电影产业
- RxJS 系列之一 - Functional Programming 简介
- hdu 5964:平行四边形 【计算几何】