文章目录
一、什么是Maven
1、构建
构建过程包含的主要的环节:
- 清理:删除上一次构建的结果,为下一次构建做好准备
- 编译:Java源程序编译成*.class字节码文件
- 测试:允许提前准备好的测试程序
- 报告:针对刚才测试的结果生成一个全面的信息
- 打包
- Java工程:jar包
- Web工程:War包
- 安装:把一个Maven工程经过打包操作生成的jar包或war包存入Maven仓库
- 部署
- 部署jar包:把一个jar包部署大Nexus私服服务器上
- 部署war包:借助相关Maven插件(例如cargo),将war包部署到Tomcat服务器上
2、依赖
在A工程中里面用到了B工程的类、接口、配置文件等等这样的资源,那么就可以说A依赖B。
依赖管理中需要解决的问题:
- jar包的下载:使用Maven之后,jar包会从规范的远程仓库下载到本地
- jar包之间的依赖:通过依赖的传递性自动完成
- jar包之间的冲突:通过对依赖的配置进行调整,让某些jar包不会被导入
3、Maven的工作机制
二、Maven核心程序解压与配置
1、下载核心程序
- 下载连接:https://maven.apache.org/download.cgi
选择下载 第二个-bin.zip文件
2、解压Maven核心程序
将核心程序压缩包,解压到非中文,没有空格的目录下:
在解压目录中,我们需要着重关注Maven的核心配置文件:conf/setting.xml
3、指定本地仓库
本地仓库默认值:家目录/.m2/repository。由于本仓库的默认位置是在用户的家目录,一般来说也就是系统盘下。当Maven仓库中jar包越来越多,仓库体积越来越大,可能会托盘C盘的允许速度,影响系统性能。所以我们进行对仓库进行自行配置:
本地仓库这个目录只需要手动新建一个空的目录即可。
注意:
- 一定要把 localRepository 标签从注释中拿出来。
- 本地仓库也是需要使用一个非中文、没有空格的目录。
4、配置阿里云提供的镜像仓库
Maven下载jar包,默认是在境外的中央仓库,因为外站速度慢,所以这边建议改成阿里云提供的镜像仓库,访问国内网站,可以让Maven瞎子jar包的速度更快。配置方式:
- 将原有的例子配置注释掉
- 将下面mirror标签只能个体复制到settings.xml文件的mirrors标签的内部。
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
5、配置Maven工程的基础JDK版本
如果按照默认配置允许,Java工程使用的默认版本是1.5,而我们一般都是使用1.8版本。将下面的 profile 标签整个复制到 setting.xml 文件的 profiles 标签内
<profile>
<id>jdk1.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>
可以放在结束标签的上面,这样就可以确保在profiles标签内
6、配置环节变量
- 保证JDK的环境没有问题
- 配置MAVEN_HOME环境变量
三、使用Maven:命令行环境
1、根据坐标创建Maven工程
①Maven核心概念:坐标
向量的说明
- 使用三个向量在Maven的仓库中唯一的定位到一个jar包
- groupld:公司或组织的id
- artifactld:一个项目或者是项目中的一个模块的id
- version:版本号
三个向量的取值方式
- groupId:公司或组织域名的倒序,通常也会加上项目名称
- 例如com.jianbing.maven
- artifactId:模块的名称,将来作为Maven工程的工程名
- version:模块的版本号,根据自己的需要设定
- 例如:SNAPSHOT表示快照版本,郑在迭代过程中,不稳定的版本
- 例如:RELEASE表示正式版本
举例:
- groupId:com.jianbing.maven
- artifactId:pro01-atjianbing-maven
- version:1.0-SNAPSHOT
②坐标和仓库中jar包的存储路径之间的对应关系
坐标:
<groupId>java.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>1.0</version>
上面坐标对应的jar包在maven本地仓库的位置:
Maven本地苍鹭根目录\javax\servlet\servlet-api\1.0\servlet-api-1.0.jar
2、实验操作
①创建目录作为后面操作的工作空间
- 例如:D:\Maven-workspace
做个比喻:
- Maven核心程序:中军大帐
- Maven本地仓库:兵营
- 本地工作空间:战场
②在工作空间目录下打开命令行窗口
③使用命令生成Maven工程
运行mvn archetype:generate
④调整
maven默认生成的工程,对junit依赖是较低的3.8.1版本,我们可以改成4.12版本。自动生成的App.java和AppTest.java可以删除。
<!--依赖信息配置-->
<!-- dependencies复数标签:里面包含dependency单数标签 -->
<dependencies>
<!--dependency单数标签:配置一个具体的依赖 -->
<dependency>
<!-- 通过坐标来依赖其他jar包 -->
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<!-- 依赖的范围 -->
<scope>test</scope>
</dependency>
</dependencies>
⑤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 标签:从Maven2开始就固定是4.0.0。 -->
<!-- 代表当前pom.xml 所采用的标签结构。 -->
<modelVersion>4.0.0</modelVersion>
<!-- 坐标信息 -->
<!-- groupId 标签:坐标向量之一;代表公司或组织开发的摸一个项目 -->
<groupId>com.atjianbing.maven</groupId>
<!-- artifactId 标签:坐标向量之一;代表项目下的某一个模板 -->
<artifactId>pro01-maven-java</artifactId>
<!-- version 标签:坐标向量之一;代表当前模板的版本 -->
<version>1.0-SNAPSHOT</version>
<!-- packaging 标签:打包方式 -->
<!-- 取值 jar:生成jar包,说明这是一个Java工程 -->
<!-- 取值 war:生成war包,说明这是一个Web工程 -->
<!-- 取值 pom:说明这个工程是用来管理其他工程的工程 -->
<packaging>jar</packaging>
<name>pro01-maven-java</name>
<url>http://maven.apache.org</url>
<!-- properties 标签:在 Maven 中定义属性值 -->
<properties>
<!-- 在构建过程中读取源码时使用的字符集 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- dependencies 标签:配置具体依赖信息,可以包含多个 dependency 子标签 -->
<dependencies>
<!-- dependency 标签:配置一个具体的依赖信息 -->
<dependency>
<!-- 坐标信息:导入哪个 jar 包,就配置它的坐标信息即可 -->
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<!-- scope 标签: 配置当前依赖的范围 -->
<scope>test</scope>
</dependency>
</dependencies>
</project>
3、Maven核心概念:POM
①含义
POM:Project Object Model,项目对象模型。和POM类似的是:DOM(Document Object Model),文档对象模型。它们都是模型化思想的具体体现。
②模型化思想
POM表示将工程抽象为一个模型,再用程序中的对象来描述这个模型。这样我们就可以用程序来管理项目。我们再开发过程中,最基本的做法就是将现实生活中的事物抽象为模型,然后封装模型相关的数据作为一个对象,这样就可以在程序中计算与现实事物相关的数据。
③对应的配置文件
POM理念集中体现再 Maven 工程根目录下 pom.xml 这个配置文件中。所以这个 pom.xml 配置文件就是 Maven 工程的核心配置文件。
4、Maven核心概念:约定的目录结构
①各个目录的作用
target目录专门存放构建操作输出的结果。
②约定目录结构的意义
Maven为了让构建过程能够尽可能自动化完成,所以必须约定目录结构的作用。例如:Maven 执行编译操作,必须先去Java源程序目录读取Java源代码,然后执行编译,最后把编译结果存放在target目录。
③约定大于配置
Maven对于目录结构这个问题,没有采用配置的方式,而是基于约定。这样会让我们在开发过程中非常方便。如果每次创建Maven工程后,还需要针对各个目录的位置进行详细的配置,那肯定非常麻烦。
目前开发领域的技术发展趋势就是:约定大于配置,配置大于编码。
四、在Maven工程中编写代码
1、主体程序
主题程序指的是被测试的程序,同时也是将来再项目中真正要使用的程序。
package com.atjianbing.maven
public class Calculator{
public int sum(int i, int j){
return i + j;
}
}
2、测试程序
默认情况下,Maven创建的整个项目工程的结构如下:
package com.atjianbing.maven;
import org.junit.Test;
import com.atjianbing.maven.Calculator;
//静态导入的效果是将Assert类中的静态资源导入当前类
//这样依赖,在当前类中就可以直接使用Assert类中的静态资源,不需要写类名
import static org.junit.Assert.*;
public class CalculatorTest{
@Test
public void testSum(){
//创建Calculator对象
Calculator calculator = new Calculator();
//调用Calculator对象的方法,获取到程序运行实际的结果
int actualResult = calculator.sum(5,3);
//声明一个变量,表示程序运行期待的结果
int expectedResult = 8;
//使用断言来判断实际结果和期待结果是否一致
//如果一致:测试通过,不会抛出异常
//如果不一致:抛出异常,测试失败
assertEquals(expectedResult,actualResult);
//加个输出进行判定
System.out.println("Test method have been called ");
}
}
五、执行Maven 的构建命令
1、要求
运行Maven中和构建操作相关的命令时,必须进入到 pom.xml 所在的目录。如果没有在 pom.xml 所在的目录运行Maven的构建命令,将会看到报错信息“
The goal you specified requires a project to execute but there is no PoM in thisdirectory
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
安装的效果是将本地构建过程中生成的 jar 包存入 Maven 本地仓库,这个 jar 包在 Maven 仓库中的路径是根据他的坐标生成的。
安装操作还会将 pom.xml 文件转换为 xx.pom 文件一起存入本地仓库。所以我们在Maven的本地仓库中想看一个 jar 包院书的 pom.xml 文件时,查看对应 xx.pom 文件即可,他们只是名字上发生了改变,本质上是同一个文件。
六、创建Maven版的Web工程
1、说明
使用下面命令创建web工程:
mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DarchetypeVersion=1.4
参数:archetypeGroupId、archetypeArtifactId、DarchetypeVersion用来指定现在使用的 maven-archetype-webapp 的坐标。
2、生成的pom.xml
确认打包方式是war形式
<packaging>war</packaging>
3、生成的web工程的目录结构
webapp 目录下有 index.jsp
web-inf 目录下有 web.xml
4、创建Servlet
①在 main 目录下创建java目录
②在 java目录下创建 Servlet 类所在的包的目录
③在包下建Servlet类
package com.atjianbing.maven;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.ServletException;
import java.io.IOException;
public class HelloServlet extends HttpServlet{
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException,IOException{
response.getWriter().writer("Hello maven web");
}
}
④在 web.xml 中注册 Servlet
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.atjianbing.maven.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<servlet-class>/helloServlet</servlet-class>
</servlet-mapping>
5、在 index.jsp 页面编写超链接
<html>
<body>
<h2>Hello World!</h2>
<a href="helloServlet"><Access Servlet></a>
</body>
</html>
6、配置对servlet-api.jar包的依赖
可进入网站https://mvnrepository.com/进行查询,使用关键字搜索,在搜索结果中选择适合的使用
将依赖内容复制到 pom.xml 文件中的依赖环境中
7、进行编译
执行 mvn compile命令
8、将 web 工程打包为 war 包
执行 mvn oackage 命令,生成 war 包的位置如下所示:
9、将 war 包部署到tomcat下进行运行
先到tomcat目录下启动tomcat
将我们打包好的 war 包放到 tomcat 的工作环境下:
打开浏览器,访问http://localhost:8082/demo/index.jsp(因为我的配置是8082端口的,一般是8080端口)
七、让 Web 工程依赖 Java 工程
1、观念
明确一个概念:从来只有 Web 工程依赖 Java 工程,没有反过来 Java 工程依赖 Web 工程。本质上来说,Web 工程依赖的 Java 工程其实就是 Web 工程里导入的 jar 包。最终 Java 工程会变成 jar 包,放在Web 工程的 WEB-INF/lib目录下。
2、操作
在 web 工程的 pom.xml 中,找到 dependencies 标签,在该标签中添加如下配置:
<!-- 配置对 Java 工程的依赖 -->
<dependency>
<!-- 通过指定北依赖工程的坐标完成依赖 -->
<groupId>com.atjianbing.maven</groupId>
<artifactId>pro01-maven-java</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
3、在 Web 工程中,编写测试代码
①补充创建目录
②确认 Web 工程依赖了 junit
原来在 pom.xml 里就有该依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
③创建测试类
直接将我们之前创建的 Java 类中的测试类复制到该目录下:
④执行Maven命令
测试命令
mvn test
说明:测试操作中会提前自动执行编译操作,测试成功就说明编译也是成功的。
可以看到成功编译,输出了测试方法的内容。
打包整个web工程
mvn package
来到target目录下
通过查看war包内的结构,我们看到被 Web 工程依赖的 Java 工程确实是会变成 Web工程的 WEB-INF/lib 目录下的jar包。
查看依赖
mvn depency:list
发现有个不属于我们所导入的依赖,但是它确实是由这个依赖;
mvn depency:tree
发现它是我们所依赖的 junit 所依赖的 jar 包。基于依赖的传递性,hamcrest-core被传递到我们的工程了。
八、测试依赖的范围
1、依赖范围
标签的位置:dependencis/dependency/scope
标签的可选值:compile/test/provided/system/runtime/import
①compile和test对比
main目录(空间) | test目录(空间) | 开发过程(时间) | 部署到服务器(时间) | |
---|---|---|---|---|
compile | 有效 | 有效 | 有效 | 有效 |
test | 无效 | 有效 | 有效 | 无效 |
②compile和provided对比
main目录(空间) | test目录(空间) | 开发过程(时间) | 部署到服务器(时间) | |
---|---|---|---|---|
compile | 有效 | 有效 | 有效 | 有效 |
provided | 有效 | 有效 | 有效 | 无效 |
main目录(空间)、test目录(空间)指的是在这两个位置下去引用导入的 jar 包的类是否能正常编译;
开发过程(时间),指的是IDEA的环境下通过 . 是否能将对象方法等提示出来;
部署到服务器(时间),指的是打 war 包的情况下,能否将它打包进 war 包的 lib 目录下。
③结论
compile:通常使用的第三方框架的 jar 包这样在项目实际运行时真正要用到的 jar 包都是以 compile 范围进行依赖的。比如SSM框架所需的 jar 包。
test:测试过程中使用的 jar 包,以 test 范围依赖进来。比如 junit。
provided:在开发过程中需要用到的“服务器上的 jar 包”通常以 provided 范围依赖进来。比如 servlet-api、jsp-api。而这个坊为的 jar 包之所以不参与部署、不放入 war 包,就是避免和服务器上异有的同类 jar 包产生冲突,同时减轻服务器的负担。服务器上已经有了,你就别外带了!
九、测试依赖的传递性
1、依赖的传递性
①概念
A 依赖 B , B 依赖 C ,那么在A没有配置对 C 的依赖的情况下, A里面能不能直接使用 C?
②传递的原则
在 A 依赖 B ,B 依赖 C 的前提下,C 是否能够传递到 A,取决于 B依赖 C 时使用的依赖范围。
- B 依赖 C 时使用 compile 范围: 可以传递
- B 依赖 C 时使用 test 或 provided 范围:不能传递,所以需要这样的 jar 包时,就必须在需要的地方明确配置依赖才可以。
③使用 compile 范围依赖spring-core
测试方式:让 java 工程依赖 spring-core
到 java 工程根目录下修改 pom.xml 配置文件,添加依赖
<!-- 以 compile 范围导入 spring-core 依赖,测试依赖的传递性 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
使用 mvn dependency:tree 命令查看效果:
④web 工程依赖
mvn dependency:tree
我们修改了 java 工程的配置文件完成了依赖的添加,然后我们在 web 工程这里查看
发现没有依赖;
注意:
我们修改的只是我们的工程中的内容,web工程是根据 Maven 仓库的坐标来找的工程,所以我们需要对 java 工程重新进行安装
mvn clean install
完成重新安装后,我们再去查看 web 工程的依赖内容:
可以看到,无论依赖了多少 jar 包,只要是 compile 类型依赖的,都可以向上进行传递。
十、测试依赖的排除
1、概念
当 A 依赖 B ,B 依赖 C 而且 C 可以传递到 A 的时候,A 不想要 C ,需要 A 里面把 C 排除掉。而往往这种情况都是为了避免 jar 包之间的冲突。
所以配置依赖的排除其实就是阻止某些 jar 包的传递。因为这样的 jar 包传递过来会和其他 jar 包冲突
2、配置方式
在web工程的配置文件中找到 java 工程依赖的添加依赖的排除:
<!-- 配置对 Java 工程的依赖 -->
<dependency>
<groupId>com.atjianbing.maven</groupId>
<artifactId>pro01-maven-java</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
<!-- 配置依赖的排除 -->
<exclusions>
<!-- 配置具体排除信息,让 spring-jcl
不要传递到当前 Web 工程(pro01-atjianbing-maven) -->
<exclusion>
<!-- 这里指定坐标不需要指定 version -->
<groupId>org.springframework</groupId>
<artifactId>spring-jcl</artifactId>
</exclusion>
</exclusions>
</dependency>
3、测试
在我们的仓库下找到spring-jcl,指定 jar 包的坐标
我们再到 web 工程下查看依赖树结构:
可以看到没有了 spring-jcl 的依赖了。(这里的排除不会影响java工程的依赖结构)。
十一、继承
1、概念
Maven 工程之间,A 工程继承B 工程
-
B 工程:父工程
-
A 工程:子工程
本质上是 A 工程的 pom.xml 中的配置继承了 B 工程中 pom.xml 的配置。
2、作用
在父工程中同一管理项目中的依赖信息,具体来说是管理依赖信息的版本。
它的背景是:
- 对一个比较大型的项目进行了模块拆分。
- 一个 project 下面,创建了很多个 module。
- 每一个 module 都需要配置自己的依赖信息。
它背后的需求是:
- 在每一个 module 中各自维护各自的依赖信息很容易发生出入,不易同一管理。
- 使用同一个框架内的不同 jar 包,他们应该是同一个版本,所以整个项目中使用的框架版本需要统一。
- 使用框架时所需要的 jar 包组合(或者是依赖信息组合)需要经过长期摸索和反复调试,最终确定一个可用组合。这个耗费很大精力总结出来的方案不应该在新的项目中重新摸索。
通过在父工程中为整个项目维护依赖信息的组合既保证了整个项目使用规范、准确的 jar 包;又能够将以往的经验沉淀下来,节约时间和精力。
3、举例
在一个工程中依赖多个 spring 的 jar 包。使用 Spring 时要求所有的 Spring 自己的jar包版本必须一致。为了能够对这些 jar 包的版本进行统一的管理,我们使用继承这个机制,将所有版本信息统一在父工程中进行管理。
4、操作
①创建父工程
- groupId:com.jianbing.parent
- artifactId:pro02-atjianbing-parent
- version:1.0-SNAPSHOT
工程创建好之后,需要修改它的打包方式:
<groupId>com.jianbing.parent</groupId>
<artifactId>pro02-atjianbing-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 当前工程作为父工程,他要去管理子工程,所以打包方式必须是 pom -->
<packaging>pom</packaging>
只有打包方式为 pom 的 Maven 工程才能管理其他 Maven 工程。打包方式为 pom 的Maven 工程中不写业务代码,它是专门管理其他 Maven 工程的工程。将里面的依赖清空。
②创建模块工程
模块工程类似于 IDEA 中的 module,所以需要进入 pro02-atjianbing-parent 工程的根目录,然后运行 mvn archetype:generate 命令来创建模块工程。
③查看被添加新内容的父工程 pom.xml
下面是 modules 和 module 标签是聚合功能的配置
<!-- 聚合的配置 -->
<modules>
<module>pro03-atjianbing-module</module>
<module>pro04-atjianbing-module</module>
<module>pro05-atjianbing-module</module>
</modules>
④解读子工程的 pom.xml
<!-- parent 标签给当前工程配置父工程 -->
<parent>
<!-- 通过指定父工程的坐标找到父工程 -->
<groupId>com.jianbing.parent</groupId>
<artifactId>pro02-atjianbing-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<!-- 子工程的 groupId 如果和父工程一样,则可以省略 -->
<!-- <groupId>aom.atjianbing.parent</groupId> -->
<!-- 子工程的 version 如果和父工程一样,则可以省略 -->
<!-- <version>1.0-SNAPSHOT</version> -->
<!-- 省略 grouId 和 version 后子工程自己的坐标可以只保留 artifactId -->
<artifactId>pro03-atjianbing-module</artifactId>
⑤在父工程中配置依赖的统一管理
<!-- 使用 dependencyManagement 标签在父工程中统一管理依赖信息 -->
<!-- 被管理的依赖并没有真正被引入到工程,
子工程需要使用具体哪一个依赖还是要明确配置,只是不需要写版本号 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
⑥配置子工程的依赖
<!-- 被管理的依赖并没有真正被引入到工程,
子工程需要使用具体哪一个依赖还是要明确配置 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<!-- 对于已经在父工程进行了管理的依赖,子工程中引用时可以不写 version -->
<!-- 情况1:确实省略 version 标签:子工程采纳的就是父工程的版本 -->
<!-- 情况2:没有省略 version 标签:
A:与父工程管理版本一致,最终还是采纳这个版本
B:与父工程管理版本不一致,那么子工程配置的版本
会覆盖父工程管理的版本并最终会采纳
-->
<!-- <version>5.0.8.RELEASE</version> -->
</dependency>
我们去给04、和05分别添加剩下的依赖(不添加版本号):
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
⑦在父工程中升级依赖信息的版本
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.0.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
再去查看子工程的依赖版本,可以看到,都一起变更了
⑧在父工程声明自定义属性标签
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 创建我们自定义的属性标签 -->
<!-- 标签名:属性名 -->
<!-- 标签值:属性值 -->
<!-- 引用方式:${atjianbing.spring.version} -->
<atjianbing.spring.version>5.1.0.RELEASE</atjianbing.spring.version>
</properties>
修改父工程的依赖version为动态值:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<!-- 通过引用属性表达式设定版本号,这样版本号就成了一个动态值 -->
<version>${atjianbing.spring.version}</version>
</dependency>
我们再直接修改我们配置的属性5.0.8,可以看到又变回5.0.8版本的Spring了
真正的做到改一处,处处变。
5、实际意义
编写一套符合要求、开发各种功能都能正常工作的依赖组合并不容易。如果公司里已经有人总结了成熟的组合方案,那么再开发新项目时,如果不使用原有的积累,而是重新摸索,会浪费大量的时间。为了提高效率,我们可以使用工程继承的机制,让成熟的依赖组合方案能够保留下来。
如上图所示,公司级的父工程中管理的就是成熟的依赖组合方案,各个新项目、子系统各取所需即可。
十二、聚合
1、聚合本身的含义
部分组成整体
动画片《战神金刚》中的经典台词:“ 我来组成头部!我来组成手臂!”就是聚合关系最生动的体现。
2、Maven 中的聚合
使用一个“总工程” 将各个“模块工程”汇集起来,作为一个整体对应完整的项目。
- 项目:整体
- 模块:部分
概念的对应关系:
从继承关系角度来看:
- 父工程
- 子工程
从句和关系角度来看:
- 总工程
- 模块工程
3、好处
-
—键执行Maven命令:很多构建命令都可以在“总工程”中—键执行。
以 mvn install 命令为例:Maven 要求有父工程时先安装父工程;有依赖的工程时,先安装被依赖的工程。我们自己考虑这些规则会很麻烦。但是工程聚合之后,在总工程执行 mvn install 可以一键完成安装,而且会自动按照正确的顺序执行。
-
配置聚合之后,各个模块工程会在总工程中展示一个列表,让项目中的各个模块一目了然。
<!-- 测试聚合之后可以一键安装:让 pro03 依赖 pro04,pro04 依赖 pro05 -->
<dependency>
<groupId>aom.atjianbing.parent</groupId>
<artifactId>pro04-atjianbing-module</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
执行命令 mvn clean install:
构建的顺序为 02(父)→05(子)→04(子)→03(子),与子工程的构建顺序与依赖方向相反。但是父工程都是第一个构建的。
4、聚合的配置
在总工程中配置 nodules 即可:
<modules>
<module>pro03-atjianbing-module</module>
<module>pro04-atjianbing-module</module>
<module>pro05-atjianbing-module</module>
</modules>
5、循环依赖问题
如果 A 工程依赖 B 工程,B 工程依赖 C 工程,C 工程又反过来依赖 A 工程,那么在执行构建操作时会构建失败,提示错误。
这个错误的情况时:循环引用。
十三 、使用 Maven:IDEA 环境
1、创建父工程
什么都不用添加,下一步:
选择自己的路径位置进行创建,按需要更改GroupID:
创建完成后,来到settings,一级一级打开
或者打开下图所示位置:
我们一般不使用IDEA自带的Maven环境,选择我们自己的 Maven 路径(关于配置自己的 Maven环境,请看第二部分),选择bin目录的上一级目录
有些版本会自动识别仓库和setting .xml 文件,没有的话就自己去修改路径,选择自己的仓库和setting,如果项目还是会有报错,重开一下项目就好了。
2、创建 Java 子模块
什么都不用管点下一步:
然后修改我们的名称,GroupID会自动使用父工程的:
或许会有小伙伴出现版本不兼容的问题,这边建议下载3.5.4版本的 maven 下载地址如下:(我也是IDEA版本不兼容的问题,换成3.5.4就解决问题了)
https://archive.apache.org/dist/maven/maven-3/3.5.4/binaries/apache-maven-3.5.4-bin.zip
进行测试:
将junit导入依赖:
编写一个主类和测试类:
运行成功
完成在IDEA中创建父工程,并再子工程完成测试。
3、在IDEA中的三种命令行使用方法
方法一:
打开IDEA右边的Maven选择需要进行命令行运行命令的工程,选中生命周期,以下就是我们前面所使用的一些命令。
可进行编译、测试等操作
也可以在插件中:
也可以看到依赖的传递:
方法二:
打开 Maven 中的 m,输入需要的命令就可执行。
方法三
4、创建 Web 子模块
与创建 Java 子模块的顺序一样,先创建子项目
在配置文件 pom.xml 下添加打包方式为war
生成web结构
到我们的项目结构中,我们默认的web路径是在项目中的src\main\webapp下
修改资源目录,可能会报红,打开生成以下路径就可以了:
创建java类,index.jsp
配置 Tomcat 本地服务器:
开启服务器,打开页面:
5、工程导入
Maven 工程除了自己创建的,还有很多情况是别人创建的。而为了参与开发或者是参考学习,我们都需要导入到 IDEA 中。下面分几种不同情况来说明。
①来自版本控制系统
目前通常使用的是Git(本地库) + 码云(远程库) 的版本控制系统,结合IDEA的相关操作方式。(这里不做多的介绍)
②来自工程目录
直接使用 IDEA 打开工程目录即可:
[1]工程压缩包
假设别人发给我们一个 Maven 工程的 zip 压缩包:xxx.zip。从码云或 GitHub 上也可以以 ZIP 压缩格式对项目代码打包下载。
[2] 解压
如果你的所有 IDEA 工程有一个专门的目录来存放,而不是散落各处,那么首先我们就把 ZIP 包解压到这个指定目录中。
[3]打开
只要我们确认在解压目录下可以直接看到 pom.xml ,那就能证明这个解压目录就是我们的工程目录,接下来让 IDEA 打开这个项目就可以了。
[4]配置 Maven 核心程序位置
打开一个新的 Maven 工程,和创建一个 Maven 工程是一样的,此时 IDEA 的 settings 配置中关于 Maven 仍是默认值,需要手动去指定 Maven 核心程序位置,本地仓库位置等。
6、模块导入
①java子工程导入
将我们的子模块文件夹直接复制到新的测试工程下,记得要将target等文件删掉,只留src 和 pom.xml文件。
IDEA 此时是以一个普通文档进行加载的,而不是一个Maven:
打开项目结构
选择需要导入的模块,这里先导入Java子模块:
就可以完成运行了
② Web子工程导入
与Java 工程基本一致,多个检查项目结构,web.xml 的文件目录是否规范。
十四、其他核心概念
1、生命周期
①作用
为了让构建过程自动化完成,Maven 设定了三个生命周期,生命周期中的每一个环节对应构建过程中的一个操作。
②三个生命周期
生命周期名称 | 作用 | 各个环节 |
---|---|---|
Clean | 清理操作相关 | pre-clean clean post-clean |
Site | 生成站点相关 | pre-site site post-site deploy-site |
Default | 主要构建过程 | validate generate-sources process-sources generate-resources process-resources 复制并处理资源文件,至目标目录,准备打包。 compile 编译项目 main 目录下的源代码。 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将最终的包复制到远程的仓库,以让其它开发人员共享;或者部署到服务器上运行(需借助插件,例如:cargo)。 |
③特点
- 前面三个生命周期彼此是独立的。
- 在任何一个生命周期内部,执行任何一个具体环节的操作,都是从本周期最初的位置开始执行,直到指定的地方。(本节记住这句话就行了,其他的都不需要记)
Maven 之所以这么设计其实就是为了提高构建过程的自动化程度:让使用者只关心最终要干的即可,过程中的各个环节是自动执行的。
2、插件和目标
①插件
Maven 的核心程序仅仅负责宏观调度,不做具体工作。具体工作都是由 Maven 插件完成的。例如:编译就是由 maven-compiler-plugin-3.1.jar 插件来执行的。
②目标
一个插件可以对应多个目标,而每一个目标都和生命周期中的某一个环节对应。
Default 生命周期中有 compile 和 test-compile 两个和编译相关的环节,这两个环节对应 compile 和 test-compile 两个目标,而这两个目标都是由 maven-compiler-plugin-3.1.jar 插件来执行的。
3、仓库
- 本地仓库:在当前电脑上,为电脑上所有 Maven 工程服务
- 远程仓库:需要联网
- 局域网:我们自己搭建的 Maven 私服,例如使用 Nexus 技术。
- Internet
- 中央仓库
- 镜像仓库:内容和中央仓库保持一致,但是能够分担中央仓库的负载,同时让用户能够就近访问提高下载速度,例如:Nexus aliyun
建议:不要中央仓库和阿里云镜像混用,否则 jar 包来源不纯,彼此冲突。