前言
对于复杂庞大的项目,maven的熟练使用可以大大提高工作效率
分模块开发
开发的模块可以独立出来,作为一个资源,当需要使用时可以通过依赖的形式来引用
1.1 分模块开发理念
将原始模块按照功能拆分成若干个子模块,方便模块间的相互调用,接口共享。这样的话,项目中的每一层都可以单独维护,也可以很方便的被别人使用
1.按照功能拆分
为了避免项目中某一个模块代码出现问题,导致整个项目无法正常启动,我们会按照功能将项目进行拆分
2.按照模块拆分
为了提高代码复用性
可以将公共的部分抽取成一个独立的模块,其他模块要想使用可以像添加第三方jar包依赖一样来使用我们自己抽取的模块,这样就解决了代码重复的问题(比如订单用户)
1.2 分模块开发实现
建立依赖关系
在maven01
项目的pom.xml添加maven03
的依赖
<dependency>
<groupId>ppgoodlike.yu7daily</groupId>
<artifactId>maven03</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
在IDEA中是有maven03
这个项目,所以我们只需要将maven03
项目安装到本地仓库即可,将需要被依赖的项目maven03
,使用maven的install命令,把其安装到Maven的本地仓库中。否则会出现编译错误!
2.依赖管理
2.1 依赖传递与冲突问题
(1) A依赖了B和C,B和C有分别依赖了其他jar包,所以在A项目中就可以使用上面所有jar包,这就是所谓的依赖传递
(2) 依赖传递有直接依赖和间接依赖
直接依赖:在当前项目中通过依赖配置建立的依赖关系
间接依赖:被资源的资源如果依赖其他资源,当前项目间接依赖其他资源
- 相对于A来说,A直接依赖B和C,间接依赖了D1,E1,G,F,D2和E2
- 相对于B来说,B直接依赖了D1和E1,间接依赖了G
- 直接依赖和间接依赖是一个相对的概念
(3)因为有依赖传递的存在,就会导致jar包在依赖的过程中出现冲突问题,具体什么是冲突?Maven是如何解决冲突的?
这里所说的依赖冲突是指项目依赖的某一个jar包,有多个不同的版本,因而造成类包版本冲突。
情况一: 在maven01
的pom.xml中添加两个不同版本的Junit依赖:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
特殊优先:当同级配置了相同资源的不同版本,后配置的覆盖先配置的。
情况二:
路径优先:当依赖中出现相同的资源时,层级越深,优先级越低,层级越浅,优先级越高
- A通过B间接依赖到E1
- A通过C间接依赖到E2
- A就会间接依赖到E1和E2,Maven会按照层级来选择,E1是2度,E2是3度,所以最终会选择E1
情况三:
声明优先:当资源在相同层级被依赖时,配置顺序靠前的覆盖配置顺序靠后的
- A通过B间接依赖到D1
- A通过C间接依赖到D2
- D1和D2都是两度,这个时候就不能按照层级来选择,需要按照声明来,谁先声明用谁,也就是说B在C之前声明,这个时候使用的是D1,反之则为D2
2.2 可选依赖和排除依赖
为了解决依赖的版本冲突问题,通常可以隐藏对外的资源关系
方案一:可选依赖
- 可选依赖指对外隐藏当前所依赖的资源---不透明
在maven04
的pom.xml,在引入maven03
的时候,添加optional
<dependency>
<groupId>ppgoodlike.yu7daily</groupId>
<artifactId>maven03</artifactId>
<version>1.0-SNAPSHOT</version>
<!--可选依赖是隐藏当前工程所依赖的资源,隐藏后对应资源将不具有依赖传递-->
<optional>true</optional>
</dependency>
方案二:排除依赖
- 排除依赖指主动断开依赖的资源,被排除的资源无需指定版本---不需要
前面我们已经通过可选依赖实现了阻断maven03的依赖传递,对于排除依赖,则指的是已经有依赖的事实,也就是说maven01项目中已经通过依赖传递用到了maven03,此时我们需要做的是将其进行排除,所以接下来需要修改maven01的pom.xml
<dependency>
<groupId>ppgoodlike.yu7daily</groupId>
<artifactId>maven04</artifactId>
<version>1.0-SNAPSHOT</version>
<!--排除依赖是隐藏当前资源对应的依赖关系-->
<exclusions>
<exclusion>
<groupId>ppgoodlike.yu7daily</groupId>
<artifactId>maven03</artifactId>
</exclusion>
</exclusions>
</dependency>
A依赖B,B依赖C
,C
通过依赖传递会被A
使用到,现在要想办法让A
不去依赖C
- 可选依赖是在B上设置
<optional>
,A
不知道有C
的存在, - 排除依赖是在A上设置
<exclusions>
,A
知道有C
的存在,主动将其排除掉。
3.聚合和继承
3.1 聚合
1.所谓聚合:将多个模块组织成一个整体,同时进行项目构建的过程称为聚合
2.聚合工程:**通常是一个不具有业务功能的"空"工程(有且仅有一个pom文件)
使用聚合工程可以将多个工程编组,通过对聚合工程进行构建,实现对所包含的模块进行同步构建**
当工程中某个模块发生更新(变更)时,必须保障工程中与已更新模块关联的模块同步更新,此时可以使用聚合工程来解决批量模块同步构建的问题。
聚合具体的实现步骤为:
<?xml version="1.0" encoding="UTF-8"?>
<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>
<groupId>ppgoodlike.yu7daily</groupId>
<artifactId>maven01</artifactId>
<version>1.0-RELEASE</version>
<packaging>pom</packaging>
<!--设置管理的模块名称-->
<modules>
<module>../maven01</module>
<module>../maven03</module>
<module>../maven04</module>
</modules>
</project>
测试发现,当maven01
的compile
被点击后,所有被其管理的项目都会被执行编译操作。这就是聚合工程的作用。
聚合工程管理的项目在进行运行的时候,会按照项目与项目之间的依赖关系来自动决定执行的顺序和配置的顺序无关。
最后总结一句话就是,聚合工程主要是用来管理项目。
3.2 继承
所谓继承:描述的是两个工程间的关系,与java中的继承相似,子工程可以继承父工程中的配置信息,常见于依赖关系的继承
将所有项目公共的jar包依赖提取到父工程的pom.xml中,子项目就可以不用重复编写,简化开发
将所有项目的jar包配置到父工程的dependencyManagement标签下,实现版本管理,方便维护
注:dependencyManagement标签不真正引入jar包,只是管理jar包的版本,子项目在引入的时候,只需要指定groupId和artifactId,不需要加version
注:当dependencyManagement标签中jar包版本发生变化,所有子项目中有用到该jar包的地方对应的版本会自动随之更新
最后总结一句话就是,父工程主要是用来快速配置依赖jar包和管理项目中所使用的资源。
实现步骤:
1.创建Maven模块,设置打包类型为pom
<packaging>pom</packaging>
2.在父工程的pom文件中配置依赖关系(子工程将沿用父工程中的依赖关系),一般只抽取子项目中公有的jar包
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
...
</dependencies>
3.在父工程中配置子工程中可选的依赖关系
<dependencyManagement>
<dependencies>
<dependency>
<groupId>ppgoodlike.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
</dependencies>
...
</dependencyManagement>
4.在子工程中配置当前工程所继承的父工程
<!--定义该工程的父工程-->
<parent>
<groupId>ppgoodlike.yu7daily</groupId>
<artifactId>maven01</artifactId>
<version>1.0-RELEASE</version>
<!--填写父工程的pom文件,可以不写-->
<relativePath>../maven01/pom.xml</relativePath>
</parent>
5.在子工程中配置使用父工程中可选依赖的坐标
<dependencies>
<dependency>
<groupId>ppgoodlike.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
</dependencies>
注意事项:
1.子工程中使用父工程中的可选依赖时,仅需要提供群组id和项目id,无需提供版本,版本由父工程统一提供,避免版本冲突
2.子工程中还可以定义父工程中没有定义的依赖关系,只不过不能被父工程进行版本统一管理。
3.3 聚合VS继承
两种之间的作用:
- 聚合用于快速构建项目,对项目进行管理
- 继承用于快速配置和管理子项目中所使用jar包的版本
聚合和继承的相同点:
- 聚合与继承的pom.xml文件打包方式均为pom,可以将两种关系制作到同一个pom文件中
- 聚合与继承均属于设计型模块,并无实际的模块内容
聚合和继承的不同点:
- 聚合是在当前模块中配置关系,聚合可以感知到参与聚合的模块有哪些
- 继承是在子模块中配置关系,父模块无法感知哪些子模块继承了自己
4.属性
为了解决更新多个jar包的版本,而出现漏改导致程序出问题,可以声明一个变量,在其他地方使用该变量,当变量的值发生变化后,所有使用变量的地方,就会跟着修改,以spring、junit、mybatis-spring为例
4.1定义父工程属性
<properties>
<spring.version>5.2.10.RELEASE</spring.version>
<junit.version>4.12</junit.version>
<mybatis-spring.version>1.3.0</mybatis-spring.version>
</properties>
4.2修改依赖的version
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
5.配置文件加载属性
为了让maven管理范围更大,我们可以在父工程中定义属性通过配置文件引用的方式来完成配置
5.1父工程定义属性
<properties>
<jdbc.url>jdbc:mysql://127.1.1.1:3306/ssm_db</jdbc.url>
</properties>
5.2jdbc.properties文件中引用属性
在jdbc.properties,将jdbc.url的值直接获取Maven配置的属性
jdbc.driver=ppgoodlike.mysql.jdbc.Driver
jdbc.url=${jdbc.url}
jdbc.username=root
jdbc.password=284650
5.3设置maven过滤文件范围
Maven在默认情况下是从当前项目的src\main\resources
下读取文件进行打包。现在我们需要打包的资源文件是在maven01下,需要我们通过配置来指定下具体的资源目录
<build>
<resources>
<!--设置资源目录-->
<resource>
<directory>../maven01/src/main/resources</directory>
<!--设置能够解析${},默认是false -->
<filtering>true</filtering>
</resource>
</resources>
</build>
directory路径前要添加../
的原因是maven01相对于父工程的pom.xml路径是在其上一层的目录中,所以需要添加。