Maven

基本概念

仓库

用于存储资源,包含各种jar包
分类:
本地仓库:自己电脑上存储资源的仓库,连接远程仓库获取资源
远程仓库:非本机电脑上的仓库,为本地仓库提供资源,分为中央仓库和私服
中央仓库: Maven团队维护,存储所有资源的仓库
私服:部门/公司范围内存储资源的仓库,从中央仓库获取资源
私服的作用:
保存具有版权的资源,包含购买或自主研发的jar
中央仓库中的jar都是开源的,不能存储具有版权的资源
一定范围内共享资源,仅对内部开放,不对外共享

坐标

Maven中的坐标用于描述仓库中资源的位置
Maven坐标主要组成:
groupld:定义当前Maven项目隶属组织名称(通常是域名反写,例如: org.mybatis)
artifactld:定义当前Maven项目名称(通常是模块名称,例如CRM、SMS)
version:定义当前项目版本号
(packaging:定义该项目的打包方式)
Maven坐标的作用:
使用唯一标识,唯一性定位资源位置,通过该标识可以将资源的识别与下载工作交由机器完成

仓库配置

在maven的下载路径下有一个setting文件,可以更改一些基础设置,比如本地仓库的存储位置,以及配置阿里镜像仓库,即从阿里的仓库中获取资源而非中央仓库,这样快一点

Maven的工程目录结构

图片损坏

大概了解一下,现在一般是在idea中直接创建maven工程或spring工程

依赖管理

依赖配置

依赖是指当前项目运行所需的jar,一个项目可以设置多个依赖,这些依赖一般来自于中心仓库(私服),是前人或同事写好的jar包或工具类
图片损坏

依赖传递

在引入一个新的jar包时,这个jar包可能依赖其它的jar包,在导入这个jar包时,会将它的所有依赖也一起导入,这就是依赖的传递性
直接依赖:在当前项目中通过依赖配置建立的依赖关系
间接依赖:被依赖的资源如果依赖其它资源,当前项目间接依赖其它资源
这有时会导致依赖传递冲突问题,也就是可能不同级的依赖相同但版本号不同,应遵守以下原则:
路径优先:当依赖中出现相同的资源时,层级越深,优先级越低,层级越浅,优先级越高
声明优先:当资源在相同层级被依赖时,配置顺序靠前的覆盖配置顺序靠后的
特殊优先:当同级配置了相同资源的不同版本,后配置的覆盖先配置的

可选依赖

可选依赖指对外隐藏当前所依赖的资源(但仍在使用)

1
2
3
4
5
6
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<optional>true</optional>
</dependency>

排除依赖

排除依赖指不再使用当前所指的资源

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<exalusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>

依赖范围

依赖的jar默认情况可以在任何地方使用,可以通过scope标签设定其作用范围
作用范围:
主程序范围有效(main文件夹范围内)
测试程序范围有效(test文件夹范围内)
是否参与打包(package指令范围内)
图片损坏

循环依赖

  1. 优化模块设计: 首先,考虑你的模块设计是否合理。循环依赖通常是模块之间划分不清晰所导致的。尽量遵循单一职责原则,将模块按照功能分割,减少模块之间的直接依赖。
  2. 拆分和合并模块: 如果发现存在循环依赖,考虑将其中一个或多个模块进行拆分或合并,以消除循环依赖。有时,将功能合并到一个模块中,或者将一些共享的功能抽离成一个独立的模块,可以帮助解决循环依赖问题。
  3. 使用接口和抽象: 如果模块之间需要互相调用,尽量通过接口或抽象类来定义依赖关系,而不是直接依赖具体实现。这可以减少循环依赖的风险。
  4. Maven 中的 <dependencyManagement>: 如果循环依赖是由于版本问题引起的,可以使用 Maven 的 <dependencyManagement> 部分来集中管理依赖的版本,以确保一致性。
  5. 提取接口模块: 为了解决循环依赖,你可以创建一个独立的接口模块,其中定义了所有模块之间的接口。然后各个模块可以依赖于这个接口模块,而不会产生循环依赖。
  6. 调整模块依赖关系: 在 <dependencies> 部分中,可以明确声明模块的依赖关系和作用域,以便更好地控制依赖。
  7. 检查插件和目标: 有时,循环依赖可能是由于插件的配置或目标的执行引起的。检查是否有插件或目标的配置引发了循环依赖。
  8. 使用模块路径: 如果使用 Java 9 及更高版本,可以尝试使用模块路径来隔离模块,避免循环依赖。
  9. 重新考虑项目结构: 如果循环依赖问题无法通过上述方法解决,可能需要重新审视项目结构和模块之间的关系,进行更大范围的重构。

生命周期与插件

生命周期

生命周期指maven对项目的阶段的管理,一般分为三类:
clean:清理工作
default:核心工作,例如编译,测试,打包,部署等
site:产生报告,发布站点等
在执行某个生命周期时,会默认将这个生命周期前的所有生命周期全部执行完成,除非指定不执行某个生命周期

插件

插件与生命周期内的阶段绑定,在执行到对应生命周期时执行对应的插件功能
内置插件:默认maven在各个生命周期上绑定有预设的功能
自定义插件:通过插件可以自定义其他功能,如果内置插件无法满足特定需求,可以创建自定义插件。自定义插件通常使用 Java 编写,通过继承 Maven 插件框架来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<build>
<plugins>
<plugin>
<groupId>com.example</groupId> <!-- 插件的 Group ID -->
<artifactId>my-custom-plugin</artifactId> <!-- 插件的 Artifact ID -->
<version>1.0.0</version> <!-- 插件的版本 -->
<executions>
<execution>
<goals>
<goal>custom-goal</goal> <!-- 自定义插件的目标(Goal) -->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

