Maven是用于管理和构建Java项目的工具,是apache旗下的开源项目
Maven的作用:
- 依赖管理
- 项目构建
- 统一项目结构
-
依赖管理工具:管理规模庞大的jar包及其中的依赖关系
依赖:junit-4.12依赖hamcrest-core-1.3
依赖管理需要解决的具体问题:
-
jar包下载
-
jar包的依赖:通过依赖的传递性自动完成
-
jar包的冲突:通过对依赖的配置进行调整,让某些jar包不会被导入
-
-
项目构建工具:脱离IDE环境的构建过程
构建是Idea帮我们自动完成的,但是脱离IDE也需要进行构建
构建:从原材料(.java、.html、img、properties)到产品(可以在服务器上运行的项目)的过程
构建的过程:
- 清理:删除上一次构建结果,为下一次构建做准备
- 编译:.java源文件编译为.class字节码文件
- 测试:运行准备好的测试程序
- 报告:针对刚才的测试结果生成全面的信息
- 打包:
- Java工程:jar包
- Web工程:war包
- 安装:Maven工程经过打包生成的包安装到Maven仓库
- 部署:将准备好的包部署到服务器上运行
- jar包部署在Nexus私服上
- cargo等将war包部署在Tomcat服务器上(智能化程度不够)
Maven工作机制:
3. 统一项目结构
Idea和Eclipse的项目结构是不同的,不能互相导入
但是Maven可以统一项目结构
安装与配置
Maven – Welcome to Apache Maven
选择maven-3.9.2-bin.zip
核心程序:
核心配置文件 conf/settings.xml
- 配置本地仓库位置
- 指定镜像仓库
- 配置Maven的JDK版本
<profile>
<id>jdk-17</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>17</jdk>
</activation>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.compilerVersion>17</maven.compiler.compilerVersion>
</properties>
</profile>
-
配置MAVEN_HOME
-
配置环境变量PATH
Maven核心
Maven基于项目对象模型POM,通过一小段描述信息来管理项目的构建
GAV
GAV就是 坐标,用三个标志在Maven的仓库中定位到一个唯一的jar包
-
groupId:公司或组织id,通常为公司或组织域名的倒序。
-
artifactId:一个项目或者是项目中一个模块的名称,将来作为Maven工程的工程名
-
version:模块的版本号,根据自己的需要设置
- SNAPSHOT:快照版本,正在迭代过程中的版本
- RELEASE:正式版本
groupId:com.euneir.maven
artifactId:pro01-euneir-maven
version:1.0-SNAPSHOT
- 坐标和本地仓库的对应关系:
坐标:
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
本地仓库地址:
Maven本地仓库根目录\javax\servlet\servlet-api\2.5\servlet-api-2.5.jar
实验
实验目录为Maven_work下的MavenTestSpace
进入该目录,使用命令:mvn archetype:generate
创建Maven工程
选择模板:
普通Java工程就是7
![image-20230613143546292](file:///D:/%E6%96%B0%E5%BB%BA%E6%96%87%E4%BB%B6%E5%A4%B9/MarkDown/Maven/assets/image-20230613143546292.png?lastModify=1701050818)
对默认生成的工程进行调整:
Maven默认生成工程对Junit依赖是低版本的3.8.1,我们可以改成合适的4.12版本;其中自动生成的App.java和AppTest.java可以删除
POM
POM:Project Object Model 项目对象模型
POM表示将工程抽象为一个模型,再用程序的对象来描述这个模型。
目录结构
另外还有target目录专门存放构建操作输出的结果
在main-java和test-java下分别写源代码、测试代码,进行项目构建
在Maven中运行和构建相关的命令时,必须进入pom.xml所在目录
#执行以下命令必须cd进pom.xml文件所在目录
mvn clean #清理target目录
mvn compile #编译主程序,在项目根目录下生成target(包含resources目录下的内容)
mvn test-compile #编译测试程序,生成target
mvn test #测试,生成目录surefire-reports,保存测试结果
mvn package #打包主程序,编译、编译测试、测试,按照pom.xml中的配置将主程序打包为jar或war,生成在target目录下
mvn install #安装主程序 将本工程打包,按照本工程的坐标保存在本地仓库中
mvn deploy #部署主程序,将本工程打包,按照坐标保存在本地仓库中,保存在私服仓库中,将项目部署到web容器中
mvn-compile
完成后会在pom.xml同级目录下生成一个target文件夹
mvn package
打包,会在target目录下生成一个jar
在每个阶段执行时(打包等),都会将Maven的生命周期执行到对应的阶段
mvn install
将jar包存入本地仓库当中
创建web工程
创建出的项目结构:
没有test文件夹。
web.xml的版本较低,可以参照[[JavaWeb#Servlet入门程序|web.xml的配置]]配置一个更高版本的web.xml
mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DarchetypeVersion=1.4
在pom.xml中添加jakarta依赖,开发一个简单的servlet
mvn package
进行打包,target目录下生成war文件
将该war文件直接放在Tomcat的webapps目录下,启动Tomcat访问
但是当前的工程名太长了,直接访问不方便,可以修改pom文件指定工程名称:
<!-- https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency></dependencies>
<build>
<finalName>pro2</finalName>
</build>
生成的war包的名字就是pro2,启动服务器后浏览器访问http://localhost:8080/pro2/hello
即可
注意:Tomcat10只能使用jakarta
依赖
让Web工程依赖Java工程,只有Web工程依赖Java工程,Web工程依赖的Java工程实际上就是Web工程里导入的jar包,最终Java工程会变为jar包,放在Web工程的WEB-INF/lib目录下
在web工程的pom文件中配置对第一个Java工程的依赖:
将web工程打包,查看war包的lib目录:
包含了对java工程的依赖,和java工程对其他jar包的依赖
查看web工程的依赖:
mvn dependency:list
或者mvn dependency:tree
依赖的范围
标签的位置:dependencies/dependency/scope
标签的可选值:compile/test/provided/system/runtime/import
可选值 | main目录(空间) | test目录(空间) | 开发过程(时间) | 部署到服务器(时间) |
---|---|---|---|---|
compile | 有效 | 有效 | 有效 | 有效 |
test | 无效 | 有效 | 有效 | 无效 |
provided(已提供) | 有效 | 有效 | 有效 | 无效 |
对于web工程来说,compile范围才会放在WEB-INF下的war包当中
Maven提供test、provided只是为了与普通依赖区分开
provided:Tomcat已经提供的依赖,不需要部署到服务器上,部署上去可能会有冲突(Servlet等)
runtime:JDBC Driver就可以设置为runtime,因为编译阶段不需要使用JDBC Driver类,只需要在运行阶段使用。
依赖的传递性
A依赖B,B依赖C,在没有配置A对C的依赖的情况下,是否可以使用C?
结论:B对C是compile依赖就可以传递过去,是test/provide依赖就不能传递过去
测试方案:让java工程依赖spring-core
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
发现spring-core依赖于commons-loggin,使用list查看:
此处列出的都是可以使用的依赖,查看spring-core对common-loggin的是何种依赖:
查看local-repo中spring-core的pom文件
是compile依赖,这样的依赖是可以传递给Java工程的
如果是:
pro02 --> pro01 --> spring-core --> commons-logging
pro02中是否可以使用commons-logging?
需要将java工程重新安装到Maven的本地仓库
compile也是可以使用的
依赖的排除
依赖的排除可以阻断依赖的传递性
如果不处理,X的1.0和2.0版本都会传递过来,也就是A同时导入了1.0和2.0,在某些情况下可能导致jar包的冲突,如果希望保留2.0版本的jar包,就需要阻止1.0版本jar包的传入
阻止B工程的x-1.0.jar传入A工程,就需要在A工程依赖B工程的时候配置排除X-1.0.jar
所以配置依赖的排除其实就是阻止某些 jar 包的传递。因为这样的 jar 包传递过来会和其他 jar 包冲突。
配置方式:
在A的POM.xml的dependency依赖B工程时中配置exclusions
<dependency>
<groupId>com.eun.maven</groupId>
<artifactId>pro-b</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
<!-- 使用excludes标签配置依赖的排除 -->
<exclusions>
<!-- 在exclude标签中配置一个具体的排除 -->
<exclusion>
<!-- 指定要排除的依赖的坐标(不需要写version) -->
<groupId>c</groupId>
<artifactId>c</artifactId>
</exclusion>
</exclusions>
</dependency>
pro02 --> pro01 --> spring-core --> common-loggin
#在pro01中配置
在pro01中配置,不让common-loggin传递给pro02
分模块开发
分模块开发是先针对模块功能进行设计,再进行编码。
将项目按照功能拆分为若干子模块,方便项目的管理维护、扩展,也方便模块间的互相调用,资源共享。
实践:将原先的tlias-web-management拆分出tlias-pojo模块存放实体类和tlias-utils存放相关工具类
拆分时注意:保证拆分后模块中的实体类包名和拆分前的实体类包名相同
tlias-pojo模块存放实体类,需要使用lombok和spring-boot中的@DateTimeFormate注解,也就需要对应依赖:
<!--tlias-pojo模块-->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>3.1.6</version>
</dependency>
</dependencies>
tlias-utils存放工具类,需要lombok和OSS、JWT的依赖:
<!--tlias-utils模块-->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<!--JWT-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!--OSS-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>
</dependencies>
在tlias-web-management引入这两个模块:
<dependency>
<groupId>com.itheima</groupId>
<artifactId>tlias-pojo</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.itheima</groupId>
<artifactId>tlias-util</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
继承
在tlias-web-management、tlias-pojo、tlias-utils中都引入了lombok依赖,如果要修改这个依赖的版本,在三个工程中都需要修改:
使用maven的继承机制可以解决这个问题,继承可以把公共的依赖抽取到父工程中
- 概念:继承描述的是两个工程间的关系,子工程可以继承父工程的配置信息,常见于依赖关系的继承
- 实现:子工程通过
<parent>...</parent>
指定父工程
继承有两个重要作用:
- 在父工程中通过
<dependencies></dependencies>
引入子工程的公共依赖,通过继承机制会在子工程中直接继承下来 - 在父工程中通过
<depedencyManagement></depedencyManagement>
管理子工程的依赖版本,不会直接引入依赖
父工程引入公共依赖
- 对tlias-web-management、tlias-pojo、tlias-utils抽取父工程tlias-parent:
tlias-parent为父工程,设置打包方式为pom
pom:父工程或聚合工程,该模块内不写代码,仅进行依赖管理
-
在子工程的pom.xml中配置依赖关系
-
在父工程中配置各个子工程的共有的依赖(子工程会自动继承父工程的依赖)
<!--tlias-parent-->
<groupId>com.itheima</groupId>
<artifactId>tlias-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!--公共依赖-->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>3.1.6</version>
</dependency>
</dependencies>
<!--tlias-pojo-->
<parent>
<groupId>com.itheima</groupId>
<artifactId>tlias-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../tlias-parent/pom.xml</relativePath> <!--指定父工程pom文件的位置-->
</parent>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
继承父工程后,子工程的
<groupId>com.itheima</groupId>
可以删除
<!--tlias-utlis-->
<parent>
<groupId>com.itheima</groupId>
<artifactId>tlias-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../tlias-parent/pom.xml</relativePath> <!--指定父工程pom文件的位置-->
</parent>
<groupId>com.itheima</groupId>
<artifactId>tlias-util</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--JWT-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!--OSS-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>
</dependencies>
但是tlias-web-manager中,原先已经指定了父工程spring-boot-starter-parent:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.itheima</groupId>
<artifactId>tlias-web-management</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>tlias-web-management</name>
<description>tlias-web-management</description>
maven工程不能同时指定两个父工程,tlias-web-manager需要spring-boot-starter-parent进行依赖版本管理,此处需要使用间接继承:
将tlias-parent的父工程设置为spring-boot-starter-parent
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.itheima</groupId>
<artifactId>tlias-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
总结
- 创建父工程,设置打包方式为pom,继承spring-boot-starter-parent
- 子工程中配置继承关系
<parent> <relativePath>父工程pom相对路径</relativePath></parent>
- 父工程配置各个工程的共有依赖
- 子工程中配置了继承关系后,GAV中的groupId可以省略,自动继承自父工程
- relativePath指定了父工程的pom文件所在位置,如果不指定将从本地仓库/远程仓库中查找该工程
- 如果父子工程都配置了同一个依赖的不同版本,以子工程的为准
项目开发中可能有两种工程结构:
只不过展现形式不同,实际上是一样的。
父工程中版本锁定
在父工程中,可以使用<depedencyManagement>
管理子工程中依赖的版本
当前的项目中有三个子工程都使用了0.9.1版本的jwt,其他两个子工程没有使用,不能作为公共依赖抽取到父工程中,如果要修改为0.9.0版本的jwt就需要在子工程中一个一个修改,太繁琐,在父工程中使用dependencyManagement管理子工程的依赖版本:
子工程引入依赖时,无需指定
<version>
版本号,父工程统一管理。变更依赖版本,只需在父工程中统一变更。
以OSS相关依赖为例:
<!--tlias-parent-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>
</dependencies>
</dependencyManagement>
在子工程中使用的时候就可以不指定该依赖的版本:
<!--tlias-utils-->
<dependencies>
<!--OSS-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</dependency>
</dependencies>
注意:在父工程的depedencyManagement中并不是引入了该依赖,而是指定了这个依赖的版本
spring boot使用的大多数依赖不需要指定依赖版本,因为在父工程中指定了依赖的版本:
<!--我们创建的springboot工程都会自动指定父工程-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!--spring-boot-starter-parent-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.1.6</version>
</parent>
<!--spring-boot-dependencies-->
<properties>
<activemq.version>5.18.3</activemq.version>
<angus-mail.version>1.1.0</angus-mail.version>
<artemis.version>2.28.0</artemis.version>
<aspectj.version>1.9.20.1</aspectj.version>
<assertj.version>3.24.2</assertj.version>
<awaitility.version>4.2.0</awaitility.version>
</properties>
自定义属性/引用属性
如果父工程pom文件depedencyManagement中指定版本的依赖很多,修改版本时一个一个查找太麻烦了,可以使用自定义属性改进:
<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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.itheima</groupId>
<artifactId>tlias-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<lombok.version>1.18.30</lombok.version>
<jwt.version>0.9.1</jwt.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version> <!--继承机制传递给子工程的直接依赖-->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>3.1.6</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jwt.version}</version> <!--父工程中版本管理指定的依赖版本-->
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
聚合
对于上文中的tlias-web-management模块进行打包会报错:
[ERROR] Failed to execute goal on project tlias-web-management: Could not resolve dependencies for project com.itheima:tlias-web-management:jar:0.0.1-SNAPSHOT: The following artifacts could not be resolved: com.itheima:tlias-pojo:jar:1.0-SNAPSHOT (absent), com.itheima:tlias-util:jar:1.0-SNAPSHOT (absent): Could not find artifact com.itheima:tlias-pojo:jar:1.0-SNAPSHOT -> [Help 1]
因为当前模块依赖了tlias-pojo、tlias-utils模块:
在本地仓库中找不到对应的jar包,需要先对pojo和utils模块进行install,再对tlias-web-management模块进行package,但是还会报错:
[ERROR] Failed to execute goal on project tlias-web-management: Could not resolve dependencies for project com.itheima:tlias-web-management:jar:0.0.1-SNAPSHOT: Failed to collect dependencies at com.itheima:tlias-pojo:jar:1.0-SNAPSHOT: Failed to read artifact descriptor for com.itheima:tlias-pojo:jar:1.0-SNAPSHOT: The following artifacts could not be resolved: com.itheima:tlias-parent:pom:1.0-SNAPSHOT (absent): Could not find artifact com.itheima:tlias-parent:pom:1.0-SNAPSHOT -> [Help 1]
tlias-web-management是tlias-parent的子工程,需要先将tlias-parent进行install才能对tlias-web-management进行package。
继承下对某个子模块进行package,需要按照依赖关系对被依赖的模块先install,如果是大型项目这个操作是非常繁琐的。
-
聚合机制:将多个模块聚合为一个整体,同时进行项目的构建,Maven自动处理依赖关系
-
聚合工程:一个没有业务功能的空工程,仅包含一个pom文件
-
作用:快速进行项目构建,无需根据依赖关系手动构建,直接对聚合工程构建
此时的父工程就是聚合工程,聚合工程就是父工程,从继承角度来说就是父工程,从聚合角度来说就是聚合工程
- 在聚合工程中可以通过
<modules></modules>
设置当前聚合工程包含的子模块名称
<parent> <!--父工程-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modules> <!--聚合工程-->
<module>../tlias-pojo</module>
<module>../tlias-util</module>
<module>../tlias-web-management</module>
</modules>
构建时根据依赖关系自动设置构建顺序,设置完后maven结构:
总结
maven中继承和聚合的区别和联系:
-
联系:聚合和继承都属于设计型模块,打包方式都是pom,常将两种关系制作在同一个pom文件中(父工程/聚合工程)
-
区别:
-
继承用于抽取公共依赖、统一管理依赖版本,在子工程中配置依赖关系
-
聚合用于快速构建项目,在聚合工程中配置聚合的模块
?
继承
A工程继承自B工程
-
B工程 :父工程
-
A工程 : 子工程
本质上是A工程的POM.xml中的配置继承了B工程中POM.xml的配置
在A、B、C、D、E工程中都使用了Spring框架,要保证这些工程使用的jar包版本一致;或者是版本号信息保存在父工程当中,实现一处修改处处生效的效果
在父工程中统一管理项目中的依赖信息,具体来说是管理依赖信息的版本。
它的背景是:
-
对一个比较大型的项目进行了模块拆分。
-
一个 project 下面,创建了很多个 module。
-
每一个 module 都需要配置自己的依赖信息。
它背后的需求是:
-
在每一个 module 中各自维护各自的依赖信息很容易发生出入,不易统一管理。
-
使用同一个框架内的不同 jar 包,它们应该是同一个版本,所以整个项目中使用的框架版本需要统一。
-
使用框架时所需要的 jar 包组合(或者说依赖信息组合)需要经过长期摸索和反复调试,最终确定一个可用组合。这个耗费很大精力总结出来的方案不应该在新的项目中重新摸索。
通过在父工程中为整个项目维护依赖信息的组合既保证了整个项目使用规范、准确的 jar 包;又能够将以往的经验沉淀下来,节约时间和精力。
示例
[INFO] +- org.springframework:spring-core:jar:4.0.0.RELEASE:compile
[INFO] | \- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] +- org.springframework:spring-beans:jar:4.0.0.RELEASE:compile
[INFO] +- org.springframework:spring-context:jar:4.0.0.RELEASE:compile
[INFO] +- org.springframework:spring-expression:jar:4.0.0.RELEASE:compile
[INFO] +- org.springframework:spring-aop:jar:4.0.0.RELEASE:compile
[INFO] | \- aopalliance:aopalliance:jar:1.0:compile
使用 Spring 时要求所有 Spring 自己的 jar 包版本必须一致。为了能够对这些 jar 包的版本进行统一管理,我们使用继承这个机制,将所有版本信息统一在父工程中进行管理。
实验
- 创建父工程
创建过程与之前创建pro01-maven-java相同
工程名称:pro03-maven-parent
创建完成后修改打包方式为pom,只有打包方式为pom的工程才能管理其他Maven工程,打包方式为pom的Maven工程中不写业务代码,专门管理其他Maven工程的工程
<groupId>com.atguigu.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 当前工程作为父工程,它要去管理子工程,所以打包方式必须是 pom -->
<packaging>pom</packaging>
在父工程中创建模块工程(子工程) pro04、pro05
从继承角度来说,是父子工程的关系;从聚合角度来说,是总体和模块的关系
创建好子工程后,父工程的pom.xml文件会发送变化:
<!--pro03-maven-parent-->
<modules>
<module>pro04-maven-module</module>
<module>pro05-maven-module</module>
</modules>
并且子工程的pom.xml文件也会发生变化:
<!--pro04、pro05的pom文件-->
<parent>
<groupId>com.euneir.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
在子工程中自动指定了父工程
并且如果子工程的groupId和version和父工程相同是可以省略的。
父工程统一依赖管理
<!-- 使用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>
但是这不是父工程引入了这些依赖,子工程也不是可以直接使用这些依赖的,子工程还需要使用dependency配置使用的依赖
父工程只是指定了依赖的版本。
在子工程中指定依赖:
可以省略版本号,代表当前依赖的版本就是父工程中dependcyManagement指定的依赖版本
-
如果子工程指定了版本号,并且子工程指定的版本号与父工程不同,子工程指定的版本会覆盖父工程指定的版本
-
在父工程中修改了依赖版本号,所有子工程立刻生效
但是如果要更改很多标签,父工程一个一个修改太麻烦了:
可以将版本号都抽取到properties中自定义标签,本工程或子工程需要指定版本号的地方就${自定义标签名}
<name>pro03-maven-parent</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<eun.spring.version>6.0.11</eun.spring.version>
</properties>
<dependencies>
<dependency> <groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${eun.spring.version}</version>
</dependency> <dependency> <groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>${eun.spring.version}</version>
</dependency>
</dependencies>
<modules>
<module>pro04-maven-module</module>
<module>pro05-maven-module</module>
</modules>
继承的实际应用
编写一套符合要求、开发各种功能都能正常工作的依赖组合并不容易。如果公司里已经有人总结了成熟的组合方案,那么再开发新项目时,如果不使用原有的积累,而是重新摸索,会浪费大量的时间。为了提高效率,我们可以使用工程继承的机制,让成熟的依赖组合方案能够保留下来。
聚合
聚合就是使用一个总工程将各个模块工程汇集起来,作为一个整体对应完整的项目
好处:
- 一键执行Maven命令:很多构建命令都可以在总工程中一键执行
以mvn install为例,如果当前工程有父工程时应该先安装父工程,有依赖的工程先安装被依赖的工程,自己考虑这些规则太麻烦了,在工程聚合之后,在总工程执行mvn install就可以一键完成安装,并且按照正确的顺序执行
- 配置聚合后,各个模块工程会在总工程中展示一个列表,让项目中的模块一目了然。
聚合可以快速构建项目
演示
在总工程中配置:
<modules>
<module>pro04-maven-module</module>
<module>pro05-maven-module</module>
<module>pro06-maven-module</module>
</modules>
依赖问题演示:让4 -> 5 -> 6
D:\Development\Maven_work\MavenSpace\pro03-maven-parent>mvn dependency:tree
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] pro03-maven-parent [pom]
[INFO] pro06-maven-module [jar]
[INFO] pro05-maven-module [jar]
[INFO] pro04-maven-module [jar]
[INFO]
[INFO] ------------------< com.eun.maven:pro03-maven-parent >------------------
[INFO] Building pro03-maven-parent 1.0-SNAPSHOT [1/4]
[INFO] from pom.xml
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] --- dependency:2.8:tree (default-cli) @ pro03-maven-parent ---
[INFO] com.eun.maven:pro03-maven-parent:pom:1.0-SNAPSHOT
[INFO]
[INFO] ------------------< com.eun.maven:pro06-maven-module >------------------
[INFO] Building pro06-maven-module 1.0-SNAPSHOT [2/4]
[INFO] from pro06-maven-module\pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- dependency:2.8:tree (default-cli) @ pro06-maven-module ---
[INFO] com.eun.maven:pro06-maven-module:jar:1.0-SNAPSHOT
[INFO] \- junit:junit:jar:3.8.1:test
[INFO]
[INFO] ------------------< com.eun.maven:pro05-maven-module >------------------
[INFO] Building pro05-maven-module 1.0-SNAPSHOT [3/4]
[INFO] from pro05-maven-module\pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- dependency:2.8:tree (default-cli) @ pro05-maven-module ---
[INFO] com.eun.maven:pro05-maven-module:jar:1.0-SNAPSHOT
[INFO] +- junit:junit:jar:3.8.1:test
[INFO] \- com.eun.maven:pro06-maven-module:jar:1.0-SNAPSHOT:compile
[INFO]
[INFO] ------------------< com.eun.maven:pro04-maven-module >------------------
[INFO] Building pro04-maven-module 1.0-SNAPSHOT [4/4]
[INFO] from pro04-maven-module\pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- dependency:2.8:tree (default-cli) @ pro04-maven-module ---
[INFO] com.eun.maven:pro04-maven-module:jar:1.0-SNAPSHOT
[INFO] +- junit:junit:jar:3.8.1:test
[INFO] +- com.eun.maven:pro05-maven-module:jar:1.0-SNAPSHOT:compile
[INFO] | \- com.eun.maven:pro06-maven-module:jar:1.0-SNAPSHOT:compile
[INFO] \- org.springframework:spring-core:jar:4.0.0.RELEASE:compile
[INFO] \- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for pro03-maven-parent 1.0-SNAPSHOT:
[INFO]
[INFO] pro03-maven-parent ................................. SUCCESS [ 0.520 s]
[INFO] pro06-maven-module ................................. SUCCESS [ 0.036 s]
[INFO] pro05-maven-module ................................. SUCCESS [ 0.018 s]
[INFO] pro04-maven-module ................................. SUCCESS [ 0.020 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.788 s
[INFO] Finished at: 2023-06-14T13:41:22+08:00
[INFO] ------------------------------------------------------------------------
[WARNING]
[WARNING] Plugin validation issues were detected in 2 plugin(s)
[WARNING]
[WARNING] * org.apache.maven.plugins:maven-site-plugin:3.12.1
[WARNING] * org.apache.maven.plugins:maven-dependency-plugin:2.8
[WARNING]
[WARNING] For more or less details, use 'maven.plugin.validation' property with one of the values (case insensitive): [BRIEF, DEFAULT, VERBOSE]
[WARNING]
提取有效信息:
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- dependency:2.8:tree (default-cli) @ pro05-maven-module ---
[INFO] com.eun.maven:pro05-maven-module:jar:1.0-SNAPSHOT
[INFO] +- junit:junit:jar:3.8.1:test
[INFO] \- com.eun.maven:pro06-maven-module:jar:1.0-SNAPSHOT:compile
[INFO]
[INFO] ------------------< com.eun.maven:pro04-maven-module >------------------
[INFO] Building pro04-maven-module 1.0-SNAPSHOT [4/4]
[INFO] from pro04-maven-module\pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- dependency:2.8:tree (default-cli) @ pro04-maven-module ---
[INFO] com.eun.maven:pro04-maven-module:jar:1.0-SNAPSHOT
[INFO] +- junit:junit:jar:3.8.1:test
[INFO] +- com.eun.maven:pro05-maven-module:jar:1.0-SNAPSHOT:compile
[INFO] | \- com.eun.maven:pro06-maven-module:jar:1.0-SNAPSHOT:compile
[INFO] \- org.springframework:spring-core:jar:4.0.0.RELEASE:compile
[INFO] \- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] ------------------------------------------------------------------------
此时pro03既是总工程,又是总聚合工程
依赖循环问题:
如果 A 工程依赖 B 工程,B 工程依赖 C 工程,C 工程又反过来依赖 A 工程,那么在执行构建操作时会报下面的错误:
[ERROR] [ERROR] The projects in the reactor contain a cyclic reference:
这个错误的含义是:循环引用。
Idea使用Maven
空父工程-子工程Build System创建
- 父工程指定JDK版本为17
- 子Module选择Build System为Maven
- 子工程Module添加test-resources文件夹
父子工程Maven Archetype创建
Idea中的project就是父工程,Module就是子工程/模块工程
刚创建完毕的父工程pom.xml文件中打包方式是jar
创建一个子工程后,父工程的打包方式变为pom,并且自动指定子工程module
运行命令
注意范围的选择
也可以跳过测试的环节:
mvn clean install -Dmaven.test.skip=true
创建Web工程
quick-start
- 首先创建quickstart工程 pro-child02-web
缺少resource、webapp等文件夹,web.xml等文件并且打包方式也要修改
- add framework support - web
修改文件夹位置:
src
main
java
resources
webapp
test
java
resources
- project structure
- 添加resources文件夹
webapp
根据webapp模板创建的工程自动为war包:
但是缺少很多文件夹,并且web.xml文件版本过低,需要参照[[JavaWeb#第一个Web程序|web.xml]]设置新版本web.xml
创建出的项目结构:
缺少java文件夹,并且建议在project structer中检查web.xml文件位置和webapp根目录
导入Maven工程
project structure/Maven插件中导入模块,选择pom文件导入
如果删除之后再导入没有反应,检查.idea目录下的compiler.xml文件中的缓存记录
Idea Maven 报错解决
报错的原因大概可以分为两类:
- settings配置文件有错误
- jar包未下载完毕导致错误
下面主要介绍第二种问题的解决办法
- maven 插件不断刷新
- maven 插件刷新,但是还是爆红,说明在下载的过程中网络中断,jar包被变为lastUpdated文件,该文件不删除就无法继续下载。 运行del.bat文件, 递归删除当前目录下所有以lastUpdated结尾的文件
- 之后继续回到idea中刷新,如果下载完毕还是报错,就close project 再打开
或者参照[[Maven报错的解决办法]]
生命周期
Maven有三套相互独立的生命周期
- clean:清理工作
- default:核心工作,如:编译、测试、打包、安装、部署
- site:生成报告、发布站点等
每套生命后期都包含一些阶段(phase),阶段是有顺序的,后面的阶段依赖于前面的阶段
我们只需要关注五个生命周期即可。
在同一套生命周期中,运行后面的阶段时,前面的阶段都会运行
注意:A工程依赖B工程,如果直接编译A工程报错:找不到B工程的jar包,需要先installB工程的jar包到本地仓库
插件和目标
Maven的核心程序仅负责宏观调度,不做具体工作,具体工作都由Maven的插件完成。例如:compiler就是由 maven-compiler-plugin-3.1.jar 插件来执行的。
一个插件可以对应多个目标,而每一个目标都和生命周期中的某一个环节对应。
Default 生命周期中有 compile 和 test-compile 两个和编译相关的环节,这两个环节对应 compile 和 test-compile 两个目标,而这两个目标都是由 maven-compiler-plugin-3.1.jar 插件来执行的
调用package实际上就是调用了jar插件
install
install就是将jar包安装到本地仓库中,存储的规则:
<groupId>com.itheima</groupId>
<artifactId>maven-project02</artifactId>
<version>1.0-SNAPSHOT</version>
最终的文件名:groupId.split["-"]/artifactId/version/[artifactId-version].jar
如果在构建时在pom.xml中指定最终的名称:
<build>
<finalName>test</finalName>
</build>
虽然package生成的jar包是test.jar,但是install在本地仓库中的jar包还是原来的名称
test
test生命周期就是进行[[015-强化#单元测试|单元测试]]
test生命周期会自动运行test目录下符合规范的单元测试,也就是测试类名、测试方法名符合规范的方法。
如果想限制单元测试只能写在test目录下,可以将junit的socpe设置为test。
私服
私服是一种特殊的远程仓库,是架设在局域网内的仓库服务,用来代理位于外部的中央仓库,解决团队内部的资源共享和资源同步问题。
依赖查找顺序:
- 本地仓库
- 私服
- 中央仓库
资源上传与下载
上传资源需要指定私服的url和私服的用户名/密码,从私服下载资源需要指定连接私服的地址
根据项目版本上传到不同的仓库中:
- RELEASE 发行版本:功能趋于稳定,停止当前更新,可用于发行的版本,存储在私服中的RELEASE仓库中
- SNAPSHOT 快照版本:功能不稳定,尚处于开发中的版本,即快照版本,存储在私服的SNAPSHOT仓库中
- 设置上传的用户名和密码
- 设置pom文件中上传/发布的地址:
- 设置私服依赖下载的仓库组地址(settings.xml中的mirrors、profiles中配置)
默认不能使用SNAPSHOT仓库中的jar包,需要额外设置:
标签:INFO,maven,依赖,工程,tlias,jar,Maven From: https://www.cnblogs.com/euneirophran/p/18073918