概念
众所周知,Maven是一款自动构建化工具,那么什么是构建呢?
首先,补充一下,Maven是构建化工具,只服务于java平台。它本身是java写的。构建并不等同于创建。它是以java源文件、框架配置文件、JSP、HTML、图片等资源为“原材料”去生产一个可以运行的项目的过程。(这个生产的过程就称作为构建)
注意:它是一个过程,而不是一种操作。
构建这个过程有三个要点:编译、部署、搭建
编译:java文件通过编译变成class文件(也称字节码文件)然后交给JVM去执行
部署:一个项目最终运行的并不是它本身,而是它的编译结果(编译结果才能在服务器上执行)
搭建:指的是环境的搭建(例如javaweb项目要有tomcat的运行环境,Maevn工程中也要用到Maven的pom.xml中所引入的环境依赖)
Maven的常用命令
①clean(mvn clean)
意为清理,清理target资源包中的全部内容,包括target这个包也会被清理掉
②compile(mvn compile)
意为编译,编辑程序文件,把相应的程序文件编译为字节码文件(class文件),方便执行,编译后的文件会放到Maven项目的target资源包中的classes目录下
③test(mvn test)
意为测试,编译测试程序
④package(mvn package)
意为包装/打包,将项目打包形成一个该项目的jar包或war包(取决于你的打包方式),这个包可放在Tomcat中的webapp中运行,运行后会加载出该项目中相应的包与文件
⑤install(mvn install)
意为安装,操作基本与package相同,不同的是,它打包后还会安装到你的Maven本地仓库中
⑥deploy(mvn deploy)
意为部署,操作基本与install相同,不同的是,它除了安装到Maven本地仓库中,还会安装到Maven的中心仓库。
?package、install、deploy三者的关系图:
常用的依赖范围(scope):
compile依赖范围(scope的默认值是compile)
对主程序是否有效:有效
对测试程序是否有效:有效
是否参与打包:参与
是否参与部署:参与
test依赖范围
对主程序是否有效:无效
对测试程序是否有效:有效
是否参与打包:不参与
是否参与部署:不参与
provided依赖范围(意为这个包是从容器中提供的)
对主程序是否有效:有效
对测试程序是否有效:有效
是否参与打包:不参与
是否参与部署:不参与
那么,看到provided,不禁让人思考一个问题,什么是容器?
????????参考了一些其他文章之后,我的个人理解是:容器指的是包含了完整的运行环境,应用所需的全部依赖和类库以及其他的class文件和配置文件等的一个镜像包。它封装了运行程序所必须的相关细节,比如一个程序中,有很多依赖关系,那么运行这些程序时,会先在容器中寻找这些依赖,如果找不到程序中所用到的相关依赖则会报异常。如Spring中的IOC,如果你的项目中要用到一些类、接口的对象及其属性,就要把类和接口先用@Component把该类或接口注入到Spring容器中,实现控制反转,实现后我们才可以用@Autowired把他们的对象或属性注入到被依赖的类中。
?直接放图加深理解
BookService这个类用@Service将其对象注入到了Spring容器中,那么我们在用它的时候才能用
@Autowired把他注入到我们的IndexController类中
如果BookService没有注入到容器中【会标红,报异常表示找不到该对象(依赖)】:
?
那么,JDK,Spring这些算是一种容器么,当然不算是。JDK、Spring它们本身不能仅算作是一种容器,我们只能说Spring里有Spring提供的容器,JDK里有JDK提供的容器。(Spring是一种轻量级的java开发框架,JDK是java开发工具包,它们里面都包含了很多东西)
Maven的生命周期
Maven有三套互相独立的生命周期,每一个生命周期都有着一些相应的构建环节:
①Clean Lifecycle→在进行真正的构建之前进行一些清理工作。
②Default Lifecycle→构建的核心部分,编译,测试,打包,安装,部署等。
③Site Lifecycle→生产项目报告,站点,发布站点
Clean生命周期(有三个阶段)
1)pre-clean 执行一些需要在clean之前完成的工作
2)clean 移除所有上一次构建生成的文件
3)post-clean 执行一些需要在clean之后立刻完成的工作
Site生命周期(site命令---->生成一堆html,打开即可查看当前项目的信息)
1)pre-site 执行一些需要在生成站点文档之前完成的工作
2)site 生成项目站点文档
3)post-site 执行一些需要在生成站点文档之后完成的工作,并为部署做准备
4)site-deploy 将生成的站点文档部署到特定的服务器上
Default生命周期(重点)
绝大部分的工作都发生在这个生命周期当中。
引用其他文献的图给以参考(图中内容仅作了解就好)
validate ? 生命周期最初的位置(开始执行的位置)
generate-sources process-sources
generate-resources
process-resources 复制并处理资源文件,至目标目录,准备打包。。
compile 开始编译项目的源代码。
process-classes
generate-test-sources process-test-sources
generate-test-resources
process-test-resources 复制并处理资源文件,至目标测试目录。
test-compile 编译测试源代码。
process-test-classes
test 使用合适的单元测试框架运行测试。这些测试代码不会被打包或部署
prepare-package
package 接受编译好的代码,打包成可发布的格式,如JAR。 pre-integration-test integration-test
post-integration-test verify
install 将包安装至本地仓库,以让其它项目依赖
deploy 将最终的包复制到远程的仓库,以让其它开发人员与项目共享或部署到服务器上运行
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
总结:无论是你执行哪一个阶段,Maven都会先从生命周期最初的位置开始执行。与构建环节同理。即假如,你要执行compile,它会从validate开始,一直一步一步执行,一直到compile环节执行完毕。
关于插件与目标
这方面其实是属于概念的一些称呼,目标即为调用插件功能的命令。Why?
例如,当Maven调用compile命令时,它使用的插件是maven-compiler-plugin
?
Maven的重要特性
1.依赖
1)依赖的传递性:假设有两个项目,分别为项目A和项目B,如果B引入了A到pom.xml中,那么A所引入的jar包/环境也会传递到B中。(注意:依赖传递只传递范围是compile的依赖)
前提:如果B依赖于A,则A需要调用install命令安装到本地仓库中,若不安装则无法在B中引入,因为项目A是自己创建的,Maven在本地仓库以及远程仓库都找不到A
图示:
?
2)依赖的排除:如果在项目中出现有部分jar包可能会对项目造成干扰、威胁或会引发一些依赖冲突以及其他不良影响的问题,并且你自己又改不了。遇上这种情况,则可以使用<exclusion> 关键字排除其jar包
如图所示:
我们使用排除关键字排除冲突的依赖👇
?
3)依赖的原则:
当A←B←C时,A中有mysql8.0.25的架包,B中有mysql5.5的架包,那么这两个架包就有冲突了,C到底会引入谁的mysql jar包呢,依赖的传递性以及依赖的就近原则告诉我们,当这种情况发生,C离谁离得近就引入谁的jar包,所以C会引入B中mysql5.5的架包。在这种依赖关系当中,C对B是直接依赖,对A是间接依赖。
?
除了上面这种情况,还有一种情况,就是C同时依赖于A和B,但A和B的jar包又不一样,那么,这种情况依赖遵循的原则是顺序原则,意思为<denpendency>顺序谁越前C就引入谁的,如果想C引入B的jar包,就把A的相关jar包的<denpendency>放到其他jar包的下面。
?
4)依赖的统一管理
Maven中的jar包版本可以通过<properties>标签进行统一管理,例如:
<properties>
<mysql.version>8.0.25</mysql.version>
</properties>
?
?
<dependency>
? ?<groupId>mysql</groupId>
? ?<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
这样,当jar包版本就改变时,就不用一个一个去改jar包版本。【例如spring引入各种的相关jar包,发生要修改的情况时,一个个修改会很麻烦】
5)依赖的继承
由依赖的传递性,我们知道依赖传递时,是只传递compile范围的依赖,像test范围的依赖就传递不了,为了解决这种类似的问题,依赖的继承就来了。
Maven中的依赖继承和java的继承机制相似,都是只能实现单继承,那么依赖的继承该如何实现呢?
<!--首先,我们要有一个父工程,父工程中不需要太多的代码,关键是它的pom.xml文件。父工程的打包类型既不是war也不是jar,而是pom,像这样:↓-->
<groupId>com.example</groupId>
<artifactId>Father</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packageing>pom</packageing>
?
<!--子工程对父工程的引用-->
<parent>
? ?<groupId>com.example</groupId>
<artifactId>Father</artifactId>
<version>0.0.1-SNAPSHOT</version>
? ?<!--以当前文件为基准的父工程pom.xml文件的相对路径-->
? ?<relativePath>../Father/pom.xml</relativePath>
</parent>
引入后,就可以实现对test范围依赖的统一管理了,例如:
父工程的pom.xml👇
<groupId>com.example</groupId>
<artifactId>Father</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packageing>pom</packageing>
?
<!--父工程中用<dependencyManagement>标签来实现依赖的统一管理-->
<dependencyManagement>
? ? ? ?<depenedencies>
? ? ? ? ? ?<dependency>
? ? ? ? ? ? ? ?<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>5.0</version>
? ? ? ? ? ? ? ?<scope>test</scope>
? ? ? ? ? ?</dependency>
? ? ? ?</depenedenies>
</dependencyManagement>
子工程的pom.xml👇
? ? ? ?<groupId>com.example</groupId>
? ? ? ?<artifactId>Son</artifactId>
? ? ? ?<version>0.0.1-SNAPSHOT</version>
? ? ?
<parent>
? <groupId>com.example</groupId>
<artifactId>Father</artifactId>
<version>0.0.1-SNAPSHOT</version>
? <relativePath>../Father/pom.xml</relativePath>
</parent>
<!--子工程中的junit依赖甚至不用写明版本号,因为父工程已经做了依赖的统一管理-->
<depenedencies>
? ? ? ? ? ?<dependency>
? ? ? ? ? ? ? ?<groupId>junit</groupId>
<artifactId>junit</artifactId>
? ? ? ? ? ? ? ?<scope>test</scope>
? ? ? ? ? ?</dependency>
? ? ? ?</depenedenies>
?注意:若当前的工程继承了一个父工程,那么在当前工程调用install命令时,必须先安装父工程
2.聚合
使用<modules> 标签实现聚合功能,聚合的功能是把几个模块聚在一起,一键全部生成
首先,聚合功能与继承无关,而且能自动识别依赖传递顺序(即使图中Hello顺序打乱也无所谓,输出时,仍然会显示正确的依赖传递顺序)
在<modules> 标签中放好项目名称后,在总聚合的项目中调用Maven的install命令即可把<modules> 标签中的所有项目全都安装。
?
|