idea中执行的生命周期:

  1. clean: 清理项目构建生成的目录和文件,包括 target 目录。
  2. compile:编译项目的源代码,生成字节码文件。
  3. test: 运行项目的单元测试。
  4. package: 将编译后的代码打包成可分发的格式,如 JAR、WAR 或 EAR。
  5. install:将项目构建结果安装到本地 Maven 仓库,以供其他项目引用。
  6. deploy: 将构建结果部署到远程 Maven 仓库,以便其他项目或团队访问。
  7. site: 生成项目的站点文档和报告,如代码覆盖率、测试报告等。

分模块开发

分模块开发思想是将一个大型应用程序分解为更小、更易管理的模块,每个模块负责不同的功能或组件。每个模块都可以独立开发、测试和部署。如在web编程中,将实体类pojo,业务层service,数据层dao,控制层controller都分别设置为一个独立的模块
这种方式有许多好处:

  1. 模块化:将应用程序分为模块使得代码更加模块化和组织有序,容易理解和维护。
  2. 独立开发:开发人员可以专注于自己负责的模块,而不必关心整个应用程序。
  3. 并行开发:不同模块可以并行开发,提高了开发效率。
  4. 重用性:可以更轻松地将模块复用在其他项目中,从而提高了代码的重用性。
  5. 测试:每个模块都可以独立测试,减少了单一应用程序中的复杂度。
  6. 扩展性:添加新功能时,可以更容易地将新模块集成到现有应用程序中。

模块聚合

模块聚合是将分开开发的模块汇总在一起,形成一个完整的应用程序。通常情况下,会有一个父级 POM(Project Object Model),其中包含所有模块的定义和依赖关系。父级 POM 也可以定义构建的顺序和版本控制策略。对父级模块进行操作时,所有子模块也会进行相同的操作
图片损坏

依赖继承

在父工程中定义依赖管理,在子工程中定义依赖关系,无需声明依赖版本,版本参照父工程中依赖的版本

1
2
3
4
5
6
7
8
9
10
11
12
<! --声明此处进行依赖管理-->
<dependencyManagement>
<!--具体的依赖-->
<dependencies>
<!--spring环境-->
<dependency>
<groupId>org. springframework</ groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependencies>
<dependencyManagement>

继承与聚合对比

作用
聚合用于快速构建项目
继承用于快速配置
相同点:
聚合与继承的pom.xml文件打包方式均为pom,可以将两种关系制作到同一个pom文件中
聚合与继承均属于设计型模块,并无实际的模块内容
不同点:
聚合是在当前模块中配置关系,聚合可以感知到参与聚合的模块有哪些
继承是在子模块中配置关系,父模块无法感知哪些子模块继承了自己

属性

在pom文件中可以通过property标签自定义属性,相当于define,之后用到时就可以用#{属性名}直接引用,修改属性中的值就可以同时修改所有引用处的值
属性分为自定义属性,内置属性,setting属性,java系统属性,环境变量属性
图片损坏

版本管理

工程版本
SNAPSHOT(快照版本)
项目开发过程中,为方便团队成员合作,解决模块间相互依赖和时时更新的问题,开发者对每个模块进行构建的时候,输出的临时性版本叫快照版本((测试阶段版本),快照版本会随着开发的进展不断更新
RELEASE(发布版本)
项目开发到进入阶段里程碑后,向团队外部发布较为稳定的版本,这种版本所对应的构件文件是稳定的,即便进行功能的后续开发,也不会改变当前发布版本内容,这种版本称为发布版本

工程版本号约定
约定规范:

  1. <主版本>.<次版本>,<增量版本><里程碑版本>
  2. 主版本:表示项目重大架构的变更,如: spring5相较于spring4的迭代
  3. 次版本:表示有较大的功能增加和变化,或者全面系统地修复漏洞
  4. 增量版本:表示有重大漏洞的修复
  5. 里程碑版本:表明一个版本的里程碑(版本内部)。这样的版本同下一个正式版本相比,相对来说不是很稳定,有待更多的测试
    范例: 5.1.9.RELEASE

资源加载属性值

如果想任意配置文件中加载pom文件中定义的属性,可以在配置文件中使用 ${属性名}来调用,同时,需要在pom文件中配置开启此方式,反则编译时无法获取到属性值

1
2
3
4
5
6
7
8
9
<!--配置资源文件对应的信息-->
<resources>
<resource>
<!-设定配置文件对应的位置目录,支持使用属性动态设定路径-->
<directory>${project.basedir}/src/main/resources</directory>
<!--开启对配置文件的资源加载过滤-->
<filtering>true</filtering>
</ resource>
<resources>

跳过测试

  1. 使用命令跳过测试(执行的指令生命周期必须包含测试环节)
1
mvn 某个指令 -D skipTests
  1. 使用界面操作跳过测试
    图片损坏
  2. 使用配置跳过测试(还可以包含或排除某些测试用例)
1
2
3
4
5
6
7
8
9
10
11
12
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<skipTests>true</skipTests><!--设置跳过测试-->
<includes> <!--包含指定的测试用例-->
<inalude>**/User*Test.java</include>
</includes>
<excludes><!--排除指定的测试用例-->
<exclude>**/User*Testcase.java</exclude>
</excludes>
</configuration></plugin>