一、 Maven介绍
1.构建
构建过程包含的主要的环节:
- 清理:删除上一次构建的结果,为下一次构建做好准备
- 编译:Java 源程序编译成 *.class 字节码文件
- 测试:运行提前准备好的测试程序
- 报告:针对刚才测试的结果生成一个全面的信息
- 打包: Java工程:jar包 ;Web工程:war包
- 安装:把一个 Maven 工程经过打包操作生成的 jar 包或 war 包存入 Maven 仓库
- 部署:
(1)部署 jar 包:把一个 jar 包部署到 Nexus 私服服务器上
(2)部署 war 包:借助相关 Maven 插件(例如 cargo),将 war 包部署到 Tomcat 服务器
2.依赖管理中要解决的具体问题:
jar 包的下载:使用 Maven 之后,jar 包会从规范的远程仓库下载到本地
jar 包之间的依赖:通过依赖的传递性自动完成
jar 包之间的冲突:通过对依赖的配置进行调整,让某些jar包不会被导入
二、Maven安装配置
下载解压后:maven
修改Maven 的核心配置文件:conf/settings.xml
1.指定本地仓库
<!-- localRepository
| The path to the local repository maven will use to store artifacts.
|
| Default: ${user.home}/.m2/repository
<localRepository>/path/to/local/repo</localRepository>
-->
<localRepository>F:\software\maven-repo</localRepository>
一定要把 localRepository 标签从注释中拿出来。本地仓库本身也需要使用一个非中文、没有空格的目录。
2.配置阿里云提供的镜像仓库
让 Maven 下载 jar 包的时候速度更快。
(1)注释原有的例子
<!-- <mirror>
<id>maven-default-http-blocker</id>
<mirrorOf>external:http:*</mirrorOf>
<name>Pseudo repository to mirror external repositories initially using
HTTP.</name>
<url>http://0.0.0.0/</url>
<blocked>true</blocked>
</mirror> -->
(2)加入我们的配置
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
3.配置 Maven 工程的基础 JDK 版本
如果按照默认配置运行,Java 工程使用的默认 JDK 版本是 1.5,而我们熟悉和常用的是 JDK 1.8 版本。
修改配置的方式是:将 profile 标签整个复制到 settings.xml 文件的 profiles 标签内。
<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
4、配置环境变量
(1)MAVEN_HOME
(2)PATH
加入%MAVEN_HOME%\bin
(3)验证
mvn -v
Apache Maven 3.8.4 (9b656c72d54e5bacbed989b64718c159fe39b537)
Maven home: F:\software\apache-maven-3.8.4
Java version: 1.8.0_271, vendor: Oracle Corporation, runtime: C:\Program Files (x86)\Java\jdk1.8.0_271\jre
Default locale: zh_CN, platform encoding: GBK
OS name: "windows 10", version: "10.0", arch: "x86", family: "windows"
三、命令行环境使用Maven
Maven核心概念:坐标
**1.Maven中的坐标:**使用三个『向量』在『Maven的仓库』中唯一的定位到一个『jar』包。
- groupId:公司或组织的 id
- artifactId:一个项目或者是项目中的一个模块的 id(例如:com.atguigu.maven)
- version:版本号
- 举例:
groupId:com.atguigu.maven
artifactId:pro01-atguigu-maven
version:1.0-SNAPSHOT
Maven创建
1.使用命令生成maven工程
在工作目录下进入cmd,输入命令mvn archetype:generate
(1)默认选7,回车即可
(2)输入名称,创建成功
(3)修改pom.xml,junit 依赖的是较低的 3.8.1 版本,我们可以改成较适合的 4.12 版本
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.1.2</version>
<scope>test</scope>
</dependency>
自动生成的 App.java 和 AppTest.java 可以删除。
2.解读pom.xml
<!-- 根标签:project,表示对当前工程进行配置、管理 -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 当前Maven工程的坐标 -->
<groupId>com.ayu.maven</groupId>
<artifactId>pro01-maven-java</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- packaging标签指定当前Maven工程的打包方式,可选值有下面三种: -->
<!-- jar:表示这个工程是一个Java工程 -->
<!-- war:表示这个工程是一个Web工程 -->
<!-- pom:表示这个工程是“管理其他工程”的工程 -->
<packaging>jar</packaging>
<name>pro01-maven-java</name>
<url>http://maven.apache.org</url>
<!-- 在Maven中定义属性值 -->
<properties>
<!-- 工程构建过程中读取源码时使用的字符集 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- 当前工程所依赖的jar包 -->
<dependencies>
<!-- 使用dependency配置一个具体的依赖 -->
<dependency>
<!-- 在dependency标签内使用具体的坐标依赖我们需要的一个jar包 -->
<!-- 坐标信息:导入哪个jar包,就配置它的坐标信息即可 -->
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<!-- scope标签配置依赖的范围 -->
<scope>test</scope>
</dependency>
</dependencies>
Maven核心概念:POM
POM:Project Object Model,项目对象模型POM 表示将工程抽象为一个模型,再用程序中的对象来描述这个模型。这样我们就可以用程序来管理项目了。
一、Maven核心概念:约定的目录结构
(1)各个目录的作用
Maven 对于目录结构这个问题,没有采用配置的方式,而是基于约定(可以认为是默认配置,不做特定的修改就不需要去配置,进行配置则覆盖了约定)。
二、执行Maven构建命令
注:运行 Maven 中和构建操作相关的命令时,必须进入到 pom.xml 所在的目录。如果没有在 pom.xml 所在的目录运行 Maven 的构建命令,那么会看到下面的错误信息:
The goal you specified requires a project to execute but there is no POM in
this directory
mvn -v 命令和构建操作无关,只要正确配置了 PATH,在任何目录下执行都可以。而构建相关的
命令要在 pom.xml 所在目录下运行——操作哪个工程,就进入这个工程的 pom.xml 目录。
2、清理操作
mvn clean
效果:删除 target 目录
3、编译操作
主程序编译:mvn compile
测试程序编译:mvn test-compile
主体程序编译结果存放的目录:target/classes
测试程序编译结果存放的目录:target/test-classes
4、测试操作
mvn test
测试的报告存放的目录:target/surefire-reports
5、打包操作
mvn package
打包的结果——jar 包,存放的目录:target
6、安装操作
mvn install
mvn clean install
安装的效果是将本地构建过程中生成的 jar 包存入 Maven 本地仓库。这个 jar 包在 Maven 仓库中的路径是根据它的坐标生成的。
坐标信息如下:
<groupId>com.ayu.maven</groupId>
<artifactId>pro01-maven-java</artifactId>
<version>1.0-SNAPSHOT</version>
在Maven仓库中生成的路径如下:
F:\software\maven-repo\com\ayu\maven\pro01-maven-java\1.0-SNAPSHOT\pro01-maven-java-1.0-SNAPSHOT.jar
另外,安装操作还会将 pom.xml 文件转换为 XXX.pom 文件一起存入本地仓库。所以我们在 Maven 的本地仓库中想看一个 jar 包原始的 pom.xml 文件时,查看对应 XXX.pom 文件即可,它们是名字发生了改变,本质上是同一个文件。
三、创建Maven版的Web工程
1.运行生成工程的命令:
mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -
DarchetypeArtifactId=maven-archetype-webapp -DarchetypeVersion=1.4
参数 archetypeGroupId、archetypeArtifactId、archetypeVersion 用来指定现在使用的 maven-archetype-webapp 的坐标
2.配置对 servlet-api.jar 包的依赖(自己写好web程序)
为了正常使用HttpServlet,需要配置对servlet-api的依赖
mvn repository
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
3.使用mvn clean compile编译,mvn package进行打包,生成war包
4.将war包部署到Tomcat运行
四、让Web工程依赖Java工程
本质上来说,Web 工程依赖的 Java 工程其实就是 Web 工程里导入的 jar 包。最终 Java 工程会成 jar 包,放在Web 工程的 WEB-INF/lib 目录下。
<dependency>
<!--通过指定被依赖工程的坐标完成依赖-->
<groupId>com.ayu.maven</groupId>
<artifactId>pro01-maven-java</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
五、依赖的范围
标签的位置:dependencies/dependency/scope
标签的可选值:compile/test/provided/system/runtime/import
①compile 和 test 对比
主体业务需求需要用到依赖的基本都是compile
②compile 和 provided 对比
provided: Tomcat已经提供的,打war包的时候不会包含在war包里面(否则容易与服务器端其他jar包发生冲突)
③结论
compile:通常使用的第三方框架的 jar 包这样在项目实际运行时真正要用到的 jar 包都是以 compile 范围进行依赖的。比如 SSM 框架所需jar包。
test:测试过程中使用的 jar 包,以 test 范围依赖进来。比如 junit。
provided:在开发过程中需要用到的“服务器上的 jar 包”通常以 provided 范围依赖进来。比如 servlet-api、jsp-api。而这个范围的 jar 包之所以不参与部署、不放进 war 包,就是避免和服务器上已有的同类jar 包产生冲突,同时减轻服务器的负担。说白了就是:“服务器上已经有了,你就别带啦!
范围遵从mvn repository即可
六、依赖传递性
①概念
A 依赖 B,B 依赖 C,那么在 A 没有配置对 C 的依赖的情况下,A 里面能不能直接使用 C?
②传递的原则
在 A 依赖 B,B 依赖 C 的前提下,C 是否能够传递到 A,取决于 B 依赖 C 时使用的依赖范围。
B 依赖 C 时使用 compile 范围:可以传递
B 依赖 C 时使用 test 或 provided 范围:不能传递,所以需要这样的 jar 包时,就必须在需要的地
方明确配置依赖才可以。
七、依赖的排除
当 A 依赖 B,B 依赖 C 而且 C 可以传递到 A 的时候,A 不想要 C,需要在 A 里面把 C 排除掉。而往往这
种情况都是为了避免 jar 包之间的冲突。
所以配置依赖的排除其实就是阻止某些 jar 包的传递。因为这样的 jar 包传递过来会和其他 jar 包冲突。
<dependency>
<groupId>com.atguigu.maven</groupId>
<artifactId>pro01-maven-java</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
<!-- 使用excludes标签配置依赖的排除 -->
<exclusions>
<!-- 在exclude标签中配置一个具体的排除 -->
<exclusion>
<!-- 指定要排除的依赖的坐标(不需要写version) -->
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
八、继承
本质上是 A 工程的 pom.xml 中的配置继承了 B 工程中 pom.xml 的配置。
作用:在父工程中统一管理项目中的依赖信息,具体来说是管理依赖信息的版本。
(1)创建父工程
只有打包方式为 pom 的 Maven 工程能够管理其他 Maven 工程。打包方式为 pom 的 Maven 工程中不
写业务代码,它是专门管理其他 Maven 工程的工程。
<groupId>com.atguigu.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 当前工程作为父工程,它要去管理子工程,所以打包方式必须是 pom -->
<packaging>pom</packaging>
(2)创建模块子工程
进入 pro03-maven-parent 工程的根目录,然后运行mvn archetype:generate 命令来创建模块工程。
将会在父工程的pom.xml添加如下内容:
<!--聚合的配置 -->
<modules>
<module>pro04-maven-module</module>
<module>pro05-maven-module</module>
<module>pro06-maven-module</module>
</modules>
子工程的pom.xml如下:
<!-- 使用parent标签指定当前工程的父工程 -->
<parent>
<!-- 父工程的坐标 -->
<groupId>com.atguigu.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<!-- 子工程的坐标 -->
<!-- 如果子工程坐标中的groupId和version与父工程一致,那么可以省略 -->
<!-- <groupId>com.atguigu.maven</groupId> -->
<artifactId>pro04-maven-module</artifactId>
<!-- <version>1.0-SNAPSHOT</version> -->
(3)在父工程中配置依赖的统一管理
<!-- 使用dependencyManagement标签配置对依赖的管理 -->
<!-- 被管理的依赖并没有真正被引入到工程 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
(4)子工程中引用那些被父工程管理的依赖
即使在父工程配置了对依赖的管理,子工程需要使用哪一个依赖还是要明确配置。对于已经在父工程进行了管理的依赖,子工程引用时可以不写version。
关键点:省略版本号。
<!-- 子工程引用父工程中的依赖信息时,可以把版本号去掉。 -->
<!-- 把版本号去掉就表示子工程中这个依赖的版本由父工程决定。 -->
<!-- 具体来说是由父工程的dependencyManagement来决定。 -->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
</dependencies>
如果配置了version标签且和父工程不一样,那么这里子工程配置的版本会覆盖父工程管理的版本并最终采纳。
(5)在父工程中声明自定义属性
<!-- 通过自定义属性,统一指定Spring的版本 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 自定义标签,维护Spring版本数据 -->
<!--通过引用属性表达式设定版本号,这样版本号就成了一个动态值。 -->
<!--通过属性名解析后才知道具体是什么值-->
<atguigu.spring.version>4.3.6.RELEASE</atguigu.spring.version>
</properties>
在需要的地方使用${}的形式来引用自定义的属性名:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${atguigu.spring.version}</version>
</dependency>
九、聚合
使用一个“总工程”将各个“模块工程”汇集起来,作为一个整体对应完整的项目。
- 项目:整体
- 模块:部分
一键执行 Maven 命令:很多构建命令都可以在“总工程”中一键执行。以 mvn install 命令为例:Maven 要求有父工程时先安装父工程;有依赖的工程时,先安装被依赖的工程。我们自己考虑这些规则会很麻烦。但是工程聚合之后,在总工程执行 mvn install 可以一键完成安装,而且会自动按照正确的顺序执行。
在总工程中配置 modules 即可:
<!--聚合的配置 -->
<modules>
<module>pro04-maven-module</module>
<module>pro05-maven-module</module>
<module>pro06-maven-module</module>
</modules>
四、IDEA环境使用Maven
1.创建一个maven项目
2.修改为自己的maven
3.修改本地仓库地址和setting地址
4、创建module
右击项目,选择new module,过程与上述相同。
如果有需要,可以在此处运行maven命令
<!-- -D表示后面要附加命令的参数,字母D和后面的参数是紧挨着的,中间没有任何其它字符 -->
<!-- 在执行命令的过程中跳过测试 -->
mvn clean install -Dmaven.test.skip=true
5、创建web module
(1)按照前面的同样操作创建模块,此时这个模块其实还是一个Java模块。
(2)Web 模块将来打包当然应该是 war 包。
<packaging>war</packaging>
(3)如果没有自动生成 Web 设定,自己创建
(4)设置 Web 资源的根目录。结合 Maven 的目录结构,Web 资源的根目录需要设置为 src/main/webapp 目录
五、其他核心概念
1、Maven生命周期
为了让构建过程自动化完成,Maven 设定了三个生命周期,生命周期中的每一个环节对应构建过程中的
一个操作。
- 前面三个生命周期彼此是独立的。
- 在任何一个生命周期内部,执行任何一个具体环节的操作,都是从本周期最初的位置开始执行,直
到指定的地方。
2、插件和目标
目标:插件的功能
(1)插件:Maven 的核心程序仅仅负责宏观调度,不做具体工作。具体工作都是由 Maven 插件完成的。例如:编
译就是由 maven-compiler-plugin-3.1.jar 插件来执行的。
**(2)目标:**一个插件可以对应多个目标,而每一个目标都和生命周期中的某一个环节对应。
Default 生命周期中有 compile 和 test-compile 两个和编译相关的环节,这两个环节对应 compile 和test-compile 两个目标,而这两个目标都是由 maven-compiler-plugin-3.1.jar 插件来执行的。
3、仓库
本地仓库:在当前电脑上,为电脑上所有 Maven 工程服务
远程仓库:需要联网
- 局域网:我们自己搭建的 Maven 私服,例如使用 Nexus 技术。
- Internet
中央仓库
镜像仓库:内容和中央仓库保持一致,但是能够分担中央仓库的负载,同时让用户能够就近访问提高下载速度,例如:Nexus aliyun
建议:不要中央仓库和阿里云镜像混用,否则 jar 包来源不纯,彼此冲突。
专门搜索 Maven 依赖信息的网站:https://mvnrepository.com