分模块设计与开发
所谓分模块设计,顾名思义指的就是我们在设计一个 Java 项目的时候,将一个 Java 项目拆分成多个模块进行开发。
- 不采用分模块设计可能产生的问题:
- 不方便项目的维护和管理;
- 项目中的通用组件难以复用。
- 采用分模块设计的便利:
- 将项目按照功能/结构拆分成若干个子模块,方便项目的管理维护、拓展;
- 也方便模块间的相互调用、资源共享。
分析
以tlias 智能学习辅助系统为例,在这个项目中,除了我们所开发的部门管理以及员工管理、登录认证等相关业务功能以外,我们是不是也定义了一些实体类,也就是pojo包下存放的一些类,像分页结果的封装类PageBean、 统一响应结果Result,我们还定义了一些通用的工具类,像Jwts、阿里云OSS操作的工具类等等。
如果在当前公司的其他项目组当中,也想使用我们所封装的这些公共的组件,该怎么办?
- 方案一:直接依赖我们当前项目 tlias-web-management ,但是存在两大缺点:
- 这个项目当中包含所有的业务功能代码,而想共享的资源,仅仅是pojo下的实体类,以及 utils 下的工具类。如果全部都依赖进来,项目在启动时将会把所有的类都加载进来,会影响性能。
- 如果直接把这个项目都依赖进来了,那也就意味着我们所有的业务代码都对外公开了,这个是非常不安全的。
- 方案二:分模块设计
- 将 pojo 包下的实体类,抽取到一个 maven 模块中 tlias-pojo
- 将 utils 包下的工具类,抽取到一个maven模块中 tlias-utils
- 其他的业务代码,放在 tlias-web-management 这个模块中,在该模块中需要用到实体类 pojo、工具类 utils,直接引入对应的依赖即可。
注意:分模块开发需要先针对模块功能进行设计,再进行编码。不会先将工程开发完毕,然后进行拆分。
PS:当前我们是为了演示分模块开发,所以是基于我们前面开发的案例项目进行拆分的,实际中都是分模块设计,然后再开发的。
总结
- 什么是分模块设计?
- 将项目按照功能拆分成若干个子模块。
- 为什么要分模块设计
- 方便项目的管理维护、扩展,也方便模块间的相互调用,资源共享
- 注意事项:
- 分模块设计需要先针对模块功能进行设计,再进行编码。不会先将工程开发完毕,然后进行拆分。
继承与聚合
问题引入:在案例项目分模块开发之后啊,我们会看到tlias-pojo、tlias-utils、tlias-webmanagement中都引入了一个依赖 lombok 的依赖。我们在三个模块中分别配置了一次。
分析:如果是做一个大型的项目,这三个模块当中重复的依赖可能会很多很多。如果每一个 Maven 模块里面,我们都来单独的配置一次,功能虽然能实现,但是配置是比较繁琐的。
解决办法:我们可以再创建一个父工程 tlias-parent ,然后让上述的三个模块 tlias-pojo、tlias-utils、tlias-web-management 都来继承这个父工程 。 然后再将各个模块中都共有的依赖,都提取到父工程 tlias-parent中进行配置,只要子工程继承了父工程,依赖它也会继承下来,这样就无需在各个子工程中进行配置了
### 继承- 概念:继承描述的是两个工程间的关系,与java中的继承相似,子工程可以继承父工程中的配置信息,常见于依赖关系的继承。
- 作用:简化依赖配置、统一管理依赖
- 实现代码:
<parent>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<relativePath>....</relativePath>
</parent>
-
实现办法:
- 首先创建一个父工程
- 然后再基于父工程创建子工程
- 最后对于重复的项目依赖统一交给父工程进行管理(pom.xml)
- 注意:父工程一般不进行编写代码,可将父工程的 src 文件夹删除。
- 具体的创建过程可参见 资料中Maven高级部分…
-
Tip:Maven打包方式:
- jar:普通模块打包,springboot项目基本都是jar包(内嵌tomcat运行)
- war:普通web程序打包,需要部署在外部的tomcat服务器中运行
- pom:父工程或聚合工程,该模块不写代码,仅进行依赖管理
版本锁定
问题引入:如果项目中各个模块中公共的这部分依赖,我们可以直接定义在父工程中,从而简化子工程的配置。 然而在项目开发中,还有一部分依赖,并不是各个模块都共有的,可能只是其中的一小部分模块中使用到了这个依赖。简而言之就是:对于非通用的依赖如何进行管理?
可能出现的问题:如果项目拆分的模块比较多,每一次更换版本,我们都得找到这个项目中的每一个模块,一个一个的更改。 很容易就会出现,遗漏掉一个模块,忘记更换版本的情况。
解决办法:Maven的版本锁定功能。
- 在maven中,可以在父工程的pom文件中通过 <dependencyManagement> 来统一管理依赖版本。
- 父工程:
<!--统一管理依赖版本-->
<dependencyManagement>
<dependencies>
<!--JWT令牌-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
</dependencies>
</dependencyManagement>
- 子工程:
<dependencies>
<!--JWT令牌-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
</dependencies>
-
注意:
- 在父工程中所配置的 <dependencyManagement> 只能统一管理依赖版本,并不会将这个依赖直接引入进来。 这点和 <dependencies> 是不同的。
- 子工程要使用这个依赖,还是需要引入的,只是此时就无需指定 <version> 版本号了,父工程统一管理。变更依赖版本,只需在父工程中统一变更。
-
我们也可以通过自定义属性及属性引用的形式,在父工程中将依赖的版本号进行集中管理维护。 具体语法为:
- 自定义属性
<properties>
<lombok.version>1.18.24</lombok.version>
</properties>
- 引用属性
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
- 面试题: <dependencyManagement> 与 <dependencies> 的区别是什么?
- <dependencies> 是直接依赖,在父工程配置了依赖,子工程会直接继承下来。
- <dependencyManagement> 是统一管理依赖版本,不会直接依赖,还需要在子工程中引入所需依赖(无需指定版本)
聚合
问题引入:分模块设计与开发之后,我们的项目被拆分为多个模块,而模块之间的关系,错综复杂,各模块间可能有多重依赖。
![[image-20230113151533948.png]]那此时,我们要想将 tlias-web-management 模块打包,是比较繁琐的。因为在进行项目打包时,maven 会从本地仓库中来查找 tlias-parent 父工程,以及它所依赖的模块,而本地仓库目前是没有这几个依赖的。所以,我们在打包tlias-web-management 模块前,需要将 tlias-parent、tlias-pojo、tlias-utils 分别执行install生命周期安装到maven的本地仓库,然后再针对于 tlias-web-management 模块执行package进行打包操作。
出现的问题:如果开发一个大型项目,拆分的模块很多,模块之间的依赖关系错综复杂,那此时要进行项目的打包、安装操作,是非常繁琐的。
解决办法:maven的聚合就是来解决这个问题的,通过maven的聚合就可以轻松实现项目的一键构建(清理、编译、测试、打包、安装等)。
介绍
- 聚合:将多个模块组织成一个整体,同时进行项目的构建。
- 聚合工程:一个不具有业务功能的“空”工程(有且仅有一个pom文件),一般来说,继承关系中的父工程与聚合关系中的聚合工程是同一个。
- 作用:快速构建项目(无需根据依赖关系手动构建,直接在聚合工程上构建即可)
实现
- 在maven中,我们可以在聚合工程中通过 <moudules> 设置当前聚合工程所包含的子模块的名称。我们可以在 tlias-parent中,添加如下配置,来指定当前聚合工程,需要聚合的模块:
<!--聚合其他模块-->
<modules>
<module>../tlias-pojo</module>
<module>../tlias-utils</module>
<module>../tlias-web-management</module>
</modules>
- 此时,我们要进行编译、打包、安装操作,就无需在每一个模块上操作了。只需要在聚合工程上,统一进行操作就可以了。
私服
场景
在介绍什么是私服之前,我们先来分析一下同一个公司,两个项目组之间如何基于私服进行资源的共享。
假设现在有两个团队,A 和 B。 A 开发了一个模块 tlias-utils,模块开发完毕之后,将模块打成jar包,并安装到了A的本地仓库。
那此时,该公司的B团队开发项目时,要想使用 tlias-utils 中提供的工具类,该怎么办呢? 对于maven项目来说,是不是在pom.xml文件中引入 tlias-utils的坐标就可以了呢?
大家可以思考一下,当B团队在maven项目的pom.xml配置文件中引入了依赖的坐标之后,maven是如何查找这个依赖的? 查找顺序为:
- 本地仓库:本地仓库中是没有这个依赖jar包的。
- 远程中央仓库:由于该模块时自己公司开发的,远程仓库中也没有这个依赖。
因为目前tlias-utils这个依赖,还在A的本地仓库中的。 B电脑上的maven项目,是不可能找得到A电脑上maven本地仓库的jar包的。 那此时,大家可能会有一个想法:因为A和B都会连接中央仓库,我们可以将A本地仓库的jar包,直接上传到中央仓库,然后B从中央仓库中下载tlias-utils这个依赖。
这个想法很美好,但是现实很残酷。这个方案是行不通的,因为中央仓库全球只有一个,不是什么人都可以往中央仓库中来上传jar包的,我们是没有权限操作的。
那此时,maven的私服就出场了,私服其实就是架设在公司局域网内部的一台服务器,就是一种特殊的远程仓库。
有了私服之后,各个团队就可以直接来连接私服了。 A 连接上私服之后,他就可以把jar包直接上传到私服当中。我公司自己内部搭建的服务器,我是不是有权限操作呀,把jar包上传到私服之后,我让 B 团队的所有开发人员也连接同一台私服。连接上这一台私服之后,他就会根据坐标的信息,直接从私服当中将对应的jar包下载到自己的本地仓库,这样就可以使用到依赖当中所提供的一些工具类了。这样我们就可以通过私服来完成资源的共享。
而如果我们在项目中需要使用其他第三方提供的依赖,如果本地仓库没有,也会自动连接私服下载,如果私服没有,私服此时会自动连接中央仓库,去中央仓库中下载依赖,然后将下载的依赖存储在私服仓库及本地仓库中。
介绍
- 私服:是一种特殊的远程仓库,它是架设在局域网内的仓库服务,用来代理位于外部的中央仓库,用于解决团队内部的资源共享与资源同步问题。
- 依赖查找顺序:
- 本地仓库
- 私服仓库
- 中央仓库
- 注意事项:私服在企业项目开发中,一个项目/公司,只需要一台即可(无需我们自己搭建,会使用即可)。
资源上传与下载
- 资源上传与下载,我们需要做三步配置,执行一条指令。
- 第一步配置:在maven的配置文件中配置访问私服的用户名、密码。
- 第二步配置:在maven的配置文件中配置连接私服的地址(url地址)。
- 第三步配置:在项目的pom.xml文件中配置上传资源的位置(url地址)。
- 配置好了上述三步之后,要上传资源到私服仓库,就执行执行maven生命周期:deploy。
- 私服仓库说明:
- RELEASE:存储自己开发的RELEASE发布版本的资源。
- SNAPSHOT:存储自己开发的SNAPSHOT发布版本的资源。
- Central:存储的是从中央仓库下载下来的依赖。
- 项目版本说明:
- RELEASE(发布版本):功能趋于稳定、当前更新停止,可以用于发行的版本,存储在私服中的RELEASE仓库中。
- SNAPSHOT(快照版本):功能不稳定、尚处于开发中的版本,即快照版本,存储在私服的SNAPSHOT仓库中。