Merge remote-tracking branch 'upstream/develop' into develop

# Conflicts:
#	docs/docs/user_docs/other/issue.md
pull/635/head
airoger 3 years ago
commit 738a0a0bbd

@ -3,16 +3,16 @@ name: "BUG 报告"
about: 提交问题缺陷帮助我们更好的改进
---
## Bug Report
## BUG 报告
在开始报告错误之前,请确保认真查看了以下步骤:
- 搜索打开和关闭的 [GitHub 问题](https://github.com/opengoofy/hippo4j/issues)
- 阅读 [常见问题文档](https://hippo4j.cn/pages/9cc27d/)
- 阅读 [常见问题文档](https://hippo4j.cn/docs/user_docs/other/issue)
请在提交问题之前回答这些问题,谢谢。
### 你使用了哪个项目?Hippo-4J Server 还是 Hippo-4J Core?
### 你使用了哪个项目?hippo4j config 还是 hippo4j server?
### 你使用了哪个版本?

@ -3,11 +3,10 @@ name: "需求建议"
about: 提出针对本项目的想法和建议
---
## Feature Request
## 需求建议
请在提交问题之前回答这些问题,谢谢。
### 您的功能请求是否与问题有关?
### 描述你想要的功能

@ -3,16 +3,16 @@ name: "问题支持"
about: 文档或讨论中未回答的使用问题
---
## Question Report
## 问题支持
在开始报告问题之前,请确保认真查看了以下步骤:
- 搜索打开和关闭的 [GitHub 问题](https://github.com/opengoofy/hippo4j/issues)
- 阅读 [常见问题文档](https://hippo4j.cn/pages/9cc27d/)
- 阅读 [常见问题文档](https://hippo4j.cn/docs/user_docs/other/issue)
请在提交问题之前回答这些问题,谢谢。
### 你使用了哪个项目?Hippo-4J Server 还是 Hippo-4J Core?
### 你使用了哪个项目?hippo4j config 还是 hippo4j server?
### 你使用了哪个版本?

@ -2,31 +2,41 @@
# 动态可观测线程池框架,提高线上运行保障能力
[![Gitee](https://gitee.com/mabaiwancn/hippo4j/badge/star.svg?theme=gvp)](https://gitee.com/mabaiwancn/hippo4j) [![GitHub](https://img.shields.io/github/stars/opengoofy/hippo4j)](https://github.com/opengoofy/hippo4j) [![OpenIssue](http://isitmaintained.com/badge/open/opengoofy/hippo4j.svg)](https://github.com/opengoofy/hippo4j/issues) [![Contributors](https://img.shields.io/github/contributors/opengoofy/hippo4j?color=3ba272)](https://github.com/opengoofy/hippo4j/graphs/contributors) [![License](https://img.shields.io/github/license/opengoofy/hippo4j?color=5470c6)](https://github.com/opengoofy/hippo4j/blob/develop/LICENSE)
[![Gitee](https://gitee.com/agentart/hippo4j/badge/star.svg?theme=gvp)](https://gitee.com/agentart/hippo4j) [![GitHub](https://img.shields.io/github/stars/opengoofy/hippo4j)](https://github.com/opengoofy/hippo4j) [![OpenIssue](http://isitmaintained.com/badge/open/opengoofy/hippo4j.svg)](https://github.com/opengoofy/hippo4j/issues) [![Contributors](https://img.shields.io/github/contributors/opengoofy/hippo4j?color=3ba272)](https://github.com/opengoofy/hippo4j/graphs/contributors) [![License](https://img.shields.io/github/license/opengoofy/hippo4j?color=5470c6)](https://github.com/opengoofy/hippo4j/blob/develop/LICENSE)
-------
## 什么是 Hippo-4J
Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池等功能,为业务系统提高线上运行保障能力。
## 线程池痛点
- 🏗 全局管控 - 管理应用线程池实例;
线程池是一种基于池化思想管理线程的工具,使用线程池可以减少创建销毁线程的开销,避免线程过多导致系统资源耗尽。在高并发以及大批量的任务处理场景,线程池的使用是必不可少的。
- ⚡️ 动态变更 - 应用运行时动态变更线程池参数,包括不限于:核心、最大线程数、阻塞队列容量、拒绝策略等;
如果有在项目中实际使用线程池,相信你可能会遇到以下痛点:
- 🐳 通知报警 - 内置四种报警通知策略,线程池活跃度、容量水位、拒绝策略以及任务执行时间超长;
- 线程池随便定义,线程资源过多,造成服务器高负载。
- 👀 运行监控 - 实时查看线程池运行时数据,最近半小时线程池运行数据图表展示;
- 线程池参数不易评估,随着业务的并发提升,业务面临出现故障的风险。
- 线程池任务执行时间超过平均执行周期,开发人员无法感知。
- 线程池任务堆积,触发拒绝策略,影响既有业务正常运行。
- 当业务出现超时、熔断等问题时,因为没有监控,无法确定是不是线程池引起。
- 原生线程池不支持运行时变量的传递,比如 MDC 上下文遇到线程池就 GG。
- 无法执行优雅关闭,当项目关闭时,大量正在运行的线程池任务被丢弃。
- 线程池运行中,任务执行停止,怀疑发生死锁或执行耗时操作,但是无从下手。
- 👐 功能扩展 - 支持线程池任务传递上下文;项目关闭时,支持等待线程池在指定时间内完成任务;
## 什么是 Hippo-4J
- 👯‍♀️ 多种模式 - 内置两种使用模式:[依赖配置中心](https://hippo4j.cn/docs/user_docs/getting-started/hippo4j-core-start) 和 [无中间件依赖](https://hippo4j.cn/docs/user_docs/getting-started/hippo4j-server-start)
Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池等功能,为业务系统提高线上运行保障能力。
- 🛠 容器管理 - Tomcat、Jetty、Undertow 容器线程池运行时查看和线程数变更;
- 全局管控 - 管理应用线程池实例
- 🌈 中间件适配 - Apache RocketMQ、Dubbo、RabbitMQ、Hystrix 消费线程池运行时数据查看和线程数变更。
- 动态变更 - 应用运行时动态变更线程池参数,包括不限于:核心、最大线程数、阻塞队列容量、拒绝策略等;
- 通知报警 - 内置四种报警通知策略,线程池活跃度、容量水位、拒绝策略以及任务执行时间超长;
- 运行监控 - 实时查看线程池运行时数据,最近半小时线程池运行数据图表展示;
- 功能扩展 - 支持线程池任务传递上下文;项目关闭时,支持等待线程池在指定时间内完成任务;
- 多种模式 - 内置两种使用模式:[依赖配置中心](https://hippo4j.cn/docs/user_docs/getting-started/hippo4j-core-start) 和 [无中间件依赖](https://hippo4j.cn/docs/user_docs/getting-started/hippo4j-server-start)
- 容器管理 - Tomcat、Jetty、Undertow 容器线程池运行时查看和线程数变更;
- 中间件适配 - Apache RocketMQ、Dubbo、RabbitMQ、Hystrix 消费线程池运行时数据查看和线程数变更。
> 看完有收获,右上角帮忙点个小星星,开源作者为爱发电也不容易 🤣
> 开源作者为爱发电不容易,看完有收获,右上角帮忙点个小星星 🤩
## 快速开始
@ -36,32 +46,35 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
- http://console.hippo4j.cn/index.html
- 用户名/密码hippo4j/hippo4j
## 安全检测
[![OSCS Status](https://www.oscs1024.com/platform/badge/opengoofy/hippo4j.svg?size=large)](https://www.murphysec.com/dr/s285JA1FVHD7tayWLt)
## 荣誉墙
## 联系我
Hippo-4J 获得了一些宝贵的荣誉,肯定了 Hippo-4J 作为一款开源框架所带来的价值。
图片加载不出来,访问 [官网站点](https://hippo4j.cn/docs/user_docs/other/group)
<img align="center" width="680" alt="image" src="https://user-images.githubusercontent.com/77398366/187014905-b50bdc8b-ca0e-4137-9a02-1e6b06106191.jpg">
![image](https://user-images.githubusercontent.com/77398366/180110548-7a05b74d-0316-4066-96f4-1c9331638633.png)
## 开发者
感谢所有为 Hippo-4J 做出贡献的开发者!
Hippo-4J 获得的成就属于每一位对 Hippo-4J 做出过贡献的成员,感谢各位的贡献。
如果屏幕前的同学有意提交 Hippo-4J请参考 [good first issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) 或者 [good pro issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+pro+issue%22) 任务列表。
<a href="https://github.com/opengoofy/hippo4j/graphs/contributors"><img src="https://opencollective.com/hippo4j/contributors.svg?width=890&button=false" /></a>
## 我们的荣誉
Hippo-4J 获得了一些宝贵的荣誉,这属于每一位对 Hippo-4J 做出过贡献的成员,谢谢各位的付出。
## 友情链接
<img align="center" width="880" alt="image" src="https://user-images.githubusercontent.com/77398366/170607238-7308c9be-1d63-46a6-852c-eef2e4cf7405.JPG">
- [[ Sa-Token ]](https://github.com/dromara/sa-token):一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!
## 友情链接
- [[ HertzBeat ]](https://github.com/dromara/hertzbeat):易用友好的云监控系统, 无需 Agent, 强大自定义监控能力。
- [[ JavaGuide ]](https://github.com/Snailclimb/JavaGuide):一份涵盖大部分 Java 程序员所需要掌握的核心知识。
- [[ toBeBetterJavaer ]](https://github.com/itwanger/toBeBetterJavaer):一份通俗易懂、风趣幽默的 Java 学习指南。
## 联系我
![image](https://user-images.githubusercontent.com/77398366/185774220-c11951f9-e130-4d60-8204-afb5c51d4401.png)
- [HertzBeat](https://github.com/dromara/hertzbeat):易用友好的云监控系统, 无需Agent, 强大自定义监控能力。
- [JavaGuide](https://github.com/Snailclimb/JavaGuide):一份涵盖大部分 Java 程序员所需要掌握的核心知识。
- [toBeBetterJavaer](https://github.com/itwanger/toBeBetterJavaer):一份通俗易懂、风趣幽默的 Java 学习指南。
- [Guide-Rpc-Framework](https://github.com/Snailclimb/guide-rpc-framework):一款基于 Netty+Kyro+Zookeeper 实现的自定义 RPC 框架。
- [Austin](https://github.com/ZhongFuCheng3y/austin):消息推送平台,支持短信、邮件、微信公众号、企业微信、钉钉等多种消息类型。
扫码添加微信备注hippo4j邀您加入群聊。若图片加载不出来访问 [官网站点](https://hippo4j.cn/docs/user_docs/other/group)

@ -2,18 +2,19 @@
sidebar_position: 1
---
# 开发者指南
# 贡献指南
Git Commit Log 尽量使用英文。
为了让您的 id 显示在 contributor 列表中,别忘了以下设置:
为了让您的 ID 显示在 Contributor 列表中,别忘了以下设置:
```shell
git config --global user.name "username"
git config --global user.email "github账号邮箱"
git config --global user.email "GitHub 账号邮箱"
```
## 开发者列表
## 贡献者列表
您可以在 [Hippo4J](https://github.com/opengoofy/hippo4j/graphs/contributors) 和 [Hippo4J Console](https://github.com/opengoofy/hippo4j-console) 的贡献列表中找到全部的贡献者名单。
<a href="https://github.com/opengoofy/hippo4j/graphs/contributors"><img src="https://contrib.rocks/image?repo=opengoofy/hippo4j"/></a>
<a href="https://github.com/opengoofy/hippo4j/graphs/contributors"><img src="https://opencollective.com/hippo4j/contributors.svg?width=890&button=false"/></a>

@ -0,0 +1,7 @@
{
"label": "贡献规约",
"position": 2,
"link": {
"type": "generated-index"
}
}

@ -0,0 +1,8 @@
---
sidebar_position: 2
---
# 代码规约
1. 代码提交前,执行 `mvn spotless:apply` 保证代码格式符合规范。
2. 代码中不要出现无意义的空行。

@ -0,0 +1,227 @@
---
sidebar_position: 1
---
# 文档规约
文档引用自:[中文文案排版指北](https://github.com/sparanoid/chinese-copywriting-guidelines)
## 空格
> 「有研究顯示,打字的時候不喜歡在中文和英文之間加空格的人,感情路都走得很辛苦,有七成的比例會在 34 歲的時候跟自己不愛的人結婚,而其餘三成的人最後只能把遺產留給自己的貓。畢竟愛情跟書寫都需要適時地留白。
>
> 與大家共勉之。」——[vinta/paranoid-auto-spacing](https://github.com/vinta/pangu.js)
### 中英文之間需要增加空格
正確:
> 在 LeanCloud 上,數據儲存是圍繞 `AVObject` 進行的。
錯誤:
> 在LeanCloud上數據儲存是圍繞`AVObject`進行的。
> 在 LeanCloud上數據儲存是圍繞`AVObject` 進行的。
完整的正確用法:
> 在 LeanCloud 上,數據儲存是圍繞 `AVObject` 進行的。每個 `AVObject` 都包含了與 JSON 兼容的 key-value 對應的數據。數據是 schema-free 的,你不需要在每個 `AVObject` 上提前指定存在哪些键,只要直接設定對應的 key-value 即可。
例外「豆瓣FM」等產品名詞按照官方所定義的格式書寫。
### 中文與數字之間需要增加空格
正確:
> 今天出去買菜花了 5000 元。
錯誤:
> 今天出去買菜花了 5000元。
> 今天出去買菜花了5000元。
### 數字與單位之間需要增加空格
正確:
> 我家的光纖入屋寬頻有 10 GbpsSSD 一共有 20 TB。
錯誤:
> 我家的光纖入屋寬頻有 10GbpsSSD 一共有 20TB。
例外:度數/百分比與數字之間不需要增加空格:
正確:
> 角度為 90° 的角,就是直角。
> 新 MacBook Pro 有 15% 的 CPU 性能提升。
錯誤:
> 角度為 90 ° 的角,就是直角。
> 新 MacBook Pro 有 15 % 的 CPU 性能提升。
### 全形標點與其他字符之間不加空格
正確:
> 剛剛買了一部 iPhone好開心
錯誤:
> 剛剛買了一部 iPhone ,好開心!
> 剛剛買了一部 iPhone 好開心!
### `text-spacing` to the rescue?
CSS Text Module Level 4 的 [`text-spacing`](https://www.w3.org/TR/css-text-4/#text-spacing-property) 和 Microsoft 的 [`-ms-text-autospace`](https://msdn.microsoft.com/library/ms531164(v=vs.85).aspx) 可以實現自動為中英文之間增加空白。不過目前並未普及,另外在其他應用場景,例如 macOS、iOS、Windows 等用戶介面目前並不存在這個特性,所以請繼續保持隨手加空格的習慣。
## 標點符號
### 不重複使用標點符號
即使中國大陸的標點符號用法允許重複使用標點符號,但是這麼做會破壞句子的美觀性。
正確:
> 德國隊竟然戰勝了巴西隊!
> 她竟然對你說「喵」?!
錯誤:
> 德國隊竟然戰勝了巴西隊!!
> 德國隊竟然戰勝了巴西隊!!!!!!!!
> 她竟然對你說「喵」??!!
> 她竟然對你說「喵」?!?!??!!
## 全形和半形
不明白什麼是全形(全角)與半形(半角)符號?請查看維基百科條目『[全形和半形](https://zh.wikipedia.org/wiki/%E5%85%A8%E5%BD%A2%E5%92%8C%E5%8D%8A%E5%BD%A2)』。
### 使用全形中文標點
正確:
> 嗨!你知道嘛?今天前台的小妹跟我說「喵」了哎!
> 核磁共振成像NMRI是什麼原理都不知道JFGI
錯誤:
> 嗨! 你知道嘛? 今天前台的小妹跟我說 "喵" 了哎!
> 嗨!你知道嘛?今天前台的小妹跟我說"喵"了哎!
> 核磁共振成像 (NMRI) 是什麼原理都不知道? JFGI!
> 核磁共振成像(NMRI)是什麼原理都不知道?JFGI!
### 數字使用半形字符
正確:
> 這件蛋糕只賣 1000 元。
錯誤:
> 這件蛋糕只賣 元。
例外:在設計稿、宣傳海報中如出現極少量數字的情形時,為方便文字對齊,是可以使用全形數字的。
### 遇到完整的英文整句、特殊名詞,其內容使用半形標點
正確:
> 賈伯斯那句話是怎麼說的「Stay hungry, stay foolish.」
> 推薦你閱讀《Hackers & Painters: Big Ideas from the Computer Age》非常的有趣。
錯誤:
> 賈伯斯那句話是怎麼說的「Stay hungrystay foolish。」
> 推薦你閱讀《HackersPaintersBig Ideas from the Computer Age》非常的有趣。
## 名詞
### 專有名詞使用正確的大小寫
大小寫相關用法原屬於英文書寫範疇,不屬於本 wiki 討論內容,在這裡只對部分易錯用法進行簡述。
正確:
> 使用 GitHub 登錄
> 我們的客戶有 GitHub、Foursquare、Microsoft Corporation、Google、Facebook, Inc.。
錯誤:
> 使用 github 登錄
> 使用 GITHUB 登錄
> 使用 Github 登錄
> 使用 gitHub 登錄
> 使用 gイんĤЦ8 登錄
> 我們的客戶有 github、foursquare、microsoft corporation、google、facebook, inc.。
> 我們的客戶有 GITHUB、FOURSQUARE、MICROSOFT CORPORATION、GOOGLE、FACEBOOK, INC.。
> 我們的客戶有 Github、FourSquare、MicroSoft Corporation、Google、FaceBook, Inc.。
> 我們的客戶有 gitHub、fourSquare、microSoft Corporation、google、faceBook, Inc.。
> 我們的客戶有 gイんĤЦ8、キouЯƧquムгє、๓เςг๏ร๏Ŧt ς๏гק๏гคtเ๏ภn、900913、ƒ4ᄃëв๏๏к, IПᄃ.。
注意當網頁中需要配合整體視覺風格而出現全部大寫小寫的情形HTML 中請使用標準的大小寫規範進行書寫;並通過 `text-transform: uppercase;``text-transform: lowercase;` 對表現形式進行定義。
### 不要使用不道地的縮寫
正確:
> 我們需要一位熟悉 TypeScript、HTML5至少理解一種框架如 React、Next.js的前端開發者。
錯誤:
> 我們需要一位熟悉 Ts、h5至少理解一種框架如 RJS、nextjs的 FED。
## 爭議
以下用法略帶有個人色彩,即:無論是否遵循下述規則,從語法的角度來講都是**正確**的。
### 超連結之間增加空格
用法:
> 請 [提交一個 issue](#) 並分配给相關同事。
> 訪問我們網站的最新動態,請 [點擊這裡](#) 進行訂閱!
對比用法:
> 請[提交一個 issue](#) 並分配给相關同事。
> 訪問我們網站的最新動態,請[點擊這裡](#)進行訂閱!
### 簡體中文使用直角引號
用法:
> 「老师,『有条不紊』的『紊』是什么意思?」
對比用法:
> “老师,‘有条不紊’的‘紊’是什么意思?”

@ -4,10 +4,53 @@ sidebar_position: 2
# 核心开发者
<table>
<tr>
<td align="center"><a href="https://github.com/mabaiwan"><img src="https://avatars.githubusercontent.com/u/77398366?v=4?s=100" width="100px;" alt=""/><br /><sub><b>马称</b></sub></a></td>
<td align="center"><a href="https://github.com/shining-stars-lk"><img src="https://avatars.githubusercontent.com/u/40255310?v=4?s=100" width="100px;" alt=""/><br /><sub><b>陆宽</b></sub></a></td>
<td align="center"></td>
<td align="center" width="120">姓名</td>
<td align="center" width="160">GitHub ID</td>
<td align="center" width="160">博客地址</td>
<td align="center" width="140">角色</td>
<td align="center" width="200">联系方式</td>
</tr>
<tr>
<td align="center" ><a href="https://github.com/agentart"><img src="https://avatars.githubusercontent.com/u/77398366?v=4?s=64" width="64px;"/></a></td>
<td align="center" >马称</td>
<td align="center" ><a href="https://github.com/agentart">agentart</a></td>
<td align="center" ><a href="http://www.xiaomage.info/">小马哥的技术专栏</a></td>
<td align="center" >项目发起者</td>
<td align="center" >machen@apache.org</td>
</tr>
<tr>
<td align="center"><a href="https://github.com/shining-stars-lk"><img src="https://avatars.githubusercontent.com/u/40255310?v=4?s=64" width="64px;"/></a></td>
<td align="center">陆宽</td>
<td align="center" ><a href="https://github.com/shining-stars-lk">shining-stars-lk</a></td>
<td align="center" ><a href="https://blog.csdn.net/guntun8987">宽仔的代码之路</a></td>
<td align="center" >核心开发者</td>
<td align="center" >1031900093@qq.com</td>
</tr>
<tr>
<td align="center"><a href="https://github.com/iwangjie"><img src="https://avatars.githubusercontent.com/u/23075587?v=4?s=64" width="64px;"/></a></td>
<td align="center">王杰</td>
<td align="center" ><a href="https://github.com/iwangjie">iwangjie</a></td>
<td align="center" >-</td>
<td align="center" >核心开发者</td>
<td align="center" >wangchenmo1025@gmail.com</td>
</tr>
<tr>
<td align="center"><a href="https://github.com/weihubeats"><img src="https://avatars.githubusercontent.com/u/42484192?v=4?s=64" width="64px;"/></a></td>
<td align="center">魏虎</td>
<td align="center" ><a href="https://github.com/weihubeats">weihubeats</a></td>
<td align="center" ><a href="https://weihubeats.blog.csdn.net/">weihubeats</a></td>
<td align="center" >核心开发者</td>
<td align="center" >weihubeats@163.com</td>
</tr>
<tr>
<td align="center"><a href="https://github.com/BigXin0109"><img src="https://avatars.githubusercontent.com/u/24769514?v=4?s=64" width="64px;"/></a></td>
<td align="center">李剑鑫</td>
<td align="center" ><a href="https://github.com/BigXin0109">BigXin0109</a></td>
<td align="center" ><a href="https://blog.csdn.net/qq_34741165">OnlyBig</a></td>
<td align="center" >核心开发者</td>
<td align="center" >1064730540@qq.com</td>
</tr>
</table>

@ -12,7 +12,7 @@ sidebar_position: 3
## 谁在使用 Hippo4J
共计 14+ 家公司生产接入 Hippo4J。按照公司登记时间排序。
共计 18+ 家公司生产接入 Hippo4J。按照公司登记时间排序。
- [身边云](https://serviceshare.com)
- [Medbanks](https://www.medbanks.cn)
@ -28,3 +28,7 @@ sidebar_position: 3
- [百强国际物流](https://github.com/opengoofy/hippo4j/issues/13)
- [海南某深圳分公司](https://github.com/opengoofy/hippo4j/issues/13)
- [众合云科51社保](https://home.101hr.com/)
- [好货云店](https://pc.haohuoyundian.com/)
- [斗象科技](https://www.tophant.com/)
- [深圳航天信息有限公司](http://sz.aisino.com/)
- [新东方教育科技集团](https://www.xdf.cn/)

@ -2,27 +2,18 @@
sidebar_position: 4
---
# 支持开源
如果您正在使用这个项目并感觉良好,或者是想支持我继续开发,您可以通过如下 `任意` 方式支持我:
1. Github star 并分享动态线程池框架 [hippo4j](https://github.com/longtai-cn/hippo4j) :rocket:
2. 通过以下二维码 一次性捐款。 我多半会买一杯 ~~咖啡~~ 茶。:tea:
如果您正在使用这个项目并感觉良好,或者是想支持我继续开发。通过以下二维码 一次性捐款,我多半会买一杯咖啡或茶~
谢谢! :heart:
> [GitHub](https://github.com/opengoofy/hippo4j) 或 [Gitee](https://gitee.com/agentart/hippo4j) Star 才是最大动力~
| 微信赞赏 | 支付宝 |
| :---: | :---: |
| ![](https://images-machen.oss-cn-beijing.aliyuncs.com/IMG_6719_2.jpg?x-oss-process=image/resize,h_180,w_180) | ![](https://images-machen.oss-cn-beijing.aliyuncs.com/IMG_6720_3.jpg?x-oss-process=image/resize,h_180,w_180) |
### 致谢
![](https://images-machen.oss-cn-beijing.aliyuncs.com/IMG_6719_2.jpg?x-oss-process=image/resize,h_180,w_180)
感谢给予支持的朋友,您的支持是我前进的动力 🎉
| | ID | 赞赏金额 | 时间 | 备注 |
| ---- | ------- | ---- | ---------- | ------------------------------------ |
| 1 | Easy 点 | 66.00 | 2022-04-09 | 好货好技术当加赏 |
|-----| ------- | ---- | ---------- | ------------------------------------ |
| 1 | 六月飞雪 | 30.00 | 2021-12-30 | 代码设计很优雅的一款框架,继续加油! |
| 2 | 孙大圣 | 26.6 | 2022-03-23 | 学习一下😁😁 |
| 3 | 六月飞雪 | 30.00 | 2021-12-30 | 代码设计很优雅的一款框架,继续加油! |
| 3 | Easy 点 | 66.00 | 2022-04-09 | 好货好技术当加赏 |

@ -34,9 +34,9 @@ public class ErrorLogRejectedExecutionHandler implements CustomRejectedExecution
}
```
创建 `src/main/resources/META-INF/services` 目录,创建 SPI 自定义拒绝策略文件 `cn.hippo4j.core.spi.CustomRejectedExecutionHandler`。
创建 `src/main/resources/META-INF/services` 目录,创建 SPI 自定义拒绝策略文件 `cn.hippo4j.common.executor.support.CustomRejectedExecutionHandler`。
`cn.hippo4j.core.spi.CustomRejectedExecutionHandler` 文件内仅放一行自定义拒绝策略全限定名即可,示例:
`cn.hippo4j.common.executor.support.CustomRejectedExecutionHandler` 文件内仅放一行自定义拒绝策略全限定名即可,示例:
```text
cn.hippo4j.example.core.handler.ErrorLogRejectedExecutionHandler
@ -44,7 +44,7 @@ cn.hippo4j.example.core.handler.ErrorLogRejectedExecutionHandler
创建、修改线程池页面选择 `CustomRejectedPolicy自定义 SPI 策略)`
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220801213735751.png)
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220813173907814.png)
拒绝策略触发时,完成上述代码效果,仅打印异常日志提示。

@ -8,32 +8,30 @@ sidebar_position: 0
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220319154626314.png)
### hippo4j-core
### hippo4j-config
**轻量级动态线程池管理**,依赖 Apollo、Nacos、Zookeeper 等三方配置中心(任选其一)完成线程池参数动态变更,支持运行时报警、监控等功能。
> 监控功能配置详见:[线程池监控](/docs/user_docs/getting-started/hippo4j-core-monitor)
![](./img/grafana-monitor.jpg)
![](https://images-machen.oss-cn-beijing.aliyuncs.com/20220814_hippo4j_monitor.jpg)
### hippo4j-server
**部署 hippo4j-server 服务**,通过可视化 Web 界面完成线程池的创建、变更以及查看,不依赖三方中间件。
相比较 hippo4j-core,功能会更强大,但同时也引入了一定的复杂性。需要部署一个 Java 服务,以及依赖 MySQL 数据库。
相比较 hippo4j-config,功能会更强大,但同时也引入了一定的复杂性。需要部署一个 Java 服务,以及依赖 MySQL 数据库。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/1644032018254-min.gif)
### 使用总结
| | hippo4j-core | hippo4j-server |
| | hippo4j-config | hippo4j-server |
| ---- | ---------------------------------------------------- | ------------------------------------------------------------ |
| 依赖 | Nacos、Apollo、Zookeeper 配置中心(任选其一) | 部署 Hippo-4J Server内部无依赖中间件 |
| 使用 | 配置中心补充线程池相关参数 | Hippo-4J Server Web 控制台添加线程池记录 |
| 功能 | 包含基础功能:参数动态化、运行时监控、报警等 | 基础功能之外扩展控制台界面、线程池堆栈查看、线程池运行信息实时查看、历史运行信息查看、线程池配置集群个性化等 |
使用建议:根据公司情况选择,如果基本功能可以满足使用,选择 hippo4j-core 使用即可;如果希望更多的功能,可以选择 hippo4j-server。
使用建议:根据公司情况选择,如果基本功能可以满足使用,选择 hippo4j-config 使用即可;如果希望更多的功能,可以选择 hippo4j-server。
**两者在进行替换的时候,无需修改业务代码**。

@ -10,7 +10,9 @@ Hippo4J 目前已支持的三方框架线程池列表:
- Hystrix
- RabbitMQ
- RocketMQ
- AlibabaDubbo
- RocketMQSpringCloudStream
- RabbitMQSpringCloudStream
引入 Hippo4J Server 或 Core 的 Maven Jar 坐标后,还需要引入对应的框架适配 Jar
@ -19,6 +21,8 @@ Hippo4J 目前已支持的三方框架线程池列表:
<groupId>cn.hippo4j</groupId>
<!-- Dubbo -->
<artifactId>hippo4j-spring-boot-starter-adapter-dubbo</artifactId>
<!-- Alibaba Dubbo -->
<artifactId>hippo4j-spring-boot-starter-adapter-alibaba-dubbo</artifactId>
<!-- Hystrix -->
<artifactId>hippo4j-spring-boot-starter-adapter-hystrix</artifactId>
<!-- RabbitMQ -->
@ -27,7 +31,9 @@ Hippo4J 目前已支持的三方框架线程池列表:
<artifactId>hippo4j-spring-boot-starter-adapter-rocketmq</artifactId>
<!-- SpringCloud Stream RocketMQ -->
<artifactId>hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rocketmq</artifactId>
<version>1.3.1</version>
<!-- SpringCloud Stream RabbitMQ -->
<artifactId>hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rabbitmq</artifactId>
<version>1.4.0-RC</version>
</dependency>
```
@ -37,7 +43,7 @@ Hippo4J 目前已支持的三方框架线程池列表:
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-spring-boot-starter-adapter-all</artifactId>
<version>1.3.1</version>
<version>1.4.0-RC</version>
</dependency>
```
@ -47,9 +53,9 @@ Hippo4J Server 仅需要引入上述 Jar 包,即可在 Hippo4J Server 的控
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220531194810047.png)
## Hippo4J Core
## Hippo4J Config
Hippo4J Core 除了依赖上述适配 Jar 包外,还需要在配置中心添加以下配置项。
Hippo4J Config 除了依赖上述适配 Jar 包外,还需要在配置中心添加以下配置项。
```yaml
spring:

@ -2,9 +2,9 @@
sidebar_position: 2
---
# hippo4j core 线程池监控
# hippo4j config 线程池监控
已完成 hippo4j-core 的 [接入工作](/docs/user_docs/getting-started/hippo4j-core-start) 。
已完成 hippo4j-config 的 [接入工作](/docs/user_docs/getting-started/hippo4j-core-start) 。
## 安装 Grafana + Prometheus
@ -85,4 +85,4 @@ Grafana DashBoard 配置。
即可使用 Hippo4j 线程池监控大屏。
![](./img/grafana-monitor.jpg)
![](https://images-machen.oss-cn-beijing.aliyuncs.com/20220814_hippo4j_monitor.jpg)

@ -2,7 +2,7 @@
sidebar_position: 1
---
# hippo4j core 接入
# hippo4j config 接入
Nacos、Apollo、Zookeeper 配置中心任选其一。
@ -11,8 +11,8 @@ Nacos、Apollo、Zookeeper 配置中心任选其一。
```xml
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-core-spring-boot-starter</artifactId>
<version>1.3.1</version>
<artifactId>hippo4j-config-spring-boot-starter</artifactId>
<version>1.4.0-RC</version>
</dependency>
```
@ -42,54 +42,79 @@ spring:
dynamic:
thread-pool:
enable: true # 是否开启动态线程池
banner: true # 是否打印 banner
collect: true # 是否开启线程池数据采集,对接 Prometheus
notify-platforms: # 通知报警平台,⚠️ 请替换为自己创建的群机器人
- platform: 'WECHAT' # 企业微信
token: 1d307bfa-815f-4662-a2e5-99415e947bb8
- platform: 'DING' # 钉钉
token: 56417ebba6a27ca352f0de77a2ae9da66d01f39610b5ee8a6033c60ef9071c55
secret: SEC40943de20b51e993b47e9a55490a168f1c9e00bdb4f0fb15b1d9e4b58f8b05f3 # 加签
- platform: 'LARK' # 飞书
token: 2cbf2808-3839-4c26-a04d-fd201dd51f9e
nacos: # nacos apollo 任选其一
# 是否开启动态线程池
enable: true
# 是否打印 banner
banner: true
# 是否开启线程池数据采集,对接 Prometheus、ES、Log 等
collect: true
# 检查线程池状态,是否达到报警条件,单位毫秒
check-state-interval: 3000
# 通知报警平台,请替换为自己创建的群机器人
notify-platforms:
- platform: 'WECHAT'
token: xxx
- platform: 'DING'
token: xxx
secret: xxx # 加签专属
- platform: 'LARK'
token: xxx
# nacos apollo、zookeeper 任选其一
nacos:
data-id: xxx
group: xxx
apollo:
namespace: xxxx
config-file-type: yml # 配置中心文件格式
# tomcat:
# jetty:
undertow: # 三种容器线程池,任选其一
# 配置中心文件格式
config-file-type: yml
# tomcat、undertow、jetty 三种容器线程池,任选其一
undertow:
core-pool-size: 100
maximum-pool-size: 200
keep-alive-time: 1000
# 全局通知配置
alarm: true # 是否报警
check-state-interval: 3000 # 检查线程池状态,是否达到报警条件,单位毫秒
active-alarm: 80 # 活跃度报警阈值;假设线程池最大线程数 10当线程数达到 8 发起报警
capacity-alarm: 80 # 容量报警阈值;假设阻塞队列容量 100当容量达到 80 发起报警
alarm-interval: 8 # 报警间隔,同一线程池下同一报警纬度,在 interval 时间内只会报警一次,单位秒
receive: xxx # 企业微信填写用户 ID填写其它将无法达到 @ 效果)、钉钉填手机号、飞书填 ou_ 开头唯一 ID
# 线程池配置
# 全局通知配置-是否报警
alarm: true
# 活跃度报警阈值;假设线程池最大线程数 10当线程数达到 8 发起报警
active-alarm: 80
# 容量报警阈值;假设阻塞队列容量 100当容量达到 80 发起报警
capacity-alarm: 80
# 报警间隔,同一线程池下同一报警纬度,在 interval 时间内只会报警一次,单位秒
alarm-interval: 8
# 企业微信填写用户 ID填写其它将无法达到 @ 效果)、钉钉填手机号、飞书填 ou_ 开头唯一 ID
receives: xxx
# 动态线程池列表
executors:
- thread-pool-id: 'message-consume' # 线程池标识
core-pool-size: 1 # 核心线程数
maximum-pool-size: 1 # 最大线程数
queue-capacity: 1 # 阻塞队列大小
execute-time-out: 1000 # 执行超时时间,超过此时间发起报警
blocking-queue: 'LinkedBlockingQueue' # 阻塞队列名称,参考 QueueTypeEnum支持 SPI
rejected-handler: 'AbortPolicy' # 拒绝策略名称,参考 RejectedPolicies支持 SPI
keep-alive-time: 1024 # 线程存活时间,单位秒
allow-core-thread-time-out: true # 是否允许核心线程超时
thread-name-prefix: 'message-consume' # 线程名称前缀
notify: # 通知配置,线程池中通知配置如果存在,则会覆盖全局通知配置
is-alarm: true # 是否报警
active-alarm: 80 # 活跃度报警阈值;假设线程池最大线程数 10当线程数达到 8 发起报警
capacity-alarm: 80 # 容量报警阈值;假设阻塞队列容量 100当容量达到 80 发起报警
interval: 8 # 报警间隔,同一线程池下同一报警纬度,在 interval 时间内只会报警一次,单位分钟
receive: xxx # 企业微信填写用户 ID填写其它将无法达到 @ 效果)、钉钉填手机号、飞书填 ou_ 开头唯一 ID
- thread-pool-id: 'message-consume'
# 核心线程数
core-pool-size: 1
# 最大线程数
maximum-pool-size: 1
# 阻塞队列名称,参考 BlockingQueueTypeEnum支持 SPI
blocking-queue: 'LinkedBlockingQueue'
# 阻塞队列大小
queue-capacity: 1
# 执行超时时间,超过此时间发起报警,单位毫秒
execute-time-out: 1000
# 拒绝策略名称,参考 RejectedPolicyTypeEnum支持 SPI
rejected-handler: 'AbortPolicy'
# 线程存活时间,单位秒
keep-alive-time: 1024
# 是否允许核心线程超时
allow-core-thread-time-out: true
# 线程工厂名称前缀
thread-name-prefix: 'message-consume'
# 是否报警
alarm: true
# 活跃度报警阈值;假设线程池最大线程数 10当线程数达到 8 发起报警
active-alarm: 80
# 容量报警阈值;假设阻塞队列容量 100当容量达到 80 发起报警
capacity-alarm: 80
# 通知配置,线程池中通知配置如果存在,则会覆盖全局通知配置
notify:
# 报警间隔,同一线程池下同一报警纬度,在 interval 时间内只会报警一次,单位分钟
interval: 8
# 企业微信填写用户 ID填写其它将无法达到 @ 效果)、钉钉填手机号、飞书填 ou_ 开头唯一 ID
receives: xxx
- thread-pool-id: 'message-produce'
core-pool-size: 1
maximum-pool-size: 1
@ -100,12 +125,12 @@ spring:
keep-alive-time: 1024
allow-core-thread-time-out: true
thread-name-prefix: 'message-consume'
notify:
is-alarm: true
alarm: true
active-alarm: 80
capacity-alarm: 80
notify:
interval: 8
receive: xxx
receives: xxx
```
## ThreadPoolExecutor 适配

@ -22,7 +22,7 @@ SpringBoot Pom 引入 Hippo4j Starter Jar。
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-spring-boot-starter</artifactId>
<version>1.3.1</version>
<version>1.4.0-RC</version>
</dependency>
```

@ -42,7 +42,7 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
感谢所有为 Hippo-4J 做出贡献的开发者!
<a href="https://github.com/opengoofy/hippo4j/graphs/contributors"><img src="https://contrib.rocks/image?repo=opengoofy/hippo4j"/></a>
<a href="https://github.com/opengoofy/hippo4j/graphs/contributors"><img src="https://opencollective.com/hippo4j/contributors.svg?width=890&button=false"/></a>
## 我们的荣誉
@ -56,8 +56,13 @@ Hippo-4J 获得了一些宝贵的荣誉,这属于每一位对 Hippo-4J 做出
## 友情链接
- [HertzBeat](https://github.com/dromara/hertzbeat):易用友好的云监控系统, 无需Agent, 强大自定义监控能力。
- [toBeBetterJavaer](https://github.com/itwanger/toBeBetterJavaer)一份通俗易懂、风趣幽默的Java学习指南内容涵盖Java基础、Java并发编程等核心知识点。
- [[ Sa-Token ]](https://github.com/dromara/sa-token):一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!
- [[ HertzBeat ]](https://github.com/dromara/hertzbeat):易用友好的云监控系统, 无需 Agent, 强大自定义监控能力。
- [[ JavaGuide ]](https://github.com/Snailclimb/JavaGuide):一份涵盖大部分 Java 程序员所需要掌握的核心知识。
- [[ toBeBetterJavaer ]](https://github.com/itwanger/toBeBetterJavaer)一份通俗易懂、风趣幽默的Java学习指南内容涵盖Java基础、Java并发编程等核心知识点。
## 鸣谢

@ -4,8 +4,7 @@ sidebar_position: 1
# hippo4j server 部署
[RELEASE](https://github.com/longtai-cn/hippo4j/releases) 页面下载对应版本并进行解压。
[RELEASE](https://github.com/opengoofy/hippo4j/releases) 页面下载对应版本并进行解压。
## 初始化
@ -15,12 +14,14 @@ sidebar_position: 1
/conf/application.properties
```
数据库执行 SQL 脚本。
如果是新运行 Hippo-4J数据库执行下述 SQL 脚本即可
```txt
/conf/hippo4j_manager.sql
```
如果是对已运行 Hippo-4J 升级,请查看 `/conf/sql-upgrade` 目录下,是否有目标版本对应的升级脚本。
## 直接运行
Mac Linux 启动执行。

@ -0,0 +1,51 @@
---
sidebar_position: 2
---
# docker hippo4j server 构建
可以通过以下命令快速构建 Hippo4J Server
方式一:
```shell
# 进入到 hippo4j-server 工程路径下
mvn clean package
# 默认打包是打包的 tag 是 latest
docker build -t hippo4j-server ../hippo4j-server
```
方式二:
通过 `maven docker plugin`
```shell
# 进入到 hippo4j-server 工程路径下
mvn clean package -DskipTests docker:build
```
## Docker 镜像方式搭建 Hippo4J Server
- 下载镜像
```shell
# Docker地址https://hub.docker.com/r/xxxx/hippo4j-server/(建议指定版本号)
docker pull hippo4j-server
```
- 创建容器并运行
```shell
docker run -p 6691:6691 --name hippo4j-server -d hippo4j-server:{指定版本}
/**
* 暂时只暴露以下参数
* MYSQL_HOST、MYSQL_PORT、MYSQL_DB、MYSQL_USERNAME、MYSQL_PASSWORD
*/
docker run -p 6691:6691 --name hippo4j-server \
-e MYSQL_HOST=127.0.0.1 \
-e MYSQL_PORT=3306 \
-e MYSQL_DB=hippo4j_manager \
-e MYSQL_USERNAME=root \
-e MYSQL_PASSWORD=mysql \
-d hippo4j-server
```

@ -4,8 +4,8 @@ sidebar_position: 2
# 常见问题
- <a href="#租户和项目在-hippo4j-中是什么意思">租户和项目在 Hippo4J 中是什么意思</a>
- <a href="#控制台线程池管理和线程池实例的区别">控制台线程池管理和线程池实例的区别</a>
- <a href="#示例项目为什么会有跨域请求">示例项目为什么会有跨域请求</a>
- <a href="#更新代码后运行时服务端sql报错">更新代码后运行时服务端SQL报错</a>
- <a href="#okhttp3-call-timeout-方法不存在">okHttp3 call.timeout() 方法不存在</a>
@ -22,6 +22,13 @@ Hippo4J 按照租户、项目、线程池的维度划分。
举个例子,小编在一家公司的公共组件团队,团队中负责消息、短链接网关等项目。公共组件是租户,消息或短链接就是项目。
## 控制台线程池管理和线程池实例的区别
在线程池管理中修改线程池参数,客户端并不能实时感知到并变更参数,需要重启客户端。而线程池实例中去对具体的实例修改参数时,客户端无需重启,可以实时感知到参数变化。如果二者针对同一线程
池的参数配置不同,则在重启客户端时,客户端会去拉去线程池管理中的参数配置。
二者对应的定位:线程池管理中的配置是常态化配置。而线程池实例里的配置变更像是一种临时修改,比如突发的流量激增等场景,并不具备普适性。
## 示例项目为什么会有跨域请求
~~正常大家在部署时,服务端项目和客户端都在同一网络下,进行内网通信,是没有问题的。~~
@ -80,15 +87,10 @@ Hippo4J 发布时可能会涉及到两端发布,分别是 Server 和 Starter
重启客户端项目,会重新拉取最新报警推送配置,问题解决。
## 设置线程池参数优先级问题
- 当使用 `@DynamicThreadPool` 进行修饰的方法中和在管理界面设置中同时存在的话,则管理界面设置的优先级最高;
- 如果连接service端失败的话使用`@DynamicThreadPool`进行修饰设置的优先级最高。
- 如果连接 server 端失败的话,使用 `@DynamicThreadPool` 进行修饰设置的优先级最高。
## 线程池实例中修改队列容量参数问题
在线程池管理中添加时,只有当选择队列类型为 `ResizableCapacityLinkedBlockingQueue` 时,后续再进行修改容量大小时才会实时的刷新修改成功。
## 动态线程池中线程池管理和线程池实例的区别
在线程池管理中修改线程池参数,客户端并不能实时感知到并变更参数,需要重启客户端。而线程池实例中去对具体的实例修改参数时,客户端无需重启,可以实时感知到参数变化。如果二者针对同一线程
池的参数配置不同,则在重启客户端时,客户端会去拉去线程池管理中的参数配置。
二者对应的定位:线程池管理中的配置是常态化配置。而线程池实例里的配置变更像是一种临时修改,比如突发的流量激增等场景,并不具备普适性。

@ -38,15 +38,6 @@ Client 端指的是我们 SpringBoot 应用,通过引入 Hippo4J Starter Jar
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20211107122504126.png)
### 抽象工具Tools
顾名思义就是将某些工具单独抽象出来,并以 Module 的形式进行展现,这样的拆分方式有两点好处:**一是更符合职责分离特性,二是需要用到某块功能**,做到拿来即用。
log-record-tool基于 [mzt-biz-log](https://github.com/mouzt/mzt-biz-log "mzt-biz-log") 的操作日志变更记录组件。
## 消息通知Notify
Hippo4J 内置了很多需要通知的事件,比如:线程池参数变更通知、线程池活跃度报警、拒绝策略执行报警以及阻塞队列容量报警等。

@ -5,7 +5,8 @@ sidebar_position: 3
# 快速开始
:::tip
Hippo4J 支持两种运行模式依赖配置中心Hippo4J-Core或 Hippo4J Server下文描述接入 Hippo4J Server[Hippo4J-Core 接入参考此处](/docs/user_docs/getting-started/hippo4j-core-start.md) 。
Hippo4J 支持两种运行模式依赖配置中心Hippo4J-Config或 Hippo4J Server下文描述接入 Hippo4J
Server[Hippo4J-Config 接入参考此处](/docs/user_docs/getting-started/hippo4j-core-start.md) 。
:::
## 如何运行 Demo
@ -14,49 +15,27 @@ Clone Hippo4J [源代码](https://github.com/longtai-cn/hippo4j),导入初始
1. 导入 [Hippo4J 初始化 SQL 语句](https://github.com/longtai-cn/hippo4j/blob/develop/hippo4j-server/conf/hippo4j_manager.sql)
2. 启动 [Hippo4J-Server](https://github.com/longtai-cn/hippo4j/tree/develop/hippo4j-server) 模块下 ServerApplication 应用类;
3. 启动 [Hippo4J-spring-boot-starter-example](https://github.com/opengoofy/hippo4j/tree/develop/hippo4j-example/hippo4j-spring-boot-starter-example) 模块下 Hippo4JServerExampleApplication 应用类;
通过接口修改线程池中的配置。HTTP POST 路径:`http://localhost:6691/hippo4j/v1/cs/configs`Body 请求体如下:
```json
{
"ignore": "tenantId、itemId、tpId 代表唯一线程池,请不要修改",
"tenantId": "prescription",
"itemId": "dynamic-threadpool-example",
"tpId": "message-produce",
"coreSize": 10,
"maxSize": 15,
"queueType": 9,
"capacity": 100,
"keepAliveTime": 10,
"rejectedType": 3,
"isAlarm": 0,
"capacityAlarm": 90,
"livenessAlarm": 90
}
```
接口调用成功后,观察 Hippo4j-Example 控制台日志输出,日志输出包括不限于此信息即为成功。
3. 启动 [hippo4J-spring-boot-starter-example](https://github.com/opengoofy/hippo4j/tree/develop/hippo4j-example/hippo4j-spring-boot-starter-example) 模块下 Hippo4JServerExampleApplication 应用类。
```tex
[🔥 MESSAGE-PRODUCE] Changed thread pool.
coreSize :: [2 => 10], maxSize :: [10 => 15], queueType :: [ArrayBlockingQueue => ResizableCapacityLinkedBlockIngQueue], capacity :: [200 => 200], keepAliveTime :: [25 => 10], rejectedType :: [AbortPolicy => DiscardPolicy]
```
:::tip
也可以通过 Server 控制台访问,路径:`http://localhost:6691/index.html`。
通过 Server 控制台访问,路径:`http://localhost:6691/index.html#/hippo4j/dynamic/thread-pool/instance`。
默认用户名密码admin / 123456
:::
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220813173811668.png)
另外,当 Client 集群部署时,可以选择修改所有实例或某一实例
修改相关参数, 观察 Hippo4j-Example 控制台日志输出,日志输出包括不限于此信息即为成功。
修改请求路径:`http://localhost:6691/hippo4j/v1/cs/configs?identify=xxx`Body 体同上。
```tex
2022-08-13 21:26:25.814 INFO 38972 --- [change.config-5] c.h.s.s.c.ServerThreadPoolDynamicRefresh : [message-consume] Dynamic thread pool change parameter.
corePoolSize: [5 => 5]
maximumPoolSize: [6 => 7]
capacity: [10 => 10]
keepAliveTime: [3 => 3]
executeTimeOut: [0 => 0]
rejectedType: [CustomErrorLogRejectedExecutionHandler => CustomErrorLogRejectedExecutionHandler]
allowCoreThreadTimeOut: [false => false]
```
`identify`:代表客户端唯一标识,参数不传或为空,会修改该线程池 Client 集群下所有线程池实例参数。
另外,当 Client 集群部署时,可以修改某一个实例,或选择 `全部修改` 按钮,修改所有实例线程池信息。
线程池参数动态变更通知,或线程池运行时报警,详情参考 [通知报警](/docs/user_docs/user_guide/alarm.md)。

@ -6,7 +6,7 @@ const darkCodeTheme = require('prism-react-renderer/themes/dracula');
/** @type {import('@docusaurus/types').Config} */
const config = {
title: 'HIPPO-4J 文档',
title: 'HIPPO-4J',
tagline: '动态可观测线程池框架,为业务系统提高线上运行保障能力',
url: 'https://hippo4j.cn',
baseUrl: '/',
@ -64,7 +64,7 @@ const config = {
// content: `<a target="_blank" rel="noopener noreferrer" href="https://xiaomage.info/knowledge-planet/">👉 《小马哥的代码实战课》官方知识星球来啦!!!</a>`,
},
navbar: {
title: '4J',
title: 'HIPPO-4J',
logo: {
alt: 'HIPPO-4J 动态可观测线程池框架',
src: 'img/web.png',
@ -84,27 +84,19 @@ const config = {
sidebarId: 'community',
label: '社区',
},
{to: '/blog', label: '博客', position: 'left'},
/*{
type: 'docSidebar',
docId: 'intro',
position: 'left',
sidebarId: 'sponsor',
hideable: true,
label: '支持开源',
},*/
{
href: 'https://xiaomage.info/knowledge-planet',
label: '🥇知识星球',
position: 'right',
},
/* 国际化 */
/*{type: 'localeDropdown', position: 'right'},*/
/*{to: '/blog', label: '博客', position: 'left'},*/
{
href: 'http://console.hippo4j.cn/index.html',
label: '控制台样例',
position: 'right',
position: 'left',
},
{
href: 'https://xiaomage.info/knowledge-planet',
label: '🥇代码实战课',
position: 'left',
},
{type: 'localeDropdown', position: 'right'},
/*{
href: 'https://gitee.com/mabaiwancn/hippo4j',
label: 'Gitee',

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-adapter</artifactId>
<version>${revision}</version>
</parent>
<artifactId>hippo4j-adapter-alibaba-dubbo</artifactId>
<properties>
<alibaba-dubbo.version>2.6.12</alibaba-dubbo.version>
</properties>
<dependencies>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-adapter-base</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>${alibaba-dubbo.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Implementation-Title>${project.artifactId}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Build-Time>${maven.build.timestamp}</Build-Time>
<Built-By>chen.ma</Built-By>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,102 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.adapter.alibaba.dubbo;
import cn.hippo4j.adapter.base.ThreadPoolAdapter;
import cn.hippo4j.adapter.base.ThreadPoolAdapterParameter;
import cn.hippo4j.adapter.base.ThreadPoolAdapterState;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
import com.alibaba.dubbo.common.store.DataStore;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import static cn.hippo4j.common.constant.ChangeThreadPoolConstants.CHANGE_DELIMITER;
/**
* Alibaba Dubbo thread-pool adapter.
*/
@Slf4j
public class AlibabaDubboThreadPoolAdapter implements ThreadPoolAdapter, ApplicationListener<ApplicationStartedEvent> {
private final Map<String, ThreadPoolExecutor> DUBBO_PROTOCOL_EXECUTOR = Maps.newHashMap();
@Override
public String mark() {
return "AlibabaDubbo";
}
@Override
public ThreadPoolAdapterState getThreadPoolState(String identify) {
ThreadPoolAdapterState threadPoolAdapterState = new ThreadPoolAdapterState();
ThreadPoolExecutor executor = DUBBO_PROTOCOL_EXECUTOR.get(identify);
if (executor == null) {
log.warn("[{}] Alibaba Dubbo consuming thread pool not found.", identify);
return threadPoolAdapterState;
}
threadPoolAdapterState.setThreadPoolKey(identify);
threadPoolAdapterState.setCoreSize(executor.getCorePoolSize());
threadPoolAdapterState.setMaximumSize(executor.getMaximumPoolSize());
return threadPoolAdapterState;
}
@Override
public List<ThreadPoolAdapterState> getThreadPoolStates() {
List<ThreadPoolAdapterState> threadPoolAdapterStates = new ArrayList<>();
DUBBO_PROTOCOL_EXECUTOR.forEach((kel, val) -> threadPoolAdapterStates.add(getThreadPoolState(String.valueOf(val))));
return threadPoolAdapterStates;
}
@Override
public boolean updateThreadPool(ThreadPoolAdapterParameter threadPoolAdapterParameter) {
String threadPoolKey = threadPoolAdapterParameter.getThreadPoolKey();
ThreadPoolExecutor executor = DUBBO_PROTOCOL_EXECUTOR.get(threadPoolAdapterParameter.getThreadPoolKey());
if (executor == null) {
log.warn("[{}] Alibaba Dubbo consuming thread pool not found.", threadPoolKey);
return false;
}
int originalCoreSize = executor.getCorePoolSize();
int originalMaximumPoolSize = executor.getMaximumPoolSize();
executor.setCorePoolSize(threadPoolAdapterParameter.getCorePoolSize());
executor.setMaximumPoolSize(threadPoolAdapterParameter.getMaximumPoolSize());
log.info("[{}] Alibaba Dubbo consumption thread pool parameter change. coreSize: {}, maximumSize: {}",
threadPoolKey,
String.format(CHANGE_DELIMITER, originalCoreSize, executor.getCorePoolSize()),
String.format(CHANGE_DELIMITER, originalMaximumPoolSize, executor.getMaximumPoolSize()));
return true;
}
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
String poolKey = ExecutorService.class.getName();
try {
DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
Map<String, Object> executors = dataStore.get(poolKey);
executors.forEach((key, value) -> DUBBO_PROTOCOL_EXECUTOR.put(key, (ThreadPoolExecutor) value));
} catch (Exception ex) {
log.error("Failed to get Alibaba Dubbo protocol thread pool", ex);
}
}
}

@ -48,12 +48,7 @@ public class RabbitMQThreadPoolAdapter implements ThreadPoolAdapter, Application
private static final String FiledName = "executorService";
/**
* TODO Configurable name
*/
private static final String RABBITMQ_EXECUTOR_SERVICE = "Rabbitmq_Executor_Service";
private final AbstractConnectionFactory abstractConnectionFactory;
private final Map<String, AbstractConnectionFactory> abstractConnectionFactoryMap;
private final Map<String, ThreadPoolExecutor> RABBITMQ_THREAD_POOL_TASK_EXECUTOR = Maps.newHashMap();
@ -103,15 +98,18 @@ public class RabbitMQThreadPoolAdapter implements ThreadPoolAdapter, Application
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
ExecutorService executor = (ExecutorService) ReflectUtil.getFieldValue(abstractConnectionFactory, FiledName);
abstractConnectionFactoryMap.forEach((beanName, abstractConnectionFactor) -> {
ExecutorService executor = (ExecutorService) ReflectUtil.getFieldValue(abstractConnectionFactor, FiledName);
if (Objects.nonNull(executor)) {
if (executor instanceof ThreadPoolExecutor) {
ThreadPoolExecutor threadPoolTaskExecutor = (ThreadPoolExecutor) executor;
RABBITMQ_THREAD_POOL_TASK_EXECUTOR.put(RABBITMQ_EXECUTOR_SERVICE, threadPoolTaskExecutor);
log.info("Rabbitmq executor name {}", RABBITMQ_EXECUTOR_SERVICE);
RABBITMQ_THREAD_POOL_TASK_EXECUTOR.put(beanName, threadPoolTaskExecutor);
log.info("Rabbitmq executor name {}", beanName);
} else {
log.warn("Custom thread pools only support ThreadPoolExecutor");
}
}
});
}
}

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-adapter</artifactId>
<version>${revision}</version>
</parent>
<artifactId>hippo4j-adapter-spring-cloud-stream-rabbitmq</artifactId>
<dependencies>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-adapter-base</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
<version>${spring-cloud-starter-stream-rabbitmq.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Implementation-Title>${project.artifactId}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Build-Time>${maven.build.timestamp}</Build-Time>
<Built-By>chen.ma</Built-By>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,163 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.adapter.springcloud.stream.rabbitmq;
import cn.hippo4j.adapter.base.ThreadPoolAdapter;
import cn.hippo4j.adapter.base.ThreadPoolAdapterParameter;
import cn.hippo4j.adapter.base.ThreadPoolAdapterState;
import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hippo4j.common.toolkit.CollectionUtil;
import cn.hippo4j.common.toolkit.ReflectUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.DirectMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.cloud.stream.binder.Binding;
import org.springframework.cloud.stream.binder.DefaultBinding;
import org.springframework.cloud.stream.binding.InputBindingLifecycle;
import org.springframework.context.ApplicationListener;
import org.springframework.integration.amqp.inbound.AmqpInboundChannelAdapter;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import static cn.hippo4j.common.constant.ChangeThreadPoolConstants.CHANGE_DELIMITER;
/**
* Spring cloud stream rabbimq thread-pool adapter.
*/
@Slf4j
public class SpringCloudStreamRabbitMQThreadPoolAdapter implements ThreadPoolAdapter, ApplicationListener<ApplicationStartedEvent> {
private final Map<String, AbstractMessageListenerContainer> ROCKET_MQ_SPRING_CLOUD_STREAM_CONSUME_EXECUTOR = Maps.newHashMap();
@Override
public String mark() {
return "RabbitMQSpringCloudStream";
}
@Override
public ThreadPoolAdapterState getThreadPoolState(String identify) {
ThreadPoolAdapterState result = new ThreadPoolAdapterState();
AbstractMessageListenerContainer messageListenerContainer = ROCKET_MQ_SPRING_CLOUD_STREAM_CONSUME_EXECUTOR.get(identify);
if (messageListenerContainer != null) {
result.setThreadPoolKey(identify);
if (messageListenerContainer instanceof SimpleMessageListenerContainer) {
int concurrentConsumers = (int) ReflectUtil.getFieldValue(messageListenerContainer, "concurrentConsumers");
result.setCoreSize(concurrentConsumers);
Object maxConcurrentConsumers = ReflectUtil.getFieldValue(messageListenerContainer, "maxConcurrentConsumers");
if (maxConcurrentConsumers != null) {
result.setMaximumSize((Integer) maxConcurrentConsumers);
} else {
result.setMaximumSize(concurrentConsumers);
}
} else if (messageListenerContainer instanceof DirectMessageListenerContainer) {
int consumersPerQueue = (int) ReflectUtil.getFieldValue(messageListenerContainer, "consumersPerQueue");
result.setCoreSize(consumersPerQueue);
result.setMaximumSize(consumersPerQueue);
}
return result;
}
log.warn("[{}] RabbitMQ consuming thread pool not found.", identify);
return result;
}
@Override
public List<ThreadPoolAdapterState> getThreadPoolStates() {
List<ThreadPoolAdapterState> adapterStateList = Lists.newArrayList();
ROCKET_MQ_SPRING_CLOUD_STREAM_CONSUME_EXECUTOR.forEach(
(key, val) -> adapterStateList.add(getThreadPoolState(key)));
return adapterStateList;
}
@Override
public boolean updateThreadPool(ThreadPoolAdapterParameter threadPoolAdapterParameter) {
String threadPoolKey = threadPoolAdapterParameter.getThreadPoolKey();
AbstractMessageListenerContainer messageListenerContainer = ROCKET_MQ_SPRING_CLOUD_STREAM_CONSUME_EXECUTOR.get(threadPoolKey);
if (messageListenerContainer != null) {
synchronized (ROCKET_MQ_SPRING_CLOUD_STREAM_CONSUME_EXECUTOR) {
Integer corePoolSize = threadPoolAdapterParameter.getCorePoolSize();
Integer maximumPoolSize = threadPoolAdapterParameter.getMaximumPoolSize();
if (messageListenerContainer instanceof SimpleMessageListenerContainer) {
int originalCoreSize = (int) ReflectUtil.getFieldValue(messageListenerContainer, "concurrentConsumers");
Object maxConcurrentConsumers = ReflectUtil.getFieldValue(messageListenerContainer, "maxConcurrentConsumers");
int originalMaximumPoolSize;
if (maxConcurrentConsumers != null) {
originalMaximumPoolSize = (Integer) maxConcurrentConsumers;
} else {
originalMaximumPoolSize = originalCoreSize;
}
SimpleMessageListenerContainer simpleMessageListenerContainer = (SimpleMessageListenerContainer) messageListenerContainer;
if (originalCoreSize > maximumPoolSize) {
simpleMessageListenerContainer.setConcurrentConsumers(corePoolSize);
simpleMessageListenerContainer.setMaxConcurrentConsumers(maximumPoolSize);
} else {
simpleMessageListenerContainer.setMaxConcurrentConsumers(maximumPoolSize);
simpleMessageListenerContainer.setConcurrentConsumers(corePoolSize);
}
log.info("[{}] RabbitMQ consumption thread pool parameter change. coreSize: {}, maximumSize: {}",
threadPoolKey,
String.format(CHANGE_DELIMITER, originalCoreSize, corePoolSize),
String.format(CHANGE_DELIMITER, originalMaximumPoolSize, maximumPoolSize));
} else if (messageListenerContainer instanceof DirectMessageListenerContainer) {
int originalCoreSize = (int) ReflectUtil.getFieldValue(messageListenerContainer, "consumersPerQueue");
DirectMessageListenerContainer directMessageListenerContainer = (DirectMessageListenerContainer) messageListenerContainer;
directMessageListenerContainer.setConsumersPerQueue(maximumPoolSize);
log.info("[{}] RabbitMQ consumption thread pool parameter change. coreSize: {}",
threadPoolKey,
String.format(CHANGE_DELIMITER, originalCoreSize, corePoolSize));
} else {
log.warn("[{}] RabbitMQ consuming thread pool not support. messageListenerContainer: {}", threadPoolKey, messageListenerContainer.getClass());
return false;
}
}
return true;
}
log.warn("[{}] RabbitMQ consuming thread pool not found.", threadPoolKey);
return false;
}
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
InputBindingLifecycle bindingLifecycle = ApplicationContextHolder.getBean(InputBindingLifecycle.class);
Collection<Binding<Object>> inputBindings = Optional.ofNullable(ReflectUtil.getFieldValue(bindingLifecycle, "inputBindings"))
.map(each -> (Collection<Binding<Object>>) each).orElse(null);
if (CollectionUtil.isEmpty(inputBindings)) {
log.info("InputBindings record not found.");
return;
}
try {
for (Binding<Object> each : inputBindings) {
String bindingName = each.getBindingName();
DefaultBinding defaultBinding = (DefaultBinding) each;
Object lifecycle = ReflectUtil.getFieldValue(defaultBinding, "lifecycle");
if (lifecycle instanceof AmqpInboundChannelAdapter) {
AbstractMessageListenerContainer rabbitMQListenerContainer = (AbstractMessageListenerContainer) ReflectUtil.getFieldValue(lifecycle, "messageListenerContainer");
ROCKET_MQ_SPRING_CLOUD_STREAM_CONSUME_EXECUTOR.put(bindingName, rabbitMQListenerContainer);
}
}
} catch (Exception ex) {
log.error("Failed to get input-bindings thread pool.", ex);
}
}
}

@ -27,7 +27,7 @@ import cn.hippo4j.core.executor.DynamicThreadPoolExecutor;
import cn.hutool.core.date.DateUtil;
import io.undertow.Undertow;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.embedded.undertow.UndertowWebServer;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServer;
import org.springframework.boot.web.server.WebServer;
import org.springframework.util.ReflectionUtils;
import org.xnio.Options;
@ -50,11 +50,12 @@ public class UndertowWebThreadPoolHandler extends AbstractWebThreadPoolService {
@Override
protected Executor getWebThreadPoolByServer(WebServer webServer) {
// There is no need to consider reflection performance because the fetch is a singleton.
UndertowWebServer undertowWebServer = (UndertowWebServer) webServer;
Field undertowField = ReflectionUtils.findField(UndertowWebServer.class, UNDERTOW_NAME);
// Springboot 2-3 version, can directly through reflection to obtain the undertow property
UndertowServletWebServer undertowServletWebServer = (UndertowServletWebServer) webServer;
Field undertowField = ReflectionUtils.findField(UndertowServletWebServer.class, UNDERTOW_NAME);
ReflectionUtils.makeAccessible(undertowField);
Undertow undertow = (Undertow) ReflectionUtils.getField(undertowField, undertowWebServer);
Undertow undertow = (Undertow) ReflectionUtils.getField(undertowField, undertowServletWebServer);
return Objects.isNull(undertow) ? null : undertow.getWorker();
}

@ -13,12 +13,14 @@
<modules>
<module>hippo4j-adapter-base</module>
<module>hippo4j-adapter-dubbo</module>
<module>hippo4j-adapter-alibaba-dubbo</module>
<module>hippo4j-adapter-kafka</module>
<module>hippo4j-adapter-rabbitmq</module>
<module>hippo4j-adapter-rocketmq</module>
<module>hippo4j-adapter-hystrix</module>
<module>hippo4j-adapter-spring-cloud-stream-rocketmq</module>
<module>hippo4j-adapter-spring-cloud-stream-kafka</module>
<module>hippo4j-adapter-spring-cloud-stream-rabbitmq</module>
<module>hippo4j-adapter-web</module>
</modules>
</project>

@ -102,7 +102,7 @@ public class GlobalSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
String[] ignores = Stream.of("/hippo4j/v1/cs/auth/users/apply/token/**", "/hippo4j/v1/cs/configs/**").toArray(String[]::new);
String[] ignores = Stream.of("/hippo4j/v1/cs/auth/users/apply/token/**").toArray(String[]::new);
web.ignoring().antMatchers(ignores);
}
}

@ -14,7 +14,6 @@
<spring-web.version>5.2.15.RELEASE</spring-web.version>
<spring-beans.version>5.2.21.RELEASE</spring-beans.version>
<spring-core.version>5.2.22.RELEASE</spring-core.version>
<jackson-databind.version>2.12.6.1</jackson-databind.version>
</properties>
<dependencies>
@ -45,7 +44,6 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind.version}</version>
</dependency>
<dependency>
@ -72,6 +70,12 @@
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>

@ -17,6 +17,8 @@
package cn.hippo4j.common.api;
import com.fasterxml.jackson.core.type.TypeReference;
import java.util.List;
/**
@ -42,6 +44,16 @@ public interface JsonFacade {
*/
<T> T parseObject(String text, Class<T> clazz);
/**
* Parse object.
*
* @param text
* @param valueTypeRef
* @param <T>
* @return
*/
<T> T parseObject(String text, TypeReference<T> valueTypeRef);
/**
* Parse array.
*

@ -22,15 +22,20 @@ package cn.hippo4j.common.constant;
*/
public class ChangeThreadPoolConstants {
public static final String CHANGE_THREAD_POOL_TEXT = "Dynamic thread pool change parameter: [{}]" +
/**
* Dynamic thread pool parameter change text
*/
public static final String CHANGE_THREAD_POOL_TEXT = "[{}] Dynamic thread pool change parameter." +
"\n corePoolSize: [{}]" +
"\n maximumPoolSize: [{}]" +
"\n blockingQueueType: [{}]" +
"\n capacity: [{}]" +
"\n keepAliveTime: [{}]" +
"\n executeTimeOut: [{}]" +
"\n rejectedType: [{}]" +
"\n allowCoreThreadTimeOut: [{}]";
/**
* Dynamic thread pool parameter change separator
*/
public static final String CHANGE_DELIMITER = "%s => %s";
}

@ -15,10 +15,10 @@
* limitations under the License.
*/
package cn.hippo4j.core.executor.support;
package cn.hippo4j.common.executor.support;
import cn.hippo4j.core.spi.CustomBlockingQueue;
import cn.hippo4j.core.spi.DynamicThreadPoolServiceLoader;
import cn.hippo4j.common.spi.DynamicThreadPoolServiceLoader;
import lombok.Getter;
import java.util.Arrays;
import java.util.Collection;
@ -28,9 +28,9 @@ import java.util.concurrent.*;
import java.util.stream.Stream;
/**
* Queue type enum.
* Blocking queue type enum.
*/
public enum QueueTypeEnum {
public enum BlockingQueueTypeEnum {
/**
* {@link java.util.concurrent.ArrayBlockingQueue}
@ -67,11 +67,13 @@ public enum QueueTypeEnum {
*/
RESIZABLE_LINKED_BLOCKING_QUEUE(9, "ResizableCapacityLinkedBlockingQueue");
public Integer type;
@Getter
private Integer type;
public String name;
@Getter
private String name;
QueueTypeEnum(int type, String name) {
BlockingQueueTypeEnum(int type, String name) {
this.type = type;
this.name = name;
}
@ -82,7 +84,7 @@ public enum QueueTypeEnum {
public static BlockingQueue createBlockingQueue(String blockingQueueName, Integer capacity) {
BlockingQueue blockingQueue = null;
QueueTypeEnum queueTypeEnum = Stream.of(QueueTypeEnum.values())
BlockingQueueTypeEnum queueTypeEnum = Stream.of(BlockingQueueTypeEnum.values())
.filter(each -> Objects.equals(each.name, blockingQueueName))
.findFirst()
.orElse(null);
@ -105,7 +107,6 @@ public enum QueueTypeEnum {
if (capacity == null || capacity <= 0) {
temCapacity = 1024;
}
return new LinkedBlockingQueue(temCapacity);
}));
return blockingQueue;
@ -139,7 +140,7 @@ public enum QueueTypeEnum {
}
public static String getBlockingQueueNameByType(int type) {
Optional<QueueTypeEnum> queueTypeEnum = Arrays.stream(QueueTypeEnum.values())
Optional<BlockingQueueTypeEnum> queueTypeEnum = Arrays.stream(BlockingQueueTypeEnum.values())
.filter(each -> each.type == type)
.findFirst();
return queueTypeEnum.map(each -> each.name).orElse("");

@ -15,7 +15,7 @@
* limitations under the License.
*/
package cn.hippo4j.core.spi;
package cn.hippo4j.common.executor.support;
import java.util.concurrent.BlockingQueue;

@ -15,7 +15,7 @@
* limitations under the License.
*/
package cn.hippo4j.core.spi;
package cn.hippo4j.common.executor.support;
import java.util.concurrent.RejectedExecutionHandler;

@ -15,10 +15,10 @@
* limitations under the License.
*/
package cn.hippo4j.core.executor.support;
package cn.hippo4j.common.executor.support;
import cn.hippo4j.core.spi.CustomRejectedExecutionHandler;
import cn.hippo4j.core.spi.DynamicThreadPoolServiceLoader;
import cn.hippo4j.common.spi.DynamicThreadPoolServiceLoader;
import lombok.Getter;
import java.util.Collection;
import java.util.Objects;
@ -28,9 +28,9 @@ import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Stream;
/**
* Reject policy type Enum.
* Rejected policy type Enum.
*/
public enum RejectedTypeEnum {
public enum RejectedPolicyTypeEnum {
CALLER_RUNS_POLICY(1, "CallerRunsPolicy", new ThreadPoolExecutor.CallerRunsPolicy()),
@ -40,17 +40,19 @@ public enum RejectedTypeEnum {
DISCARD_OLDEST_POLICY(4, "DiscardOldestPolicy", new ThreadPoolExecutor.DiscardOldestPolicy()),
RUNS_OLDEST_TASK_POLICY(5, "RunsOldestTaskPolicy", new RejectedPolicies.RunsOldestTaskPolicy()),
RUNS_OLDEST_TASK_POLICY(5, "RunsOldestTaskPolicy", new RunsOldestTaskPolicy()),
SYNC_PUT_QUEUE_POLICY(6, "SyncPutQueuePolicy", new RejectedPolicies.SyncPutQueuePolicy());
SYNC_PUT_QUEUE_POLICY(6, "SyncPutQueuePolicy", new SyncPutQueuePolicy());
public Integer type;
@Getter
private Integer type;
public String name;
@Getter
private String name;
public RejectedExecutionHandler rejectedHandler;
RejectedTypeEnum(Integer type, String name, RejectedExecutionHandler rejectedHandler) {
RejectedPolicyTypeEnum(Integer type, String name, RejectedExecutionHandler rejectedHandler) {
this.type = type;
this.name = name;
this.rejectedHandler = rejectedHandler;
@ -61,7 +63,7 @@ public enum RejectedTypeEnum {
}
public static RejectedExecutionHandler createPolicy(String name) {
RejectedTypeEnum rejectedTypeEnum = Stream.of(RejectedTypeEnum.values())
RejectedPolicyTypeEnum rejectedTypeEnum = Stream.of(RejectedPolicyTypeEnum.values())
.filter(each -> Objects.equals(each.name, name))
.findFirst()
.orElse(null);
@ -78,7 +80,7 @@ public enum RejectedTypeEnum {
}
public static RejectedExecutionHandler createPolicy(int type) {
Optional<RejectedExecutionHandler> rejectedTypeEnum = Stream.of(RejectedTypeEnum.values())
Optional<RejectedExecutionHandler> rejectedTypeEnum = Stream.of(RejectedPolicyTypeEnum.values())
.filter(each -> Objects.equals(type, each.type))
.map(each -> each.rejectedHandler)
.findFirst();

@ -15,7 +15,7 @@
* limitations under the License.
*/
package cn.hippo4j.core.executor.support;
package cn.hippo4j.common.executor.support;
import cn.hutool.core.util.ReflectUtil;
import lombok.extern.slf4j.Slf4j;

@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.common.executor.support;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
/**
* Run the oldest task policy.
*/
public class RunsOldestTaskPolicy implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
if (executor.isShutdown()) {
return;
}
BlockingQueue<Runnable> workQueue = executor.getQueue();
Runnable firstWork = workQueue.poll();
boolean newTaskAdd = workQueue.offer(r);
if (firstWork != null) {
firstWork.run();
}
if (!newTaskAdd) {
executor.execute(r);
}
}
}

@ -0,0 +1,42 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.common.executor.support;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
/**
* Synchronous put queue policy.
*/
@Slf4j
public class SyncPutQueuePolicy implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
if (executor.isShutdown()) {
return;
}
try {
executor.getQueue().put(r);
} catch (InterruptedException e) {
log.error("Adding Queue task to thread pool failed.", e);
}
}
}

@ -23,91 +23,98 @@ package cn.hippo4j.common.model;
public interface ThreadPoolParameter {
/**
* tenantId
* Get tenant id
*
* @return
*/
String getTenantId();
/**
* itemId
* Get item id
*
* @return
*/
String getItemId();
/**
* tpId
* Get thread-pool id
*
* @return
*/
String getTpId();
/**
* coreSize
* Get core size
*
* @return
*/
Integer getCoreSize();
/**
* maxSize
* Get max size
*
* @return
*/
Integer getMaxSize();
/**
* queueType
* Get queue type
*
* @return
*/
Integer getQueueType();
/**
* capacity
* Get capacity
*
* @return
*/
Integer getCapacity();
/**
* keepAliveTime
* Get keep alive time
*
* @return
*/
Integer getKeepAliveTime();
/**
* rejectedType
* Get execute time out
*
* @return
*/
Long getExecuteTimeOut();
/**
* Get rejected type
*
* @return
*/
Integer getRejectedType();
/**
* isAlarm
* Get is alarm
*
* @return
*/
Integer getIsAlarm();
/**
* capacityAlarm
* Get capacity alarm
*
* @return
*/
Integer getCapacityAlarm();
/**
* livenessAlarm
* Get liveness alarm
*
* @return
*/
Integer getLivenessAlarm();
/**
* allowCoreThreadTimeOut
* Get allow core thread timeOut
*
* @return
*/

@ -17,6 +17,7 @@
package cn.hippo4j.common.model;
import com.fasterxml.jackson.annotation.JsonAlias;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -50,6 +51,7 @@ public class ThreadPoolParameterInfo implements ThreadPoolParameter, Serializabl
/**
* Thread-pool id
*/
@JsonAlias("threadPoolId")
private String tpId;
/**
@ -94,6 +96,11 @@ public class ThreadPoolParameterInfo implements ThreadPoolParameter, Serializabl
*/
private Integer keepAliveTime;
/**
* Execute time out
*/
private Long executeTimeOut;
/**
* Rejected type
*/
@ -112,6 +119,7 @@ public class ThreadPoolParameterInfo implements ThreadPoolParameter, Serializabl
/**
* Liveness alarm
*/
@JsonAlias("activeAlarm")
private Integer livenessAlarm;
/**

@ -17,6 +17,9 @@
package cn.hippo4j.common.model.register;
import cn.hippo4j.common.executor.support.BlockingQueueTypeEnum;
import cn.hippo4j.common.executor.support.RejectedPolicyTypeEnum;
import com.fasterxml.jackson.annotation.JsonAlias;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -53,9 +56,9 @@ public class DynamicThreadPoolRegisterParameter {
private Integer maximumPoolSize;
/**
* Queue type
* Blocking queue type
*/
private Integer queueType;
private BlockingQueueTypeEnum blockingQueueType;
/**
* Capacity
@ -65,17 +68,17 @@ public class DynamicThreadPoolRegisterParameter {
/**
* Keep alive time
*/
private Integer keepAliveTime;
private Long keepAliveTime;
/**
* Rejected type
* Rejected policy type
*/
private Integer rejectedType;
private RejectedPolicyTypeEnum rejectedPolicyType;
/**
* Is alarm
*/
private Integer isAlarm;
private Boolean isAlarm;
/**
* Capacity alarm
@ -83,12 +86,31 @@ public class DynamicThreadPoolRegisterParameter {
private Integer capacityAlarm;
/**
* Liveness alarm
* Active alarm
*/
private Integer livenessAlarm;
@JsonAlias("livenessAlarm")
private Integer activeAlarm;
/**
* Allow core thread timeout
*/
private Integer allowCoreThreadTimeOut;
private Boolean allowCoreThreadTimeOut;
/**
* Thread name prefix
*/
private String threadNamePrefix;
/**
* Execute timeout
*/
private Long executeTimeOut;
public Integer getIsAlarm() {
return this.isAlarm ? 1 : 0;
}
public Integer getAllowCoreThreadTimeOut() {
return this.allowCoreThreadTimeOut ? 1 : 0;
}
}

@ -17,6 +17,8 @@
package cn.hippo4j.common.model.register;
import cn.hippo4j.common.model.register.notify.DynamicThreadPoolRegisterCoreNotifyParameter;
import cn.hippo4j.common.model.register.notify.DynamicThreadPoolRegisterServerNotifyParameter;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -31,6 +33,15 @@ import lombok.NoArgsConstructor;
@AllArgsConstructor
public class DynamicThreadPoolRegisterWrapper {
// Hippo4j common ----------------------------------------------------------------------
/**
* Dynamic thread-pool register parameter
*/
private DynamicThreadPoolRegisterParameter dynamicThreadPoolRegisterParameter;
// Hippo4j server ----------------------------------------------------------------------
/**
* Tenant id
*/
@ -44,10 +55,22 @@ public class DynamicThreadPoolRegisterWrapper {
/**
* Update if exists
*/
private Boolean updateIfExists = Boolean.TRUE;
private Boolean updateIfExists = Boolean.FALSE;
/**
* Dynamic thread-pool register parameter
* Notify update if exists
*/
private DynamicThreadPoolRegisterParameter dynamicThreadPoolRegisterParameter;
private Boolean notifyUpdateIfExists = Boolean.FALSE;
/**
* Dynamic thread-pool server notify parameter
*/
private DynamicThreadPoolRegisterServerNotifyParameter dynamicThreadPoolRegisterServerNotifyParameter;
// Hippo4j core ----------------------------------------------------------------------
/**
* Dynamic thread-pool core notify parameter
*/
private DynamicThreadPoolRegisterCoreNotifyParameter dynamicThreadPoolRegisterCoreNotifyParameter;
}

@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.common.model.register.notify;
import lombok.*;
/**
* Dynamic thread-pool register core notify parameter.
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DynamicThreadPoolRegisterCoreNotifyParameter {
/**
* Interval
*/
private Integer interval;
/**
* Receive
*/
private String receives;
}

@ -0,0 +1,53 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.common.model.register.notify;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* Dynamic thread-pool register server notify parameter.
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DynamicThreadPoolRegisterServerNotifyParameter {
/**
* Platform
*/
private String platform;
/**
* Access token
*/
private String accessToken;
/**
* Interval
*/
private Integer interval;
/**
* Receives
*/
private String receives;
}

@ -15,8 +15,9 @@
* limitations under the License.
*/
package cn.hippo4j.core.spi;
package cn.hippo4j.common.spi;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@ -84,9 +85,9 @@ public class DynamicThreadPoolServiceLoader {
*/
private static Object newServiceInstance(final Class<?> clazz) {
try {
return clazz.newInstance();
} catch (final InstantiationException | IllegalAccessException ex) {
throw new ServiceLoaderInstantiationException(clazz, ex);
return clazz.getDeclaredConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new ServiceLoaderInstantiationException(clazz, e);
}
}
}

@ -15,7 +15,7 @@
* limitations under the License.
*/
package cn.hippo4j.core.spi;
package cn.hippo4j.common.spi;
/**
* Service loader instantiation exception.

@ -17,29 +17,27 @@
package cn.hippo4j.common.toolkit;
import java.text.DecimalFormat;
/**
* Byte conversion tool class
*/
public class ByteConvertUtil {
public static final Integer KB_SIZE = 2 << 9;
public static final Integer MB_SIZE = 2 << 19;
public static final Integer GB_SIZE = 2 << 29;
public static String getPrintSize(long size) {
long covertNum = 1024;
if (size < covertNum) {
DecimalFormat df = new DecimalFormat("#.00");
if (size < KB_SIZE) {
return size + "B";
} else if (size < MB_SIZE) {
return df.format((double) size / KB_SIZE) + "KB";
} else if (size < GB_SIZE) {
return df.format((double) size / MB_SIZE) + "MB";
} else {
size = size / covertNum;
}
if (size < covertNum) {
return size + "KB";
} else {
size = size / covertNum;
}
if (size < covertNum) {
size = size * 100;
return (size / 100) + "." + (size % 100) + "MB";
} else {
size = size * 100 / covertNum;
return (size / 100) + "." + (size % 100) + "GB";
return df.format((double) size / GB_SIZE) + "GB";
}
}
}

@ -36,6 +36,7 @@ public class ContentUtil {
.setQueueType(parameter.getQueueType())
.setCapacity(parameter.getCapacity())
.setKeepAliveTime(parameter.getKeepAliveTime())
.setExecuteTimeOut(parameter.getExecuteTimeOut())
.setIsAlarm(parameter.getIsAlarm())
.setCapacityAlarm(parameter.getCapacityAlarm())
.setLivenessAlarm(parameter.getLivenessAlarm())

@ -18,6 +18,7 @@
package cn.hippo4j.common.toolkit;
import cn.hippo4j.common.api.JsonFacade;
import com.fasterxml.jackson.core.type.TypeReference;
import java.util.List;
@ -32,7 +33,6 @@ public class JSONUtil {
if (object == null) {
return null;
}
return JSON_FACADE.toJSONString(object);
}
@ -40,15 +40,20 @@ public class JSONUtil {
if (StringUtil.isBlank(text)) {
return null;
}
return JSON_FACADE.parseObject(text, clazz);
}
public static <T> List<T> parseArray(String text, Class<T> clazz) {
public static <T> T parseObject(String text, TypeReference<T> valueTypeRef) {
if (StringUtil.isBlank(text)) {
return null;
}
return JSON_FACADE.parseObject(text, valueTypeRef);
}
public static <T> List<T> parseArray(String text, Class<T> clazz) {
if (StringUtil.isBlank(text)) {
return null;
}
return JSON_FACADE.parseArray(text, clazz);
}
}

@ -20,6 +20,7 @@ package cn.hippo4j.common.toolkit;
import cn.hippo4j.common.api.JsonFacade;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -61,6 +62,12 @@ public class JacksonHandler implements JsonFacade {
return MAPPER.readValue(text, javaType);
}
@Override
@SneakyThrows
public <T> T parseObject(String text, TypeReference<T> valueTypeRef) {
return MAPPER.readValue(text, valueTypeRef);
}
@Override
@SneakyThrows
public <T> List<T> parseArray(String text, Class<T> clazz) {

@ -17,15 +17,15 @@
package cn.hippo4j.common.toolkit;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import cn.hippo4j.common.monitor.AbstractMessage;
import cn.hippo4j.common.monitor.Message;
import cn.hippo4j.common.monitor.MessageWrapper;
import lombok.SneakyThrows;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Message convert.
*/
@ -60,7 +60,7 @@ public class MessageConvert {
*/
@SneakyThrows
public static Message convert(MessageWrapper messageWrapper) {
AbstractMessage message = (AbstractMessage) messageWrapper.getResponseClass().newInstance();
AbstractMessage message = (AbstractMessage) messageWrapper.getResponseClass().getDeclaredConstructor().newInstance();
List<Map<String, Object>> contentParams = messageWrapper.getContentParams();
List<Message> messages = new ArrayList();
contentParams.forEach(each -> {

@ -94,9 +94,7 @@ public class ReflectUtil {
} else {
int length = allFields.length;
allFields = Arrays.copyOf(allFields, length + declaredFields.length);
for (int i = 1; i < declaredFields.length; i++) {
allFields[length + i] = declaredFields[i - 1];
}
System.arraycopy(declaredFields, 0, allFields, length, declaredFields.length);
}
searchType = withSuperClassFields ? searchType.getSuperclass() : null;
}

@ -26,6 +26,36 @@ public class StringUtil {
public static final char UNDERLINE = '_';
/**
* Returns the given string if it is nonempty; {@code null} otherwise.
*
* @param str
* @return
*/
public static String emptyToNull(String str) {
return (str == null || str.isEmpty()) ? null : str;
}
/**
* Returns the given string if it is non-null; the empty string otherwise.
*
* @param str
* @return
*/
public static String nullToEmpty(String str) {
return str == null ? "" : str;
}
/**
* Returns {@code true} if the given string is null or is the empty string.
*
* @param str
* @return
*/
public static boolean isNullOrEmpty(String str) {
return str == null || str.isEmpty();
}
/**
* Is blank.
*

@ -0,0 +1,72 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.common.toolkit;
import cn.hippo4j.common.function.Matcher;
import com.google.common.base.Strings;
import org.checkerframework.checker.units.qual.A;
import org.junit.Test;
import java.lang.reflect.Array;
public class ArrayUtilTest {
@Test
public void assertIsEmpty() {
String[] array = new String[0];
Assert.isTrue(ArrayUtil.isEmpty(array));
}
@Test
public void assertIsNotEmpty() {
String[] array = new String[0];
Assert.isTrue(!ArrayUtil.isNotEmpty(array));
}
@Test
public void assertFirstMatch() {
Matcher<String> matcher = (str) -> "1".equalsIgnoreCase(str);
String[] array = new String[0];
Assert.isTrue(Strings.isNullOrEmpty(ArrayUtil.firstMatch(matcher, array)));
array = new String[]{"0"};
Assert.isTrue(Strings.isNullOrEmpty(ArrayUtil.firstMatch(matcher, array)));
array = new String[]{"1"};
Assert.isTrue(!Strings.isNullOrEmpty(ArrayUtil.firstMatch(matcher, array)));
}
@Test
public void assertAddAll() {
String[] array = new String[]{"1"};
Assert.isTrue(ArrayUtil.addAll(array, null).length == 1);
Assert.isTrue(ArrayUtil.addAll(null, array).length == 1);
Assert.isTrue(ArrayUtil.addAll(array, new String[]{"1"}).length == 2);
}
@Test
public void assertClone() {
Assert.isNull(ArrayUtil.clone(null));
String[] array = new String[0];
Assert.isTrue(array != ArrayUtil.clone(array));
Assert.isTrue(array.length == ArrayUtil.clone(array).length);
}
}

@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.common.toolkit;
import org.junit.Test;
public class BooleanUtilTest {
@Test
public void assertToBoolean() {
Assert.isTrue(BooleanUtil.toBoolean("true"));
Assert.isTrue(BooleanUtil.toBoolean("yes"));
Assert.isTrue(BooleanUtil.toBoolean("1"));
}
@Test
public void assertIsTrue() {
Assert.isTrue(BooleanUtil.isTrue(true));
}
}

@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.common.toolkit;
import org.junit.Test;
import java.util.Objects;
public class ByteConvertUtilTest {
@Test
public void assertGetPrintSize() {
Assert.isTrue(Objects.equals(ByteConvertUtil.getPrintSize(220), "220B"));
Assert.isTrue(Objects.equals(ByteConvertUtil.getPrintSize(2200), "2.15KB"));
Assert.isTrue(Objects.equals(ByteConvertUtil.getPrintSize(2200000), "2.10MB"));
Assert.isTrue(Objects.equals(ByteConvertUtil.getPrintSize(2200000000L), "2.05GB"));
}
}

@ -0,0 +1,30 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.common.toolkit;
import org.junit.Test;
public class CalculateUtilTest {
@Test
public void assertDivide() {
Assert.isTrue(CalculateUtil.divide(200, 100) == 200);
Assert.isTrue(CalculateUtil.divide(100, 200) == 50);
Assert.isTrue(CalculateUtil.divide(100, 100) == 100);
}
}

@ -0,0 +1,97 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.common.toolkit;
import com.google.common.collect.Maps;
import org.assertj.core.util.Lists;
import org.junit.Test;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class CollectionUtilTest {
@Test
public void assertGetFirst() {
Assert.isNull(CollectionUtil.getFirst(null));
String first = CollectionUtil.getFirst(Lists.newArrayList("1", "2"));
Assert.notEmpty(first);
}
@Test
public void assertIsEmpty() {
List list = null;
Assert.isTrue(CollectionUtil.isEmpty(list));
list = Lists.newArrayList();
Assert.isTrue(CollectionUtil.isEmpty(list));
list = Lists.newArrayList("1");
Assert.isTrue(!CollectionUtil.isEmpty(list));
Map map = null;
Assert.isTrue(CollectionUtil.isEmpty(map));
map = Maps.newHashMap();
Assert.isTrue(CollectionUtil.isEmpty(map));
map.put("key", "value");
Assert.isTrue(!CollectionUtil.isEmpty(map));
Iterator iterator = null;
Assert.isTrue(CollectionUtil.isEmpty(iterator));
iterator = Lists.emptyList().iterator();
Assert.isTrue(CollectionUtil.isEmpty(iterator));
iterator = Lists.newArrayList("1").iterator();
Assert.isTrue(!CollectionUtil.isEmpty(iterator));
}
@Test
public void assertIsNotEmpty() {
List list = null;
Assert.isTrue(!CollectionUtil.isNotEmpty(list));
list = Lists.newArrayList();
Assert.isTrue(!CollectionUtil.isNotEmpty(list));
list = Lists.newArrayList("1");
Assert.isTrue(CollectionUtil.isNotEmpty(list));
Map map = null;
Assert.isTrue(!CollectionUtil.isNotEmpty(map));
map = Maps.newHashMap();
Assert.isTrue(!CollectionUtil.isNotEmpty(map));
map.put("key", "value");
Assert.isTrue(CollectionUtil.isNotEmpty(map));
Iterator iterator = null;
Assert.isTrue(!CollectionUtil.isNotEmpty(iterator));
iterator = Lists.emptyList().iterator();
Assert.isTrue(!CollectionUtil.isNotEmpty(iterator));
iterator = Lists.newArrayList("1").iterator();
Assert.isTrue(CollectionUtil.isNotEmpty(iterator));
}
}

@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.common.toolkit;
import cn.hippo4j.common.function.NoArgsConsumer;
import org.junit.Test;
import java.util.concurrent.atomic.AtomicBoolean;
public class ConditionUtilTest {
@Test
public void assertCondition() {
// init consumer
AtomicBoolean checkValue = new AtomicBoolean(false);
NoArgsConsumer trueConsumer = () -> checkValue.set(true);
NoArgsConsumer falseConsumer = () -> checkValue.set(false);
// test trueConsumer run
ConditionUtil.condition(true, trueConsumer, falseConsumer);
Assert.isTrue(checkValue.get());
// test falseConsumer run
ConditionUtil.condition(false, trueConsumer, falseConsumer);
Assert.isTrue(!checkValue.get());
}
}

@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.common.toolkit;
import org.junit.Test;
public class ContentUtilTest {
@Test
public void assertGetPoolContent() {
}
@Test
public void assertGetGroupKey() {
}
@Test
public void assertGetGroupKeys() {
}
}

@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.common.toolkit;
import org.junit.Test;
public class FileUtilTest {
@Test
public void assertReadUtf8String() {
String testText = "abcd简体繁体\uD83D\uDE04\uD83D\uDD25& *\n" +
"second line\n" +
"empty line next\n";
String testFilePath = "test/test_utf8.txt";
String contentByFileUtil = FileUtil.readUtf8String(testFilePath);
Assert.isTrue(testText.equals(contentByFileUtil));
}
}

@ -0,0 +1,84 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.common.toolkit;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.junit.Assert;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
/**
* JSON util test.
*/
public class JSONUtilTest {
private static final Foo EXPECTED_FOO = new Foo(1, "foo1", new Foo(2, "foo2", null));
private static final List<Foo> EXPECTED_FOO_ARRAY = Arrays.asList(EXPECTED_FOO, EXPECTED_FOO);
private static final String EXPECTED_FOO_JSON = "{\"id\":1,\"name\":\"foo1\",\"foo\":{\"id\":2,\"name\":\"foo2\"}}";
private static final String EXPECTED_FOO_JSON_ARRAY = "[" + EXPECTED_FOO_JSON + "," + EXPECTED_FOO_JSON + "]";
@Test
public void assertToJSONString() {
Assert.assertNull(JSONUtil.toJSONString(null));
Assert.assertEquals(EXPECTED_FOO_JSON, JSONUtil.toJSONString(EXPECTED_FOO));
}
@Test
public void assertParseObject() {
Assert.assertNull(JSONUtil.parseObject(null, Foo.class));
Assert.assertNull(JSONUtil.parseObject(" ", Foo.class));
Assert.assertEquals(EXPECTED_FOO, JSONUtil.parseObject(EXPECTED_FOO_JSON, Foo.class));
}
@Test
public void assertParseObjectTypeReference() {
Assert.assertNull(JSONUtil.parseObject(null, new TypeReference<List<Foo>>() {}));
Assert.assertNull(JSONUtil.parseObject(" ", new TypeReference<List<Foo>>() {}));
Assert.assertEquals(
EXPECTED_FOO_ARRAY,
JSONUtil.parseObject(EXPECTED_FOO_JSON_ARRAY, new TypeReference<List<Foo>>() {})
);
}
@Test
public void assertParseArray() {
Assert.assertNull(JSONUtil.parseArray(null, Foo.class));
Assert.assertNull(JSONUtil.parseArray(" ", Foo.class));
Assert.assertEquals(
EXPECTED_FOO_ARRAY,
JSONUtil.parseArray(EXPECTED_FOO_JSON_ARRAY, Foo.class)
);
}
@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor
@Data
private static class Foo {
private Integer id;
private String name;
private Foo foo;
}
}

@ -0,0 +1,3 @@
abcd简体繁体😄🔥& *
second line
empty line next

@ -17,7 +17,9 @@
package cn.hippo4j.config.model;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonIgnore;
@ -81,6 +83,12 @@ public class ConfigInfoBase implements Serializable {
*/
private Integer keepAliveTime;
/**
* executeTimeOut
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
private Long executeTimeOut;
/**
* rejectedType
*/

@ -18,6 +18,7 @@
package cn.hippo4j.config.model.biz.notify;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* Notify req DTO.
@ -26,6 +27,7 @@ import lombok.Data;
* @date 2021/11/18 20:15
*/
@Data
@Accessors(chain = true)
public class NotifyReqDTO {
/**
@ -58,6 +60,11 @@ public class NotifyReqDTO {
*/
private String platform;
/**
* Type
*/
private String type;
/**
* Config type
*/

@ -78,6 +78,11 @@ public class ThreadPoolRespDTO {
*/
private Integer keepAliveTime;
/**
* Execute time out
*/
private Long executeTimeOut;
/**
* Is alarm
*/

@ -70,6 +70,11 @@ public class ThreadPoolSaveOrUpdateReqDTO {
*/
private Integer keepAliveTime;
/**
* Execute time out
*/
private Long executeTimeOut;
/**
* Is alarm
*/

@ -30,6 +30,7 @@ import cn.hippo4j.config.model.biz.adapter.ThreadPoolAdapterReqDTO;
import cn.hippo4j.config.model.biz.adapter.ThreadPoolAdapterRespDTO;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.http.HttpUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
@ -105,7 +106,8 @@ public class ThreadPoolAdapterService {
try {
String resultStr = HttpUtil.get(urlString, param, HTTP_EXECUTE_TIMEOUT);
if (StringUtil.isNotBlank(resultStr)) {
Result<ThreadPoolAdapterRespDTO> restResult = JSONUtil.parseObject(resultStr, Result.class);
Result<ThreadPoolAdapterRespDTO> restResult = JSONUtil.parseObject(resultStr, new TypeReference<Result<ThreadPoolAdapterRespDTO>>() {
});
result.add(restResult.getData());
}
} catch (Throwable ex) {

@ -60,6 +60,14 @@ public interface NotifyService {
*/
void update(NotifyReqDTO reqDTO);
/**
* Save or update.
*
* @param notifyUpdateIfExists
* @param reqDTO
*/
void saveOrUpdate(boolean notifyUpdateIfExists, NotifyReqDTO reqDTO);
/**
* Delete.
*

@ -21,27 +21,24 @@ import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hippo4j.common.enums.DelEnum;
import cn.hippo4j.common.model.register.DynamicThreadPoolRegisterParameter;
import cn.hippo4j.common.model.register.DynamicThreadPoolRegisterWrapper;
import cn.hippo4j.common.model.register.notify.DynamicThreadPoolRegisterServerNotifyParameter;
import cn.hippo4j.common.toolkit.*;
import cn.hippo4j.common.web.exception.ServiceException;
import cn.hippo4j.config.event.LocalDataChangeEvent;
import cn.hippo4j.config.mapper.ConfigInfoMapper;
import cn.hippo4j.config.mapper.ConfigInstanceMapper;
import cn.hippo4j.config.model.ConfigAllInfo;
import cn.hippo4j.config.model.ConfigInfoBase;
import cn.hippo4j.config.model.ConfigInstanceInfo;
import cn.hippo4j.config.model.LogRecordInfo;
import cn.hippo4j.config.model.*;
import cn.hippo4j.config.model.biz.notify.NotifyReqDTO;
import cn.hippo4j.config.service.ConfigCacheService;
import cn.hippo4j.config.service.ConfigChangePublisher;
import cn.hippo4j.config.service.biz.ConfigService;
import cn.hippo4j.config.service.biz.ItemService;
import cn.hippo4j.config.service.biz.OperationLogService;
import cn.hippo4j.config.service.biz.TenantService;
import cn.hippo4j.config.service.biz.*;
import cn.hippo4j.config.toolkit.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@ -68,6 +65,8 @@ public class ConfigServiceImpl implements ConfigService {
private final OperationLogService operationLogService;
private final NotifyService notifyService;
@Override
public ConfigAllInfo findConfigAllInfo(String tpId, String itemId, String tenantId) {
LambdaQueryWrapper<ConfigAllInfo> wrapper = Wrappers.lambdaQuery(ConfigAllInfo.class)
@ -139,11 +138,7 @@ public class ConfigServiceImpl implements ConfigService {
@Override
public void register(DynamicThreadPoolRegisterWrapper registerWrapper) {
DynamicThreadPoolRegisterParameter registerParameter = registerWrapper.getDynamicThreadPoolRegisterParameter();
ConfigAllInfo configAllInfo = JSONUtil.parseObject(JSONUtil.toJSONString(registerParameter), ConfigAllInfo.class);
configAllInfo.setTenantId(registerWrapper.getTenantId());
configAllInfo.setItemId(registerWrapper.getItemId());
configAllInfo.setTpId(registerParameter.getThreadPoolId());
ConfigAllInfo configAllInfo = parseConfigAllInfo(registerWrapper);
TenantService tenantService = ApplicationContextHolder.getBean(TenantService.class);
ItemService itemService = ApplicationContextHolder.getBean(ItemService.class);
Assert.isTrue(tenantService.getTenantByTenantId(registerWrapper.getTenantId()) != null, "Tenant does not exist");
@ -155,6 +150,41 @@ public class ConfigServiceImpl implements ConfigService {
ConfigServiceImpl configService = ApplicationContextHolder.getBean(this.getClass());
configService.updateConfigInfo(null, false, configAllInfo);
}
DynamicThreadPoolRegisterServerNotifyParameter serverNotifyParameter = registerWrapper.getDynamicThreadPoolRegisterServerNotifyParameter();
if (serverNotifyParameter != null) {
ArrayList<String> notifyTypes = Lists.newArrayList("CONFIG", "ALARM");
notifyTypes.forEach(each -> {
NotifyReqDTO notifyReqDTO = new NotifyReqDTO();
notifyReqDTO.setType(each)
.setEnable(1)
.setTenantId(registerWrapper.getTenantId())
.setItemId(registerWrapper.getItemId())
.setTpId(configAllInfo.getTpId())
.setPlatform(serverNotifyParameter.getPlatform())
.setReceives(serverNotifyParameter.getReceives())
.setSecretKey(serverNotifyParameter.getAccessToken());
if (Objects.equals(each, "ALARM")) {
notifyReqDTO.setInterval(serverNotifyParameter.getInterval());
notifyReqDTO.setAlarmType(true);
} else {
notifyReqDTO.setConfigType(true);
}
notifyService.saveOrUpdate(registerWrapper.getNotifyUpdateIfExists(), notifyReqDTO);
});
}
}
private ConfigAllInfo parseConfigAllInfo(DynamicThreadPoolRegisterWrapper registerWrapper) {
DynamicThreadPoolRegisterParameter registerParameter = registerWrapper.getDynamicThreadPoolRegisterParameter();
ConfigAllInfo configAllInfo = JSONUtil.parseObject(JSONUtil.toJSONString(registerParameter), ConfigAllInfo.class);
configAllInfo.setTenantId(registerWrapper.getTenantId());
configAllInfo.setItemId(registerWrapper.getItemId());
configAllInfo.setTpId(registerParameter.getThreadPoolId());
configAllInfo.setLivenessAlarm(registerParameter.getActiveAlarm());
configAllInfo.setQueueType(registerParameter.getBlockingQueueType().getType());
configAllInfo.setRejectedType(registerParameter.getRejectedPolicyType().getType());
configAllInfo.setAllowCoreThreadTimeOut(registerParameter.getAllowCoreThreadTimeOut());
return configAllInfo;
}
private void verification(String identify) {

@ -119,6 +119,26 @@ public class NotifyServiceImpl implements NotifyService {
}
}
@Override
public void saveOrUpdate(boolean notifyUpdateIfExists, NotifyReqDTO reqDTO) {
try {
existNotify(reqDTO.getType(), reqDTO);
save(reqDTO);
} catch (Exception ignored) {
if (!notifyUpdateIfExists) {
return;
}
LambdaQueryWrapper<NotifyInfo> queryWrapper = Wrappers.lambdaQuery(NotifyInfo.class)
.eq(NotifyInfo::getTenantId, reqDTO.getTenantId())
.eq(NotifyInfo::getItemId, reqDTO.getItemId())
.eq(NotifyInfo::getTpId, reqDTO.getTpId())
.eq(NotifyInfo::getPlatform, reqDTO.getPlatform())
.eq(NotifyInfo::getType, reqDTO.getType());
List<NotifyInfo> notifyInfos = notifyInfoMapper.selectList(queryWrapper);
notifyInfos.forEach(each -> update(reqDTO.setId(String.valueOf(each.getId()))));
}
}
@Override
public void delete(NotifyReqDTO reqDTO) {
LambdaUpdateWrapper<NotifyInfo> updateWrapper = Wrappers.lambdaUpdate(NotifyInfo.class)

@ -40,7 +40,7 @@ import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.Objects;
/**
* Thread pool service impl.
@ -82,7 +82,10 @@ public class ThreadPoolServiceImpl implements ThreadPoolService {
@Override
public void saveOrUpdateThreadPoolConfig(String identify, ThreadPoolSaveOrUpdateReqDTO reqDTO) {
configService.insertOrUpdate(identify, false, BeanUtil.convert(reqDTO, ConfigAllInfo.class));
ConfigAllInfo configAllInfo = BeanUtil.convert(reqDTO, ConfigAllInfo.class);
Long executeTimeOut = Objects.equals(configAllInfo.getExecuteTimeOut(), 0L) ? null : configAllInfo.getExecuteTimeOut();
configAllInfo.setExecuteTimeOut(executeTimeOut);
configService.insertOrUpdate(identify, false, configAllInfo);
}
@Override
@ -99,7 +102,7 @@ public class ThreadPoolServiceImpl implements ThreadPoolService {
LogRecordInfo logRecordInfo = LogRecordInfo.builder()
.bizKey(requestParam.getItemId() + "_" + requestParam.getTpId())
.bizNo(requestParam.getItemId() + "_" + requestParam.getTpId())
.operator(Optional.ofNullable(UserContext.getUserName()).orElse("-"))
.operator(UserContext.getUserName())
.action("删除线程池: " + requestParam.getTpId())
.category("THREAD_POOL_DELETE")
.detail(JSONUtil.toJSONString(requestParam))

File diff suppressed because one or more lines are too long

@ -1 +1 @@
.waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.dashboard-editor-container[data-v-001a3100]{padding:32px;background-color:#f0f2f5;position:relative;min-height:100vh}
.waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.dashboard-editor-container[data-v-58ed3ad9]{padding:32px;background-color:#f0f2f5;position:relative;min-height:100vh}

@ -0,0 +1 @@
.waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}

@ -0,0 +1 @@
.waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}

@ -1 +1 @@
.waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.pagination-container[data-v-df7d1fa0]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-df7d1fa0]{display:none}[data-v-40b8bf28]::-webkit-scrollbar{width:8px;height:8px}[data-v-40b8bf28]::-webkit-scrollbar-track{border-radius:5px;background:rgba(0,0,0,.06);-webkit-box-shadow:inset 0 0 5px rgba(0,0,0,.08)}[data-v-40b8bf28]::-webkit-scrollbar-thumb{border-radius:5px;background:rgba(0,0,0,.12);-webkit-box-shadow:inset 0 0 10px rgba(0,0,0,.2)}.stack-info[data-v-40b8bf28]{height:400px;overflow:auto}.stack-info>li[data-v-40b8bf28]{margin-bottom:24px}.stack-info>li p[data-v-40b8bf28]:first-child{color:#06f;font-weight:600;margin-top:10px}.stack-info>li ul[data-v-40b8bf28]{margin-left:30px}.stack-info>li ul li[data-v-40b8bf28]{color:#fc5531;text-align:justify;margin:10px auto}
.waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.pagination-container[data-v-df7d1fa0]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-df7d1fa0]{display:none}[data-v-65a213ee]::-webkit-scrollbar{width:8px;height:8px}[data-v-65a213ee]::-webkit-scrollbar-track{border-radius:5px;background:rgba(0,0,0,.06);-webkit-box-shadow:inset 0 0 5px rgba(0,0,0,.08)}[data-v-65a213ee]::-webkit-scrollbar-thumb{border-radius:5px;background:rgba(0,0,0,.12);-webkit-box-shadow:inset 0 0 10px rgba(0,0,0,.2)}.stack-info[data-v-65a213ee]{height:400px;overflow:auto}.stack-info>li[data-v-65a213ee]{margin-bottom:24px}.stack-info>li p[data-v-65a213ee]:first-child{color:#06f;font-weight:600;margin-top:10px}.stack-info>li ul[data-v-65a213ee]{margin-left:30px}.stack-info>li ul li[data-v-65a213ee]{color:#fc5531;text-align:justify;margin:10px auto}

@ -0,0 +1 @@
.waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save