Commit 7c8bfa34435129577ce5cbadd984af9ac40094ac
1 parent
53db9de9
1. 增加服务保障组件,支持限流、熔断等功能
2. 进一步完善文档
Showing
29 changed files
with
126 additions
and
39 deletions
README.md
| ... | ... | @@ -40,6 +40,7 @@ |
| 40 | 40 | 1. 链路追踪:基于 SkyWalking 实现性能监控,特别是链路的追踪 |
| 41 | 41 | 1. 分布式锁:基于 Redis 实现分布式锁,满足并发场景 |
| 42 | 42 | 1. 幂等组件:基于 Redis 实现幂等组件,解决重复请求问题 |
| 43 | +1. 服务保障:基于 Resilience4j 实现服务的稳定性,包括限流、熔断等功能 | |
| 43 | 44 | |
| 44 | 45 | ### 研发工具 |
| 45 | 46 | |
| ... | ... | @@ -58,6 +59,37 @@ |
| 58 | 59 | |
| 59 | 60 | > 未来会补充文档和视频,方便胖友冲冲冲! |
| 60 | 61 | |
| 62 | +## 技术栈 | |
| 63 | + | |
| 64 | +**后端** | |
| 65 | + | |
| 66 | +| 框架 | 说明 | 版本 | 学习指南 | | |
| 67 | +| --- | --- | --- | --- | | |
| 68 | +| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 2.4.2 | [文档](https://github.com/YunaiV/SpringBoot-Labs) | | |
| 69 | +| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 | | | |
| 70 | +| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.4 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) | | |
| 71 | +| [MyBatis-Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.4.1 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) | | |
| 72 | +| [Redis](https://redis.io/) | key-value 数据库 | 5.0 | | | |
| 73 | +| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.1.46 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) | | |
| 74 | +| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.4.2 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) | | |
| 75 | +| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.4.2 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) | | |
| 76 | +| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.1.7 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) | | |
| 77 | +| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) | | |
| 78 | +| [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.2 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) | | |
| 79 | +| [Resilience4j](https://github.com/quartz-scheduler) | 服务保障组件 | 1.7.0 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) | | |
| 80 | +| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.6.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) | | |
| 81 | +| [Spring Boot Admin](https://github.com/skywalking) | Spring Boot 监控平台 | 8.6.0 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) | | |
| 82 | +| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.11.4 | | | |
| 83 | +| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.4.1 | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) | | |
| 84 | +| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码| 1.16.14 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) | | |
| 85 | + | |
| 86 | +**前端** | |
| 87 | + | |
| 88 | +| 框架 | 说明 | 版本 | | |
| 89 | +| --- | --- | --- | | |
| 90 | +| [Vue](https://cn.vuejs.org/index.html) | JavaScript 框架 | 2.6.12 | | |
| 91 | +| [Vue Element Admin](https://ant.design/docs/react/introduce-cn) | 后台前端解决方案 | - | | |
| 92 | + | |
| 61 | 93 | ## 演示图 |
| 62 | 94 | |
| 63 | 95 | <table> | ... | ... |
pom.xml
| ... | ... | @@ -34,6 +34,7 @@ |
| 34 | 34 | <apollo.version>1.7.0</apollo.version> |
| 35 | 35 | <!-- 服务保障相关 --> |
| 36 | 36 | <lock4j.version>2.2.0</lock4j.version> |
| 37 | + <resilience4j.version>1.7.0</resilience4j.version> | |
| 37 | 38 | <!-- 监控相关 --> |
| 38 | 39 | <skywalking.version>8.3.0</skywalking.version> |
| 39 | 40 | <spring-boot-admin.version>2.3.1</spring-boot-admin.version> |
| ... | ... | @@ -145,6 +146,12 @@ |
| 145 | 146 | <version>${lock4j.version}</version> |
| 146 | 147 | </dependency> |
| 147 | 148 | |
| 149 | + <dependency> | |
| 150 | + <groupId>io.github.resilience4j</groupId> | |
| 151 | + <artifactId>resilience4j-spring-boot2</artifactId> | |
| 152 | + <version>${resilience4j.version}</version> | |
| 153 | + </dependency> | |
| 154 | + | |
| 148 | 155 | <!-- 监控相关 --> |
| 149 | 156 | <dependency> |
| 150 | 157 | <groupId>org.apache.skywalking</groupId> | ... | ... |
ruoyi-ui/README.md deleted
| 1 | -## 开发 | |
| 2 | - | |
| 3 | -```bash | |
| 4 | -# 克隆项目 | |
| 5 | -git clone https://github.com/YunaiV/ruoyi-vue-pro | |
| 6 | - | |
| 7 | -# 进入项目目录 | |
| 8 | -cd ruoyi-ui | |
| 9 | - | |
| 10 | -# 安装依赖 | |
| 11 | -npm install | |
| 12 | - | |
| 13 | -# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题 | |
| 14 | -npm install --registry=https://registry.npm.taobao.org | |
| 15 | - | |
| 16 | -# 启动服务 | |
| 17 | -npm run dev | |
| 18 | -``` | |
| 19 | - | |
| 20 | -浏览器访问 http://localhost:80 | |
| 21 | - | |
| 22 | -## 发布 | |
| 23 | - | |
| 24 | -```bash | |
| 25 | -# 构建测试环境 | |
| 26 | -npm run build:stage | |
| 27 | - | |
| 28 | -# 构建生产环境 | |
| 29 | -npm run build:prod | |
| 30 | -``` |
src/main/java/cn/iocoder/dashboard/DashboardApplication.java
| ... | ... | @@ -5,7 +5,6 @@ import org.springframework.boot.SpringApplication; |
| 5 | 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; |
| 6 | 6 | |
| 7 | 7 | @SpringBootApplication |
| 8 | -@EnableAdminServer // TODO 芋艿:需要迁移出去 | |
| 9 | 8 | public class DashboardApplication { |
| 10 | 9 | |
| 11 | 10 | public static void main(String[] args) { | ... | ... |
src/main/java/cn/iocoder/dashboard/common/exception/enums/GlobalErrorCodeConstants.java
| ... | ... | @@ -23,6 +23,8 @@ public interface GlobalErrorCodeConstants { |
| 23 | 23 | ErrorCode FORBIDDEN = new ErrorCode(403, "没有该操作权限"); |
| 24 | 24 | ErrorCode NOT_FOUND = new ErrorCode(404, "请求未找到"); |
| 25 | 25 | ErrorCode METHOD_NOT_ALLOWED = new ErrorCode(405, "请求方法不正确"); |
| 26 | + ErrorCode LOCKED = new ErrorCode(423, "请求失败,请稍后重试"); // 并发请求,不允许 | |
| 27 | + ErrorCode TOO_MANY_REQUESTS = new ErrorCode(429, "请求过于频繁,请稍后重试"); | |
| 26 | 28 | |
| 27 | 29 | // ========== 服务端错误段 ========== |
| 28 | 30 | |
| ... | ... | @@ -30,7 +32,6 @@ public interface GlobalErrorCodeConstants { |
| 30 | 32 | |
| 31 | 33 | // ========== 自定义错误段 ========== |
| 32 | 34 | ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求 |
| 33 | - ErrorCode CONCURRENCY_REQUESTS = new ErrorCode(901, "请求失败,请稍后重试"); // 并发请求,不允许 | |
| 34 | 35 | |
| 35 | 36 | ErrorCode UNKNOWN = new ErrorCode(999, "未知错误"); |
| 36 | 37 | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/async/《芋道 Spring Boot 异步任务入门》.md
src/main/java/cn/iocoder/dashboard/framework/datasource/《芋道 Spring Boot 多数据源(读写分离)入门》.md
0 → 100644
| 1 | +<http://www.iocoder.cn/Spring-Boot/dynamic-datasource/?yudao> | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/datasource/《芋道 Spring Boot 数据库连接池入门》.md
0 → 100644
| 1 | +<http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao> | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/lock4j/core/DefaultLockFailureStrategy.java
| ... | ... | @@ -14,7 +14,7 @@ public class DefaultLockFailureStrategy implements LockFailureStrategy { |
| 14 | 14 | @Override |
| 15 | 15 | public void onLockFailure(String key, long acquireTimeout, int acquireCount) { |
| 16 | 16 | log.debug("[onLockFailure][线程:{} 获取锁失败,key:{} 获取超时时长:{} ms]", Thread.currentThread().getName(), key, acquireTimeout); |
| 17 | - throw new ServiceException(GlobalErrorCodeConstants.CONCURRENCY_REQUESTS); | |
| 17 | + throw new ServiceException(GlobalErrorCodeConstants.LOCKED); | |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | 20 | } | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/monitor/AdminServerConfiguration.java
0 → 100644
src/main/java/cn/iocoder/dashboard/framework/monitor/package-info.java
0 → 100644
src/main/java/cn/iocoder/dashboard/framework/monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md
0 → 100644
| 1 | +<http://www.iocoder.cn/Spring-Boot/Admin/?yudao> | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/mybatis/《芋道 Spring Boot MyBatis 入门》.md
0 → 100644
| 1 | +<http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao> | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/quartz/《芋道 Spring Boot 定时任务入门》.md
0 → 100644
| 1 | +<http://www.iocoder.cn/Spring-Boot/Job/?yudao> | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/redis/package-info.java
0 → 100644
src/main/java/cn/iocoder/dashboard/framework/redis/《芋道 Spring Boot Redis 入门》.md
0 → 100644
| 1 | +<http://www.iocoder.cn/Spring-Boot/Redis/?yudao> | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/resilience4j/package-info.java
0 → 100644
src/main/java/cn/iocoder/dashboard/framework/resilience4j/《芋道 Spring Boot 安全框架 Spring Security 入门》.md
0 → 100644
| 1 | +<http://www.iocoder.cn/Spring-Boot/Spring-Security/?github> | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/security/《芋道 Spring Boot 安全框架 Spring Security 入门》.md
| 1 | -* 芋道 Spring Security 入门:<http://www.iocoder.cn/Spring-Boot/Spring-Security/?dashboard> | |
| 2 | -* Spring Security 基本概念:<http://www.iocoder.cn/Fight/Spring-Security-4-1-0-Basic-concept-description/?dashboard> | |
| 1 | +* 芋道 Spring Security 入门:<http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao> | |
| 2 | +* Spring Security 基本概念:<http://www.iocoder.cn/Fight/Spring-Security-4-1-0-Basic-concept-description/?yudao> | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/swagger/《芋道 Spring Boot API 接口文档 Swagger 入门》.md
src/main/java/cn/iocoder/dashboard/framework/tracer/《芋道 Spring Boot 链路追踪 SkyWalking 入门》.md
0 → 100644
| 1 | +<http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao> | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/validator/package-info.java
0 → 100644
src/main/java/cn/iocoder/dashboard/framework/validator/《芋道 Spring Boot 参数校验 Validation 入门》.md
0 → 100644
| 1 | +<http://www.iocoder.cn/Spring-Boot/Validation/?yudao> | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/web/core/handler/GlobalExceptionHandler.java
| ... | ... | @@ -4,6 +4,7 @@ import cn.iocoder.dashboard.common.exception.GlobalException; |
| 4 | 4 | import cn.iocoder.dashboard.common.exception.ServiceException; |
| 5 | 5 | import cn.iocoder.dashboard.common.pojo.CommonResult; |
| 6 | 6 | import cn.iocoder.dashboard.framework.security.core.util.SecurityUtils; |
| 7 | +import io.github.resilience4j.ratelimiter.RequestNotPermitted; | |
| 7 | 8 | import lombok.extern.slf4j.Slf4j; |
| 8 | 9 | import org.springframework.security.access.AccessDeniedException; |
| 9 | 10 | import org.springframework.validation.BindException; |
| ... | ... | @@ -63,6 +64,9 @@ public class GlobalExceptionHandler { |
| 63 | 64 | if (ex instanceof HttpRequestMethodNotSupportedException) { |
| 64 | 65 | return httpRequestMethodNotSupportedExceptionHandler((HttpRequestMethodNotSupportedException) ex); |
| 65 | 66 | } |
| 67 | + if (ex instanceof RequestNotPermitted) { | |
| 68 | + return requestNotPermittedExceptionHandler(request, (RequestNotPermitted) ex); | |
| 69 | + } | |
| 66 | 70 | if (ex instanceof ServiceException) { |
| 67 | 71 | return serviceExceptionHandler((ServiceException) ex); |
| 68 | 72 | } |
| ... | ... | @@ -164,6 +168,15 @@ public class GlobalExceptionHandler { |
| 164 | 168 | } |
| 165 | 169 | |
| 166 | 170 | /** |
| 171 | + * 处理 Resilience4j 限流抛出的异常 | |
| 172 | + */ | |
| 173 | + @ExceptionHandler(value = RequestNotPermitted.class) | |
| 174 | + public CommonResult<?> requestNotPermittedExceptionHandler(HttpServletRequest req, RequestNotPermitted ex) { | |
| 175 | + log.warn("[requestNotPermittedExceptionHandler][url({}) 访问过于频繁]", req.getRequestURL(), ex); | |
| 176 | + return CommonResult.error(TOO_MANY_REQUESTS); | |
| 177 | + } | |
| 178 | + | |
| 179 | + /** | |
| 167 | 180 | * 处理 Spring Security 权限不足的异常 |
| 168 | 181 | * |
| 169 | 182 | * 来源是,使用 @PreAuthorize 注解,AOP 进行权限拦截 | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/web/《芋道 Spring Boot SpringMVC 入门》.md
src/main/java/cn/iocoder/dashboard/modules/tool/controller/test/ToolTestDemoController.http
src/main/java/cn/iocoder/dashboard/modules/tool/controller/test/ToolTestDemoController.java
| ... | ... | @@ -10,6 +10,7 @@ import cn.iocoder.dashboard.modules.tool.convert.test.ToolTestDemoConvert; |
| 10 | 10 | import cn.iocoder.dashboard.modules.tool.dal.dataobject.test.ToolTestDemoDO; |
| 11 | 11 | import cn.iocoder.dashboard.modules.tool.service.test.ToolTestDemoService; |
| 12 | 12 | import com.baomidou.lock.annotation.Lock4j; |
| 13 | +import io.github.resilience4j.ratelimiter.annotation.RateLimiter; | |
| 13 | 14 | import io.swagger.annotations.Api; |
| 14 | 15 | import io.swagger.annotations.ApiImplicitParam; |
| 15 | 16 | import io.swagger.annotations.ApiOperation; |
| ... | ... | @@ -78,6 +79,7 @@ public class ToolTestDemoController { |
| 78 | 79 | @ApiOperation("获得测试示例列表") |
| 79 | 80 | @ApiImplicitParam(name = "ids", value = "编号列表", required = true, dataTypeClass = List.class) |
| 80 | 81 | @PreAuthorize("@ss.hasPermission('tool:test-demo:query')") |
| 82 | + @RateLimiter(name = "backendA") | |
| 81 | 83 | public CommonResult<List<ToolTestDemoRespVO>> getTestDemoList(@RequestParam("ids") Collection<Long> ids) { |
| 82 | 84 | List<ToolTestDemoDO> list = testDemoService.getTestDemoList(ids); |
| 83 | 85 | return success(ToolTestDemoConvert.INSTANCE.convertList(list)); | ... | ... |
src/main/resources/application-dev.yaml
| ... | ... | @@ -88,6 +88,16 @@ lock4j: |
| 88 | 88 | acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒 |
| 89 | 89 | expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒 |
| 90 | 90 | |
| 91 | +# Resilience4j 配置项 | |
| 92 | +resilience4j: | |
| 93 | + ratelimiter: | |
| 94 | + instances: | |
| 95 | + backendA: | |
| 96 | + limit-for-period: 1 # 每个周期内,允许的请求数。默认为 50 | |
| 97 | + limit-refresh-period: 60s # 每个周期的时长,单位:微秒。默认为 500 | |
| 98 | + timeout-duration: 1s # 被限流时,阻塞等待的时长,单位:微秒。默认为 5s | |
| 99 | + register-health-indicator: true # 是否注册到健康监测 | |
| 100 | + | |
| 91 | 101 | --- #################### 监控相关配置 #################### |
| 92 | 102 | |
| 93 | 103 | # Actuator 监控端点的配置项 | ... | ... |
src/main/resources/application-local.yaml
| ... | ... | @@ -88,6 +88,16 @@ lock4j: |
| 88 | 88 | acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒 |
| 89 | 89 | expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒 |
| 90 | 90 | |
| 91 | +# Resilience4j 配置项 | |
| 92 | +resilience4j: | |
| 93 | + ratelimiter: | |
| 94 | + instances: | |
| 95 | + backendA: | |
| 96 | + limit-for-period: 1 # 每个周期内,允许的请求数。默认为 50 | |
| 97 | + limit-refresh-period: 60s # 每个周期的时长,单位:微秒。默认为 500 | |
| 98 | + timeout-duration: 1s # 被限流时,阻塞等待的时长,单位:微秒。默认为 5s | |
| 99 | + register-health-indicator: true # 是否注册到健康监测 | |
| 100 | + | |
| 91 | 101 | --- #################### 监控相关配置 #################### |
| 92 | 102 | |
| 93 | 103 | # Actuator 监控端点的配置项 | ... | ... |