最近准备跟伙伴合作开发一个OA系统,环境使用SpringBoot + maven,由于在此之前我们都是单兵作战,所以在项目开始前,打算率先解决这个问题。使用SpringBoot + Maven进行多模块配置
开始前,先了解一下maven的几个知识点。
- groupId:定义当前 Maven 项目隶属的实际项目,一个实际项目下会有多个 Maven 项目。如一家公司开发的产品,groupId 就是公司/个人域名,但会包括众多的 Maven 项目;
- artifactId:定义实际项目中的一个 Maven 项目,一般用实际项目名称作为 artifactId 的前缀;
- versioin:指定工程的版本,如 - 1.0 SNAPSHOT,SNAPSHOT 意为快照,说明在该项目还处于开发中;
- packaging:定义 Maven 项目的打包方式,有 JAR 、WAR 和 EAR 三种格式详情见:JAR,WAR,EAR区别
- dependencies:所有依赖在此范围添加,包含众多dependency
- parent:指定当前项目的父模块或者父工程,使用groupId,artifactId定位项目
- modules:在父模块中引用子模块,所有子模块均包含在里面
- module:表示一个子模块,使用相对路径
父模块包含子模块(包含)
在用maven管理项目中,可以在当前项目下构建一个子模块。(子模块使用maven构造的话默认继承父模块,若是使用Spring Initializr的话,则需要手动配置父模块)
- 建立一个父模块
在IDEA中建立一个SpringBoot项目,Group选择公司名字,Artifact选择项目名字。建立好之后,POM.xml大概会是一下的样子。
==值得注意的是==:要将packaging改为pom,因为所有的父模块中的packaging就是pom。
1 | <?xml version="1.0" encoding="UTF-8"?> |
由于使用SpringBoot,所以最顶层父项目就是spring-boot-starter-parent。逻辑上不影响项目分层。父项目建立了基本依赖。
- 建立子模块
- 右键点击父模块,New -> Module -> Maven
- 选择maven-archetype-webapp之后,默认继承父模块的GroupId,需要填写artifactId,此处可填写模块的作用。
- 一直点击Next,最后Finish,完成子模块构建
最后生成的pom.xml如下所示:
1 | <?xml version="1.0" encoding="UTF-8"?> |
这时父模块中将会添加
在我的测试项目中建立user,service,repository子模块,他们都继承父模块。又因为父模块继承SpringBoot模块,因此user,service,repository都继承SpringBoot模块,也就是说user,service,repository都是SpringBoot项目
假设A继承B模块,B继承C模块,那么A也将自动继承C模块。
1 | <modules> |
- 子模块A调用子模块B
概述:子模块A依赖子模块B,所以直接在子模块A上添加子模块B的依赖。
完成user,service,repository三个模块之后,每个模块都是独立的一个项目。此时假设user想要调用service模块中的方法,那将怎么做。
分析:user模块调用service模块可以表示为user模块依赖service模块。因此在此理解基础上,可以为user模块添加一个service模块依赖
1 | <dependency> |
这时就可以引入service中的方法了。
父工程与子工程同级(并列)
父工程与子工程同级的意思是,子工程不在父工程文件夹下,而是与父工程同一级文件夹。
- 建立父工程
使用Spring Initializr进行构建项目,步骤同上。建立好之后的pom.xml与上面一样。
- 建立子工程
子工程可以使用maven构建,也可以使用Spring Initializr构建,这两种方法无异。但是在pom.xml中都要使用
1 | <!--为子工程指明父工程--> |
此时在maven里的逻辑上已经指明他的父工程,若想使用父工程,则添加父工程依赖
1 | <!--在子工程添加父工程的依赖--> |
目前,测试时建立两个子工程:TestAdmin和TestUser。他们两个都与父工程TestMaven同级,因此在TestMaven中聚合这两个子工程。使用
1 | <!--在父工程TestMaven--> |
- 配置入口类
由于maven中继承是子工程继承自父工程,而父工程聚合子工程,所以子工程可以添加父工程的依赖,而父工程不能添加子工程依赖,就像儿子可以依赖父亲,父亲却很少依赖儿子一样。
假设入口类在子工程A
子工程A默认引用了父工程的依赖,而没有引用子工程B的依赖,因此当启动叻在子工程A中的启动类时,Spring将扫描子工程A和父工程,而不会扫描子工程B,原因就是没有在子工程A中引入子工程B的依赖。
子工程A没理由也没必要引用子工程B,就像A独立开发A模块,B独立开发B模块,最后必须得将A模块依赖B模块,这样功劳岂不都是B的了,因此这样做在逻辑上说不通。
假设入口类在子工程B
同上
假设入口类在父工程
当入口类在父工程时,在逻辑上说的过去了,因为子工程A,子工程B本来就是从父工程中分离出来的,最后终究要回到父工程,因此由父工程作为启动类位置较为合适。
但是!!!!!假若入口类直接放在父工程中的src - main - java - com - maven - test的包里,由于父工程不能引用子工程AB,因此启动时,将不会扫描子工程AB,貌似情况比之前还要糟糕了。
仔细想想,入口类放在父工程下是没错的,但是就是不能直接放在父工程的代码里,那如果是放在父工程的子模块呢?
试一下,在父工程下建立子模块在前面已经提到过,建立的子模块就是SpringBoot项目。因此将入口类放在子模块中,而在子模块中的pom.xml去引入TestAdmin, TestUser的依赖,好像这样子就可以运行起来了,因为子模块的pom.xml继承自父工程,因此可以直接添加依赖。
当项目运行起来时,可以看到,在父工程下建立子模块,将这个子模块作为整个项目的入口启动类,这样是可以行得通的。