介绍
项目亮点
综合了多种项目的亮点
- 电商:对接支付平台、优惠券设计、库存超卖问题、秒杀抢购问题、超时订单处理问题
- 在线学习:视频点播、学习辅助系统、考试评测系统
- 社交互动:互动问答系统、课程点评系统、通用点赞系统、积分系统、排行榜系统
系统架构
-
用户端:学习、个人、搜索、交易中心
-
管理端:课程、用户、学习、交易、营销活动管理
-
支撑平台
- 基础服务:数据字典、角色管理、权限管理
- 第三方平台:视频点播、文件存储、内容审核、短信发送、三方支付服务
技术架构
-
展现层 Vue
-
接入层
- CDN
- 反向代理 NGINX
- 身份认证、请求路由、负载均衡
-
服务层
- 微服务组件:Nacos、Seata、Openfeign、sentinel、LoadBalancer、Springcloud
- 分布式组件:XXL-JOB、redisson、rabbitMq
-
数据层:es、Redis、MongoDB、MySQL
-
第三方:阿里云、腾讯云
-
DevOps:文档管理 YAPI、GOGS、持续集成 Jenkins、容器管理 Docker、日志管理 GrayLog、链路追踪 SW
补充:NGINX 与 Gateway 模块
功能区分
在 Spring Cloud 微服务项目中,负载均衡、请求路由和身份认证的功能通常可以由 Spring Cloud Gateway 和 NGINX 共同承担,但它们各自的侧重点不同:
都可以转发请求、引入负载均衡策略
- Gateway 请求路由:根据路径、请求头等条件,将请求路由到不同的微服务实例。
- NGINX 反向代理和静态资源处理:一方面处理前端页面和静态资源的请求,一方面将请求转发到后端的 Spring Cloud Gateway 或直接转发到微服务实例。
a. NGINX 进行简单的负载均衡:对多个 Gateway 实例或微服务实例进行简单的轮询或 IP Hash 负载均衡。
b. Gateway 配合 Spring Cloud LoadBalancer 或其他组件,实现对不同实例的流量分发。
# 示例(NGINX负载均衡到多个Gateway实例):
upstream gateway {
server gateway1:8080;
server gateway2:8080;
}
Spring Cloud Gateway
- 身份认证和授权:可以集成 OAuth2、JWT 等方式,在请求到达微服务前进行安全校验。
- 动态路由:可以通过配置中心动态修改路由规则,适应不同的需求。
- 限流:直接使用 Gateway 自带的
RequestRateLimiter
在配置文件中进行流量数量的限制配置即可,无需引入 Sentinel。
NGINX
- 请求过滤:可以做简单的黑白名单过滤或 IP 限制。
链路关系梳理
下边以
api.tianji.com/ts/orders/xxxxx
请求为例
由于在本地 hosts 文件已经配置了域名 api.tianji.com
,所以会转发到对应的 ip 地址 192.168.150.101
,即虚拟机的地址
又因为端口是缺省的 80,所以到了虚拟机里面就是访问 NGINX,NGINX 进行了如下的配置
-
-
所以请求会被代理到 Gateway 微服务模块
而 Gateway 里面又配置了下列路由规则,说明 URL /ts/**
会被负载均衡地路由到名称为 trade-service 的模块
而 tj-trade 项目配置文件里的项目名称就是 trade-service
由 URL 看得出来这种请求是 restful 风格的,看得出来订单资源后面的一串数字是订单 id,所以接下来去找 orders 相关的控制器
最终就找到了请求入口
-
综上所述,请求经过了 本地 DNS 文件、虚拟机 NGINX、Springcloud-Gateway 模块,最终抵达 tj-trade 模块的 OrderController 的 deleteOrder() 接口
NGINX 将请求转发给网关微服务模块,网关微服务将请求转发到具体的微服务
项目环境搭建
企业开发模式
本地部署、编码方面
-
本地只运行正在开发的微服务
-
对于 clone 下来的项目
-
Master 分支是完整的项目代码,==lesson-init 是上课要渐渐开发的分支==
-
==开发时需要使用 dev 分支==
- 后续在开发功能的时候,还会在 dev 基础上==创建其他分支==,一个功能就创建一个新的分支,然后合并到 dev,最后进行部署
-
-
对于 bootstrap 的多环境配置文件启动模块的 Application 的时候,不要直接右键 run,因为每个模块的 resource 下面都有不同环境的 yaml 配置文件
-
原因:由于 bootstrap.yaml 文件的配置,在默认情况下,微服务启用的是 bootstrap-dev.yaml 配置
-
说明:本项目 -dev 和-local 文件的唯一区别是 ip 地址,-dev 是虚拟机的地址,-local 是本机的地址
-
如果要在本地运行,需要在 idea 的服务的配置里设置 profile 为 local:【在这里配的会比配置文件的优先级要高,所以就不用修改配置文件了】
-
-
当本地项目和远程容器里的项目同时运行时,因为两个都是注册到虚拟机上的 Nacos,所以 Nacos 里同一个服务有两个实例
-
如果想要本地正在开发的项目不被别人访问到,但是又可以调用其他的服务,可以在配置成为 Nacos 的服务调用者的同时让自己不要注册要 Nacos 上,即将
register-enabled
配置为 false
-
调试方面
远程调试:用户在页面发起的请求还是到虚拟机的容器里,但虚拟机和本机都配置好了,请求会跳转到本机的 idea 的源码上
本地调试:通过在 Nacos 里将虚拟机的服务下线或者权重设置为 0,让用户页面发起请求后,到 Nacos 里只能获取并访问本地的服务实例
远程调试
==由于交易服务属于开发环境已经部署的服务,我们无法在本地调试(也不建议在本地调试,因为环境不一样),这在今后的开发中会经常碰到。遇到这样的情况我们就需要利用 IDEA 提供的远程调试功能。==
其实很简单,idea 已经给我们准备好了这样的功能,我们只要做一些简单的配置、再把在 idea 里配置的一串参数放到远程服务启动的参数里,然后就可以进行远程联调了
ps:要求本地和远程的代码一致
服务器端(远程机器)
本项目是基于 Jenkins 来部署的,因此是需要修改 Jenkins 部署脚本。
具体细节如下。
在 Jenkins 部署
tj-trade-debug
的任务里配置构建步骤 —— 执行shell
:
java ....xx.jar
的一串参数被配置在了启动脚本 startup.sh
里,启动脚本如下:
本地端(IDEA 或 Eclipse 配置)
-
打开 IDEA,点击
Run -> Edit Configurations
。 -
点击
+
,添加一个新的启动项,选择Remote JVM Debug
。 -
配置远程调试参数:
-
-
Host:远程服务器的 IP 地址。
-
Port:5005(远程 Java 进程监听的调试端口)。
-
Command Line Arguments for remote JVM:显示的命令和上面在服务器端执行的启动命令一致,即远程微服务启动命令为:
java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 xx.jar
这个命令用于远程调试 Java 应用程序,启动一个 Java 应用并开启 Java Debug Wire Protocol (JDWP) 调试接口。
-
java -jar
:以 jar 包形式运行 Java 程序。 -
xx.jar
:目标 Java 应用的 jar 文件名。 -
-agentlib:jdwp
:启用 JDWP,允许远程调试。 -
transport=dt_socket
:使用 socket 通信方式进行调试。 -
server=y
:将 JVM 作为调试服务器(监听调试请求)。 -
suspend=n
:JVM 启动时不挂起,直接运行,调试器可以随时连接。 -
address=*:5005
:监听在 5005 端口,*
表示监听所有 IP 地址,可以远程连接。
-
-
-
点击
Apply
,然后点击Debug
,IDEA 会尝试连接远程服务器进行调试。此时启动的不是本机的 tj-trade,而是远程的 代理
-
在代码中打断点,访问页面发起请求,触发远程代码执行后,调试器会自动停在断点处。
本地调试
测试方面
(本地)接口 / 单元 测试
因为项目中全部都配置了 swagger 的注解,所以可以通过 swagger 来测试所有的接口。
下面以测试 “删除订单” 接口为例。
-
在本地启动 tj-trade 项目,访问 swagger 页面
http://192.168.150.101:8088/doc.html
其中
8088
是 tj-trade 的端口 -
在
文档管理 - 全局参数设置
里添加一个 请求头类型的参数 user-info因为 删除订单时需要对登录用户做校验,因此需要先设置用户 id 的全局参数【具体细节看源码的登录用户的信息是如何传递的】
-
在
删除订单接口 - 调试 - 请求参数 - id
里添加 订单 id
用户 id 和 订单 id 得是 订单数据库里面的一条记录里配对的两个值!所以得通过数据库找到一对匹配的值进行测试才可以。
组件测试
将本地的微服务注册到 nacos 上去,把虚拟机里的服务停掉,从而让本地服务和其他服务进行联调
把虚拟机里的服务停掉的办法:
- 关停虚拟机中启动的交易服务:虚拟机里
docker stop tj-trade
- 在 Nacos 中将虚拟机中启动的交易服务权重设置为 0
- 在 Nacos 中将虚拟机中的服务下线
可以通过网页前端发起请求,也可以用公司提供的公共服务器上的 Mock 服务
部署联调
-
将本地代码 push 到 gogs 的==对应分支==上,让 gogs 上的钩子触发 Jenkins 对执行 tjxt-dev-build 任务:将 tjxt 项目从 gogs 上==**对应分支**==上拉取最新代码,进行编译、构建
编译、构建:具体脚本执行时是将项目从 gogs 上拉取下来,进行编译、打包
-
在 Jenkins 里手动点击部署修改了需要重新部署的微服务模块
部署:具体脚本执行时是 “构建 docker 镜像” + “ docker run 部署” ==【部署完之后 Nacos 会有对应服务】==
虽然在 Jenkins 的每个任务条目点击后方的 执行按钮都显示的是 “立即构建”,但其实对不同的任务又可以细分为 编译、构建、部署
补充:对 Jenkins 钩子 ==对应分支== 的配置
默认情况下,不加这个过滤器就意味着任何人只要推送代码到私服,都会触发这个构建,但事实上我们只要对 dev 分支的变化做构建,所以添加过滤器
此外,构建得基于特定的分支做构建,所以指定分支
远程部署方面【持续集成】
微服务手动部署比较麻烦而且容易出错,所以企业中都会采用持续集成的方式,==快捷实现开发、部署一条龙服务。==
==为了模拟真实环境,在虚拟机中已经提供了一套持续集成的开发环境,==代码一旦自测完成,push 到 Git 私服后即可自动编译、构建。
这个环境核心的角色有三个:Jenkins、gogs、docker
- gogs:存代码的私服,在 GUI 界面配置了钩子,当代码被 push 上来的时候会通知 Jenkins 进行部署
- Jenkins:从私服上拉取代码、进行部署【代码的编译、构建、打包,打包成 docker 的镜像】,是整个一条龙服务的核心
- docker:构建镜像,让部署很简单
熟悉项目
项目结构
-
本项目是:项目创建一个 Project,项目下的每一个微服务都是一个 Module,方便管理
-
绝大多数服务都是 常规的 结构:src、pom.xml
-
tj-auth 模块比较特殊,它要提供一些工具包 SDK 给其他模块用于身份校验
-
-
微服务
module
中如果有对外暴露的 Feign 接口,需要定义到tj-api
模块中-
实体类规范
- DTO:数据传输对象,在客户端与服务端间、服务端与服务端间传递数据,例如微服务之间的请求参数和返回值、前端提交的表单
- PO:持久层对象,与数据库表一一对应,作为查询数据库时的返回值
- VO:视图对象,返回给前端用于封装页面展示的数据
- QUERY:查询对象,一般是用于封装复杂查询条件
本项目里面都定义在 domain 包下【只是本项目的规范】
依赖注入
- 对于 final 类型的字段和 标注了
@NonNull
注解的字段,用 lombok 提供的 @RequiredArgsConstructor
来自动生成构造函数,用于构造器注入 - 对于其他的,仍然用 @Autowired 等方式注入
异常处理
-
全局异常处理器的使用,主要涉及到两个注解:
- @RestControllerAdvice // 表示当前类为全局异常处理器,专门捕获
@RestController
层抛出的异常。 - @ExceptionHandler // 指定可以捕获哪种类型的异常进行处理
- @RestControllerAdvice // 表示当前类为全局异常处理器,专门捕获
-
本项目的全局异常处理器位于 tj-common 的
autoconfigure.mvc.advice
包下 -
标注了
@RestControllerAdvice
的类CommonExceptionAdvice
下有很多标注了@ExceptionHandler
的异常处理方法、和一个响应处理的processResponse
方法-
-
其他
-
Linux 操作别名
-
ps -ef | grep nginx 命令【可以看到 nginx 装到哪】
-
-
docker ps -a 输出详解
- 多端口映射
-
Nacos 配置管理:共享的配置、动态的配置
-
项目是分模块开发的,除了公共模块,其余都是可以运行的
-
进入 docker 容器的命令参数详解
-
删除容器
docker rm
不等于 删除镜像docker rmi
,不可以删除正在运行的容器,除非先停掉容器或者用 -f 强制删除 -
maven 的聚合和集成
-
maven 的三套生命周期
-
每个模块都配置了 swagger,要访问某个模块的 swagger 页面,访问
192.168.150.101:xxxx
/doc.html
即可,xxxx 是该模块对应的端口-
除此之外,网关还做了微服务的聚合,即我们既可以通过上面每个端口去查看微服务的文档,也可以在网关查看所有微服务的文档。
-
Gateway 模块的端口是 10010:
同样一个接口,在网关 swagger 进行测试和在 单独模块 swagger 进行测试的返回不一样
- 网关 swagger 的返回面向前端
- 单独模块 swagger 返回的是服务间进行交互的数据
-
-
-
删除订单得用逻辑删除【可以用 @TableLogic 自动完成】
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于