Maven的讲解
1、基础知识
1.1、核心过程
Java项目的生命周期大致是 :开发–>编译–>测试(可选)–>打包–>部署(可选)
-
mvn跟大部分仓库机制一样,有本地和远程mvn仓库(第一次从远端(官方仓库)下载,保存在本地.m2文件夹中
~/.m2/repository
,后面会优先用本地) -
核心通过
pom.xml
来记录管理各种包依赖、父子关系、版本…etc -
pom.xml
中名字有不少,最基本的也就几个dependency,module,parent
,裸用就dependency即可 -
dependency是核心,那么如何唯一确定一个包,就通过它的子元素–称为坐标唯一确定。包括
xxID,version,type
… -
mvn最常用的命令无外乎
clean,install,package,test,compile
(下面说) -
最常见的包关系就是**“递进依赖”** 和 “重复依赖” (递进:A包依赖B包,B又依赖C包,mvn把这条线都下下来。重复:项目同时依赖了A和B包,它们又同时依赖C包,mvn根据策略只导一个)
1.2、常见命令对比
在Maven插件里, 可以看到一系列的命令: clean, compile, test, package, install, deploy
等,这里简要说一下他们的区别:
- compile: 这个就是单纯编译, 把java文件变为class文件, 不会做任何其他的事. (基本是必须步骤. 极少单独使用)
- package: 就是最常用的把当前项目打包 (常用)
- 如果pom文件设置了打war包, 命令就等价于
mvn war:war
- 如果pom文件设置是jar包, 命令就等价于
mvn jar:jar
- 如果pom文件设置了打war包, 命令就等价于
- install: 这个就是先执行package的操作, 然后把包放入本地的mvn仓库里, 比如本地的
.m2
目录中 - deploy: 这个是在install的基础上, 再上传到远端maven仓库, 需要单独配置.
然后以上命令一般默认带mvn test
,也就是会执行测试操作, 所以为了加快速度, 经常测试里会使用mvn -DskipTests
. 或是-Dmaven.test.skip=true
(推荐第二个, 它是既不编译测试类, 也不执行, 第一个会编译.)
2、Maven常见的错误分析
2.1、 缺失包
这个是最不能接受的了,mvn直接不去下该下的包,然后你发现IDE自己也不去下,也不告诉你原因。。然后大家的解决办法就是选择去命令行无脑clean或者是重新导入再重新让mvn下?还是来探究一下。。
- 先检查包是否是私有包(或版本不是官方的,自己修改过,检查方法参考步骤3)
- 检查本地仓库是否存在 (去.m2/repository看)
- 检查你目前的远程库(默认是官方库)是否有你的包/版本(查询地址)
- 查看mvn配置是否出错
- 刷新…重新导入试试
- 还可以用闫哥给咱们的脚本文件去清理一下咱们本地的maven仓库
- 如果在导入jar包时,明明已经finished,但还是一直在加载,那么就可以修改IDEA中maven的配置信息,如importing信息
2.2、 包冲突
这可能是很头疼的事之一,因为java项目依赖的包很多,版本号也点的飞起,导致有冲突经常调来调去,一个项目调好了另一个又报错了。。 这里来清晰的理一下思路,避免拆东墙补西墙出现。
我的思路:
-
IDEA下安装mvn-tree插件,看杂乱的xml文件简直要狗带,然后快速显示id,版本号等标识信息
-
先确认是否项目使用了非官方/内部包,那肯定是会出错的,好比你自己定义了个新函数。。
-
排除了低级错误之后, 一般大点的项目,都会很很多个module, 然后每个模块都有个pom.xml ,那肯定会有大家共同使用了一个包,但是版本不同的情况. 这会导致什么呢? (通过mvn-tree插件查看)
-
包依赖的java版本不同,但是你最后运行程序肯定只有一个Java环境. 一般高版本可以兼容低版本.
-
包版本不同,可能导致函数有些调用方法不存在或者改名字了. 那就要看优先使用的是高,还是低版本的jar包。
2.3、 打包和发布
首先,我们把Java程序的编译打包过程搞清楚. 不是上来就对着mvn命令去敲,出了问题再去临时查查….
-
我们编写的
xx.java
, 要通过java虚拟机编译为xx.class
字节码,这一步我们称之为编译 , -
class文件汇聚在一起,可以打包为一个
xx.jar/war
. (如果java文件更新了,那么必须得重新编译)再看看IDEA默认生成maven项目的结构:
src
文件夹:- main : 代码类
- test :对应main结构的各种Test类
- resources(可选): 放配置文件
pom.xml
再看看mvn的命令本质:
maven能执行各种操作,包括clean,install,package,assembly本质(我理解)都是调用的模块,底层估计就是java写的代码插件一样…. 比如打jar包模块,打war包模块, 整合打包模块,清理脚本… 只不过有些模块是内置的. 不需要你单独去导入.
-
2.3.1、打包
1.直接打包当前项目代码
首先需要在pom.xml配置编译模块 (注意模块选择有好几个,各自有侧重–比如专门把依赖一起整合的)
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
常用命令是:
#跳过测试打包到target/下.包名为pom文件中定义的"artifactID-version"
mvn package -DskipTests
#如果希望提前先清理一下target/目录,或者直接覆盖生成包. 注意这样会清掉原本所有的包.慎用
mvn clean package -DskipTests
执行完成后,在target下加入有一个demo-1.0.jar 的包. 它的内部结构是什么呢?
-
com (里面是对应的子文件夹,具体是class文件)
-
META-INF (里面有pom.xml文件和自动生成的pom.properties记录了基本的版本K-V)
-
xx.properties (都在根目录,对应的是之前maven项目的resources文件夹下内容)
可以看出结构还是很简单的.基本就是把原本项目的最核心的东西抽了出来.
2.4、下载问题
这个问题很简单,根本原因就是maven原始的中央仓库是国外的,本质就是wall的原因,我们以及都配置过阿里的mvn仓库。所以这个问题不用考虑了。
2.5、后续
有个很重要的问题我一直在想:
Java如此重度依赖各种工具插件,自动补全等. 那离开了IDE,如何生存呢…
工具本质是提高做事效率。我想不会有人为了使用XML,JSON,YAML去单独看一本Oxxly的厚书. 也不会有人愿意用一下ant,mvn,gradle或是svn,git就又去钻很久各种细节. 所以Docker这种容器化技术之所以能在Unix系崛起如此之快… 的确是因为大家更喜欢Win这种开箱即用,而不是到处重复折腾环境,折腾编译,折腾部署.