一、了解Maven
1.简介
Maven是是 Java 生态里最主流的项目构建 + 依赖管理工具,他可以定义项目结构、项目依赖,并使用统一的方式进行自动化构建,是java项目不可缺的工具
2.为什么要学习Maven
- 提供了一套标准化的项目结构;
其规范了项目结构,方便开发人员开发
- 提供了一套标准化的构建流程;
一个 Java 项目从代码到可运行程序,要经过「编译 → 测试 → 打包 → 部署」等很多步骤。 Maven 把这些步骤做成了标准的生命周期,我们只需要配置远程部署地址
- 提供了一套依赖管理机制(管理项目的所有jar包)
maven利用本地仓库统一管理所有jar包,传输文件时只需要传输调用代码,同时解决了版本冲突问题
二、实践
1.配置环境
虽然不配置maven环境也可以使用ide内置的maven,但是无法通过cmd识别命令,所以最好还是配置一下
首先到官网Download Apache Maven – Maven下载最新压缩包
解压后
打开C:\Users\Nebula\Desktop\apache-maven-3.9.16-bin\apache-maven-3.9.16\conf中的setting文件,在里面修改自己的依赖存储地址
然后向下找到镜像源(mirror),修改为国内镜像源(刚开始本地仓库并不是存有所有jar包,当jar包不存在时会从maven官方去拉取,由于maven官方地址在国外,所以拉取速度会很慢,这里我们改为国内镜像源就会好很多)
我添加的是阿里云和华为云的,当一方找不到时会向下继续查找
<mirror> <id>aliyunmaven</id> <mirrorOf>central</mirrorOf> <name>阿里云公共仓库</name> <url>https://maven.aliyun.com/repository/public</url> </mirror> <mirror> <id>huaweicloud</id> <mirrorOf>central</mirrorOf> <name>华为云公共镜像仓库</name> <url>https://repo.huaweicloud.com/repository/maven/</url> </mirror>接下来配置环境变量
首先在系统环境变量中添加下图所示变量,路径为上面下载压缩包解压后的地址
然后在path变量内部添加当前文件中的bin文件
最后打开cmd输入下面代码验证
mvn -v如果显示版本号代表配置成功
(IDE中的配置过程略,太简单了在设置里自己找就好)
三、创建Maven型项目
1.使用命令行
在文件夹中打开cdm,执行下列语句
mvn archetype:generate2.使用IDE
(1)架构解析(约定)
在这个项目中,maven就类似一个脚手架,帮你写好了基础架构
- pom文件是这个项目中最重要的文件之一,没有他这个项目就不是一个maven项目,它是一个配置文件
- main文件夹中存放的是项目主体文件。其中的Java包存放的是用java语言编写的主程序,内部的org...0806是通过groupid生成的(用cmd创建时会有一步让你自定义);而resources存放的是除了Java以外项目内所有需要用到的文件(如xml,properties,yml这样的配置文件、.html,.css,.js,.image这样的静态资源文件(不需要Java编译)或者jsp等模板页)
- test文件夹中则是用于单元测试的文件(Junit),最后打包的时候不会保存(里面也可以创建resources)
- target文件夹存放的是编译后的文件,运行主函数后会自动编译
只有按照其指定的方式存放相应类型的文件,才能够自动化构建,这也就是所谓的约定大于配置
我们学习maven主要学习的就是pom.xml的编写(划重点)
(2)pom文件解析
首先,这一行代码可以无视,他的意思大概为maven版本相关的内容
<modelVersion>4.0.0</modelVersion>重点关注的是后面groupId,artifactId和version这三条语句,他们共同组成的是坐标信息(本项目工程的坐标信息,别的项目引用需要通过他们),是每个项目唯一的
<groupId>org.example</groupId><!-- 域名反过来 --> <artifactId>Project060806</artifactId><!-- 项目名 --> <version>0.0.1-SNAPSHOT</version><!-- 意义是注释为还没上线的快照版 --> <name>Project060806</name> <description>Project060806</description> <url/><!-- 官方地址标注,可有可无相当于注释 -->那么我们如何通过坐标信息去引用别的jar包呢?
这里边需要使用到<dependencies>(依赖) 语句,称为添加依赖(一个依赖可以包含多个jar包),当需要坐标信息时,可以去中央仓库:https://mvnrepository.com/寻找
注意,依赖内部有一个语句叫做<scope>,限定的是依赖的范围,如果规定了范围,那么只有在对应的类里面可以创建对象调用该依赖里面的一些方法
<--依赖范围 有哪些范围: 编译(main/java): 测试(main/test): 运行/打包(包内): provided 编译√ 测试√ 打包× sevlet test 编译× 测试√ 打包× junit compile 编译√ 测试√ 打包√ 默认 runtime 编译× 测试√ 打包√ 反射(数据库驱动jar包——>class.forName()) system =provided 不会依赖仓库中的jar包,二十引用本地物理路径的jar包<systemPath></systemPath>(一般不使用system) 注意:依赖范围只是一个建议,即使所有的都默认也不会影响功能的正常运行,而且一般从中央仓库获取的代码自带scope,自动补全也可以使用,但事实上90%都是默认即可 -->接着我们来编写属性变量,这里的语句是<properties>
通常,内部设置的是依赖的版本,方便统一管理修改,以servlet为例,用法如下
<properties> <java.version>17</java.version> <javax.sevlet.version>3.1.0</javax.sevlet.version> </properties> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${javax.sevlet.version}</version> <scope>provided</scope> </dependency>除此之外,还有一个语句叫做<packaging>,作用为设置打包方式,不写的话默认为jar包
由于jar 包本身不带 Servlet 容器,你想让普通maven项目能跑起来,需要自己手动做 Spring Boot 帮你做好的所有事,所以一般改为war包输出
更改以后需要去文件-项目结构中更改对应文件根指向文件夹
注意由于war包运行需要借助外部工具Tomcat,所以需要配置Tomcat
首先先去Tomcat官网去下载Apache Tomcat®——欢迎!
Java17推荐使用Tomcat 10.1.x版本,下载完毕后去设置内添加服务器
设置完成后需要运行时便可以在编辑配置选项中添加Tomcat运行
接着在部署选项内添加需要运行的程序即可
这样便可以运行一个war包程序了
补充知识1——依赖传递(传递性)
我们假设B内置了mysql依赖,而A需要同时调用B和mysql,此时是否需要重新导入B和mysql的jar包呢?答案是不需要,但具体情况仍需讨论(注意:war包不可以被别的包引用)
如果B中的mysql依赖作用范围不包含jar包(install),那么这里就不会导入B的mysql
或者dependency中还有一个内置标签<optional>,默认是false代表会传递,改成true则不会传递
<optional>false</optional>补充知识2——依赖排除
上面两种阻止依赖传递的方法仅限于我们拥有修改B的权限时可以使用,当B不归我们管时,我们又该怎么办呢?有没有什么办法可以手动排除呢?
有的,这里需要用到dependency中的另一个标签<exclusion>,在这个标签内部可以填写需要排除的依赖的groupId和artifactId(由于仅存在一个版本,所以不需要填写版本号)
<exclusion> <groupId>xxxxx</groupId> <artifactId>xxxxxx</artifactId> </exclusion>或者我们也可以单独添加一个全新的MySQL依赖(不同于之前B版本的)即可,会顶替掉原来的依赖(虽然传过来了但不会用,上面的方法压根就没传过来)
即:当我们在自己的工程内添加一个系统的依赖时,不同的版本会以我们自己的工程依赖优先(跟前后引入顺序无关)
(4)聚合工程
很多时候,我们一个实际工程需要由多个模块(小项目)聚合而成,如果每个项目都是分离开的话一个一个窗口去切换修改的时候未免有些太繁琐麻烦,那么我们有没有什么办法能够把不同的多个有一定联系的项目聚合到一个窗口内呢?
当然有方法,虽然官方没有对应的功能模块,但是我们可以自己手动操作一下
首先创建一个全新的项目,然后按照下列步骤执行
- 删除src文件夹:聚合项目本身只用于管理项目(子工程),并不需要运行什么代码
- 修改install配置:将pom中的packaging输出格式修改为pom,表示当前不是一个具体的包
- 创建模块:在项目大包右键创建模块(parent设置为none)
- 配置模块:在聚合项目pom文件中添加<modules>标签用来管理模块
<modules> <module>模块名</module> <module>模块名</module> </modules>注意:这里当我们再在任一模块中添加依赖后,不需要再安装到本地仓库,同聚合项目内的其他依赖了本模块的项目便可自动感知到配置中新添加的依赖(说明此时处于同一根目录下可以直接读取对应配置而不是获取jar包后读取)
当我们执行聚合项目的生命周期时所有子模块会同时执行对应maven操作
(5)Maven的继承
还是以上面MySQL依赖需求为例,假设这里我们公司要求A和B统一MySQL版本,有没有什么办法可以让A和B(同一聚合项目中的两个模块)获取到公司统一的MySQL依赖呢?
有的,只需要在聚合项目的配置文件pom中添加要求版本的依赖,然后再在需要用到的子模块配置文件pom中添加标签<parent>,把聚合项目的版本号填进去即可
但是这样做的话会有一个问题,就是所有子工程都会加载这个依赖,有的子工程可能压根用不到这个依赖,怎么解决这个问题呢?
我们可以使用<dependencyManagement>标签,在总项目配置文件中添加这个标签后在其内部引入非必须的依赖,然后子工程在导入依赖时虽然还需要写groupId和artifactId,但是无需写版本号,相当于统一了版本号
<dependencyManagement> <dependencies> <dependency> <-- 这里填写对应依赖 --> </dependency> </dependencies> </dependencyManagement>(其实添加parent这一步在创建项目时可以选择自动创建,但这里为了演示原理上面创建的时候勾选的是none)
至此,基本的用法便讲完了,后面有一些补充会更新在这里