如何在IDEA搭建一个微服务项目
最近在写微服务,在搭建微服务的时候,还是碰壁了许多,所以专门写一篇文章来总结一下相关内容
微服务就是将单个应用程序开发为一组小服务的方法,每个小服务都在自己的进程中运行并与轻量级机制(通常是HTTP资源API)进行通信。
搭建根目录
所以我们还是要建立 Spring Boot 的项目,根项目拿 Maven 搭建也可以
下一步什么依赖也不选择,因为本质上,我们需要的根项目其实是空的
新建的根项目中会有许多的内容,我们要删除一些保持项目目录整洁
这里拿我之前的来演示了
我们把除了 .idea目录,pom.xml 和 .gitignore 留着外,剩下的都删了,包括 src,删了后就是这样
这些文件和目录都是什么作用呢?在这里简单说一下作用以及为什么能删,为什么不能删
.idea 目录
- 作用:这是 IntelliJ IDEA 集成开发环境(IDE)生成的目录,用于存储项目的配置信息,比如代码格式化设置、项目结构、历史记录、插件配置等,是 IDE 为了更好地管理项目而创建的。
- 能否删除:可以删除。但删除后,IDEA
之前对该项目的个性化配置(如自定义的代码样式、断点等)会丢失,下次打开项目时
IDEA 会重新生成一个默认配置的
.idea目录。不过如果是团队协作或需要保留 IDE 配置,一般不建议删除。
.mvn 目录
- 作用:包含 Maven Wrapper(Maven
包装器)的相关文件。Maven Wrapper 可以让项目在没有安装 Maven
或者使用特定版本 Maven 的情况下,也能通过
mvnw(Unix/Linux 系统)或mvnw.cmd(Windows 系统)脚本执行 Maven 命令,保证项目使用统一的 Maven 版本。 - 能否删除:可以删除。但删除后,就无法使用 Maven Wrapper 功能了,需要确保本地安装了合适版本的 Maven 才能正常构建项目。如果项目本身不需要 Maven Wrapper 来统一 Maven 版本,删除是可行的。
src 目录
- 作用:是项目的源代码目录,用于存放 Java 源代码、资源文件(如配置文件、静态资源等)、测试代码等,是项目的核心代码所在位置。
- 能否删除:从项目功能角度,不能随意删除。因为项目的业务逻辑、代码实现都在
src目录下,删除后项目就失去了核心功能代码,无法正常编译和运行。不过如果是要重新组织项目代码结构,或者完全重建代码,在备份好代码的前提下可以删除后重新创建。
.gitattributes 文件
- 作用:用于在 Git 版本控制中,定义文件的属性以及 Git 对文件的处理方式,比如指定文件的换行符格式(防止不同操作系统下换行符不一致的问题)、合并策略等。
- 能否删除:可以删除。如果项目不使用 Git 进行版本控制,或者不需要对文件属性做特殊的 Git 处理,删除该文件不会影响项目本身的代码运行,只是会失去这些 Git 相关的自定义配置。
.gitignore 文件
- 作用:告诉 Git 版本控制系统,哪些文件或目录不需要被跟踪(即不会被提交到 Git 仓库中),通常用于忽略编译生成的临时文件、日志文件、IDE 配置文件等。
- 能否删除:可以删除。但删除后,Git 会跟踪所有文件,可能导致一些无关的文件(如编译产物、IDE 临时文件)被提交到仓库中,造成仓库臃肿。如果项目使用 Git 进行版本控制,一般建议保留该文件来规范版本控制的内容。
HELP.md 文件
- 作用:是一个帮助文档文件,通常用于简要说明项目的相关信息,比如如何构建、运行项目,项目的功能介绍等,属于文档类文件。
- 能否删除:可以删除。它不影响项目的代码编译和运行,只是删除后会失去这份项目帮助文档,对于项目本身功能没有实质影响。
mvnw 和 mvnw.cmd 文件
- 作用:
mvnw是 Unix/Linux 系统下的 Maven Wrapper 脚本,mvnw.cmd是 Windows 系统下的 Maven Wrapper 脚本。通过这些脚本,可以在没有安装 Maven 或者使用指定版本 Maven 的情况下,执行 Maven 命令(如编译、打包等)。 - 能否删除:可以删除。删除后就无法使用 Maven Wrapper
功能,需要依赖本地安装的 Maven 来构建项目,和删除
.mvn目录的影响类似。
pom.xml 文件
- 作用:是 Maven 项目的核心配置文件,用于定义项目的坐标(groupId、artifactId、version)、依赖(项目所需要的第三方库)、插件(如编译插件、打包插件等)、构建规则等,Maven 就是根据这个文件来管理项目的构建和依赖。
- 能否删除:不能删除。它是 Maven
项目的核心配置文件,没有
pom.xml,Maven 无法识别项目,也无法进行依赖管理和项目构建,项目无法正常编译和运行。
这里其实会有一个问题,就是如果你之前创立了项目,但是没整好,把这个删了重新建立一个同名的,你会发现你的 pom.xml 文件带有删除线一样的感觉,好像不能用了一样,这里其实是 Maven 把你的 pom 文件忽视了,在这里解除忽视,在下面建立模块的时候也一样
创建模块
那么微服务是一个单体程序拆成了很多的小模块,那么我们需要创建对应的模块
模块的创建和根目录没什么太大的差别,注意如果你要写代码就别把src删了
只不过我创建模块,如果模块下没有子模块,我会删到只剩下 src 和 pom.xml
那么模块之间涉及到链接和依赖了,这就要靠 pom.xml 实现了,我们要对此进行配置
来到根目录下的 pom 文件,我们先删到干净
然后首先,我们要先改
<parent>标签下的内容,把其改为 3.2.4
这个兼容性好的版本
1 | <parent> |
然后,添加打包方式为 pom,如果你是父模块,我都推荐写上
1 | <packaging>pom</packaging> |
然后,添加
<models>标签,在这里要写你根模块下的子模块<module>
<properties>中在这里集中管理你整个微服务项目中可能用到的依赖的版本,对依赖版本进行集中管理,例如我之前的项目就是这么写的
<dependencyManagement>接着给这个标签留出位置,在这里声明
“哪些依赖可以被使用”
以及它们的版本,不实际引入依赖,仅规定子模块使用这些依赖时的默认版本
一般情况下,我们写微服务是一定要对这些内容进行依赖版本管理的
1 | <dependencyManagement> |
之后,我们如果有特殊情况,会在根模块中也写<dependencies>,这里就是抽取所有子模块的公共依赖,按依赖树传递依赖,避免子模块重复声明都有的依赖,微服务我们一般写入bootstrap
1 | <!-- Spring Cloud Bootstrap 启动器 (配置中心支持) --> |
根模块的pom写成这样差不多就可以了,我们继续写子模块的
我一般会把子模块删成这样再继续编辑
首先子模块肯定是要继承父模块的
1 | <parent> |
结合父模块中的<modules>的添加,实际上,父子的依赖关系就形成了
如果你子模块需要引入依赖,在<dependencies>直接引入就可以,先不用写版本号,到父模块的依赖管理部分把依赖引进去,然后到父模块的<properties>声明一下版本,这样就是全项目通用了
微服务如何进行模块设计
那么,我们都知道,Maven 是不支持循环依赖的,也就是不能你在这里导入依赖,那个被导入的依赖也导入了你的依赖,这样是无法过编译的
在主流的大型微服务项目中,模块设计通常遵循单一职责原则、高内聚低耦合原则,以提高项目的可维护性、可扩展性和可复用性。
common模块
一般情况下,我们需要有一个 common 模块,common 模块中包含你需要的各个模块通用的、可被多个其他模块复用的代码和资源
common 模块中一般会设计一个 core 或者 basic 模块,存放最基本的各个模块通用的、可被多个其他模块复用的代码和资源,一般来说是各种工具类,常量,复用性强的注解等,这里放的最多的就是各种通用的工具方法,也在这里集中定义项目中使用的各种常量和项目中通用的异常类,也根据开发习惯把 DTO 和枚举类放在这里
common 模块下如果你用到了 redis ,一般会设计一个 common-redis 模块,用到 Spring Security 框架,一般会设计一个 common-security 模块,这里 common 模块下的设计一般会很细,因为这样才能避免重复使用
这个 common 模块的设计按照自己的需求来说,会很不一样,我们来看 ruoyi-cloud-plus 这个微服务开发框架是如何进行 common 模块的设计的
可以看到划分的非常细,来看看 common-core 模块中有什么内容都
Gateway模块
网关模块,用于管理和转发请求。
作为微服务系统的入口,负责请求的路由、过滤、认证、限流等功能。它可以统一处理跨域问题、鉴权问题,将请求转发到后端相应的业务服务模块。
这里如果你对网关有很高的设计需求,一般会继续进行这样的模块设计
gateways:网关模块,用于管理和转发请求。
- main-gateway:主网关模块,负责整个系统的流量管理。
- admins:管理员模块,提供管理员管理功能。
- admin:管理员信息管理功能。
- tenant:租户信息管理功能。
- fronts:前台模块,提供前端页面管理功能。
- tenant:租户前台页面管理功能。
- front:前台页面管理功能。
- apps:应用程序模块,提供特定功能的应用程序。
- db-app:数据库管理应用程序。
- tenant-app:租户管理应用程序。
当客户端发起一个请求时,首先到达网关,网关根据请求的路径将其路由到对应的业务服务,同时可以对请求进行权限验证,判断用户是否有权限访问该服务。
这个模块一般是必须有的,可能不会有多少代码,但是一定会进行高度的自定义
api模块
也就是包含各种API接口的模块。
api 模块的设计是先设计一个父模块,按照业务功能,再设计 xxxx-xxx-api 模块
在微服务模块设计中,api模块有着不可或缺的作用,虽然从技术上可以将其内容放到对应的业务功能模块中,但从项目的可维护性、可扩展性、协作性等多方面考量,独立的api模块更具优势
为什么要有 api 模块
- 明确服务边界与接口定义
api模块集中定义了微服务对外提供的接口,包括接口的方法签名、入参和返回值类型等信息。通过查看api模块,开发人员可以清晰地了解该微服务提供了哪些功能,明确服务的边界。例如,在一个用户管理微服务中,api模块会定义诸如User getUserById(Long id)、void updateUser(User user)等接口,直观地展示了用户管理服务能提供的操作。
- 服务解耦
- 在微服务架构中,各个服务之间需要相互调用。如果每个服务的接口都分散在业务功能模块中,那么调用方服务在引用时,会引入过多业务功能模块的依赖,导致服务之间耦合度增加。而
api模块只包含接口和必要的数据传输对象(DTO),调用方只需依赖api模块,就能获取到调用所需的接口信息,降低了服务间的耦合度。比如,订单服务要调用用户服务获取用户信息,只需要引入用户服务的api模块,而不需要了解用户服务具体的业务实现细节。
- 在微服务架构中,各个服务之间需要相互调用。如果每个服务的接口都分散在业务功能模块中,那么调用方服务在引用时,会引入过多业务功能模块的依赖,导致服务之间耦合度增加。而
- 方便版本管理
- 随着业务的发展,微服务的接口可能会发生变化,如新增接口、修改接口参数等。通过独立的
api模块,可以更方便地进行版本管理。可以在api模块中采用版本号命名空间、注解等方式来标识不同版本的接口,如v1版本的UserService接口和v2版本的UserService接口,调用方可以根据自身需求选择合适的版本进行依赖,同时也便于服务提供方对旧版本接口的兼容和废弃处理。
- 随着业务的发展,微服务的接口可能会发生变化,如新增接口、修改接口参数等。通过独立的
- 利于团队协作
- 在大型项目中,不同的开发团队可能负责不同的微服务。
api模块为团队之间的协作提供了清晰的契约。服务提供方专注于实现api模块中定义的接口功能,服务调用方根据api模块来编写调用逻辑,双方按照统一的接口标准进行开发,减少了沟通成本和因接口不一致导致的错误。
- 在大型项目中,不同的开发团队可能负责不同的微服务。
api模块的具体功能
- 首先就是接口定义:定义微服务对外暴露的业务接口,使用编程语言的接口或抽象类等形式来描述服务提供的功能。
- 定义 dto:设计用于在服务间传输数据的对象,将业务实体对象(Entity)中需要暴露给外部的数据进行封装,屏蔽业务实体的内部细节,同时也可以根据接口需求对数据进行转换和裁剪。比如
- 也偶尔会放异常,至少我不习惯
来示例看看 ruoyi-cloud-plus 是如何设计的
modules模块
我们来看看rouyi是如何设计这个模块的
可以看到这个模块是一个模块集合目录,下面的子模块各自承担特定的业务或系统功能。
也就是说,你真正处理业务的模块,就是都在这里按照你的业务进行划分
每个模块都当成一个单独的Spring Boot 的业务程序来写
注意给api模块留出需要调用的公共接口
auth模块
认证模块
这个模块不像其他模块那样,这个模块的工作非常固定
也就是如果你使用了 Spring Security 安全框架,那么相关认证逻辑的实现都在这里进行
visual模块
比较少的项目需要的到这个模块
主要是可视化相关模块,用于实现系统数据的可视化展示,比如通过图表等形式展示系统的运行状态、业务数据统计等,帮助用户更直观地了解系统和业务情况。







