diff --git a/.codecov.yml b/.codecov.yml
index a6ffc2d4..74099668 100644
--- a/.codecov.yml
+++ b/.codecov.yml
@@ -17,9 +17,12 @@
coverage:
status:
- patch:
+ project:
default:
- threshold: 0.1%
+ target: auto
+ # adjust accordingly based on how flaky your tests are
+ # this allows a 10% drop from the previous base commit coverage
+ threshold: 10%
ignore:
- "hippo4j-example/.*"
- "docs/.*"
diff --git a/README-EN.md b/README-EN.md
index 67d1d1c8..d1f97e91 100644
--- a/README-EN.md
+++ b/README-EN.md
@@ -2,7 +2,7 @@
# Dynamic and observable thread pool framework
-[](https://gitee.com/itmachen/hippo4j) [](https://github.com/opengoofy/hippo4j) [](https://github.com/opengoofy/hippo4j/graphs/contributors) [](https://store.docker.com/community/images/hippo4j/hippo4j-server) [](https://codecov.io/gh/opengoofy/hippo4j)
+[](https://gitee.com/magegoofy/hippo4j) [](https://github.com/opengoofy/hippo4j) [](https://github.com/opengoofy/hippo4j/graphs/contributors) [](https://store.docker.com/community/images/hippo4j/hippo4j-server) [](https://codecov.io/gh/opengoofy/hippo4j)
-------
diff --git a/README.md b/README.md
index a8edb894..01ba603e 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
# 动态可观测线程池框架,提高线上运行保障能力
-[](https://gitee.com/itmachen/hippo4j) [](https://github.com/opengoofy/hippo4j) [](https://github.com/opengoofy/hippo4j/graphs/contributors) [](https://store.docker.com/community/images/hippo4j/hippo4j-server) [](https://codecov.io/gh/opengoofy/hippo4j)
+[](https://gitee.com/magegoofy/hippo4j) [](https://github.com/opengoofy/hippo4j) [](https://github.com/opengoofy/hippo4j/graphs/contributors) [](https://store.docker.com/community/images/hippo4j/hippo4j-server) [](https://codecov.io/gh/opengoofy/hippo4j)
-------
diff --git a/docs/blog/authors.yml b/docs/blog/authors.yml
index 0edbc8d9..ffffe8d4 100644
--- a/docs/blog/authors.yml
+++ b/docs/blog/authors.yml
@@ -1,5 +1,5 @@
xiaomage:
name: 小马哥
title: hippo4j 作者
- url: https://github.com/mabaiwan
+ url: https://github.com/magegoofy
image_url: https://avatars.githubusercontent.com/u/77398366?v=4
diff --git a/docs/docs/community/contributor.md b/docs/docs/community/contributor.md
index f0185ad3..5aa056a0 100644
--- a/docs/docs/community/contributor.md
+++ b/docs/docs/community/contributor.md
@@ -17,8 +17,555 @@ git config --global user.email "GitHub 账号邮箱"
## 贡献者列表
-您可以在 [Hippo4J](https://github.com/opengoofy/hippo4j/graphs/contributors) 和 [Hippo4J Console](https://github.com/opengoofy/hippo4j-console) 的贡献列表中找到全部的贡献者名单。
+感谢所有为项目作出贡献的开发者。如果有意贡献,参考 [good first issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)。
-
-
-
+
diff --git a/docs/docs/community/developer.md b/docs/docs/community/developer.md
index b468d82d..03cdd4e3 100644
--- a/docs/docs/community/developer.md
+++ b/docs/docs/community/developer.md
@@ -13,10 +13,10 @@ sidebar_position: 2
联系方式 |
-  |
+  |
马称 |
- itmachen |
- 小马哥的技术专栏 |
+ magegoofy |
+ 小马哥的技术专栏 |
machen@apache.org |
@@ -62,3 +62,21 @@ sidebar_position: 2
17855368071@163.com |
+
+## 成为核心开发者
+
+持续对 Hippo-4J 进行贡献, 粗略评估,完成 10 次 PR 贡献即可成为核心开发者。 其中包括完成 2 个 [good pro issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+pro+issue%22) 或以上,以及 若干个 [good first issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)。
+
+:::note
+会根据 PR 质量提供个性化评估,有可能一个或两个质量较高 PR 即可成为核心开发者。参考:[重构 DynamicThreadPoolExecutor 功能扩展逻辑](https://github.com/opengoofy/hippo4j/pull/854)
+:::
+
+成为核心开发者后,会为该 GitHub 账号获取 Jetbrains 全家桶 Licenses,有效期为 1 年。不用再为破解而烦恼,感受随时升级的快乐。
+
+:::note
+距离到期两周前,会再次申请 Jetbrains Licenses。有点类似于无限续约的感觉,在此感谢 Jetbrains 公司对开源的支持。
+:::
+
+截至 `2022-10-30` 当天,已为登记的 7 位核心开发者成功申请 Licenses。
+
+
diff --git a/docs/docs/community/powered-by.md b/docs/docs/community/powered-by.md
index 81bf0e32..635d9011 100644
--- a/docs/docs/community/powered-by.md
+++ b/docs/docs/community/powered-by.md
@@ -12,7 +12,7 @@ sidebar_position: 3
## 谁在使用 Hippo4J
-共计 20+ 家公司生产接入 Hippo4J。按照公司登记时间排序。
+共计 21+ 家公司生产接入 Hippo4J。按照公司登记时间排序。
- [身边云](https://serviceshare.com)
- [Medbanks](https://www.medbanks.cn)
@@ -34,3 +34,4 @@ sidebar_position: 3
- [新东方教育科技集团](https://www.xdf.cn/)
- [远眺网络科技有限公司](https://www.yuantiaokj.com/)
- [浙江吉利控股集团有限公司](https://www.geely.com/)
+- [三立人(深圳)科技有限公司-焦内](https://www.bananain.com/)
diff --git a/docs/docs/community/sponsor.md b/docs/docs/community/sponsor.md
index 30ca624b..c73fc64a 100644
--- a/docs/docs/community/sponsor.md
+++ b/docs/docs/community/sponsor.md
@@ -4,11 +4,13 @@ sidebar_position: 4
# 支持开源
-如果您正在使用这个项目并感觉良好,或者是想支持我继续开发。通过以下二维码一次性捐款,我多半会买一杯咖啡或茶~
+如果您正在使用这个项目并感觉良好,或者是想支持我继续开发,通过以下二维码一次性捐款。
+
+在这里承诺将,将收到的所有赞助支持资金完全公开化,且后续资金用途仅 Hippo-4J 项目的运转。

-感谢给予支持的朋友,您的支持是我前进的动力 🎉
+感谢给予支持的朋友,您的支持是 Hippo-4J 社区前进的动力 🎉
| | ID | 赞赏金额 | 时间 | 备注 |
|-----|--|-------|------------|--------------------|
@@ -18,3 +20,4 @@ sidebar_position: 4
| 4 | 捷克 | 30.00 | 2022-05-21 | 非常不错的框架,点赞 |
| 5 | 吃猫的饼干 | 88.00 | 2022-08-21 | 👍 |
| 6 | 不忘初心· | 66.00 | 2022-10-28 | Nice! |
+| 7 | 时刻· | 6.00 | 2022-10-30 | -! |
diff --git a/docs/docs/user_docs/intro.md b/docs/docs/user_docs/intro.md
index 4bfd0d78..fd9e5dcb 100644
--- a/docs/docs/user_docs/intro.md
+++ b/docs/docs/user_docs/intro.md
@@ -4,70 +4,613 @@ sidebar_position: 1
# 简介
-## 动态可观测线程池框架
+## 线程池痛点
-Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池等功能,为业务系统提高线上运行保障能力。
-
-- 🏗 全局管控 - 管理应用线程池实例。
+线程池是一种基于池化思想管理线程的工具,使用线程池可以减少创建销毁线程的开销,避免线程过多导致系统资源耗尽。在高并发以及大批量的任务处理场景,线程池的使用是必不可少的。
-- ⚡️ 动态变更 - 应用运行时动态变更线程池参数,包括不限于:核心、最大线程数、阻塞队列容量、拒绝策略等。
+如果有在项目中实际使用线程池,相信你可能会遇到以下痛点:
-- 🐳 通知报警 - 内置四种报警通知策略,线程池活跃度、容量水位、拒绝策略以及任务执行时间超长。
+- 线程池随便定义,线程资源过多,造成服务器高负载。
-- 👀 运行监控 - 实时查看线程池运行时数据,最近半小时线程池运行数据图表展示。
+- 线程池参数不易评估,随着业务的并发提升,业务面临出现故障的风险。
+- 线程池任务执行时间超过平均执行周期,开发人员无法感知。
+- 线程池任务堆积,触发拒绝策略,影响既有业务正常运行。
+- 当业务出现超时、熔断等问题时,因为没有监控,无法确定是不是线程池引起。
+- 原生线程池不支持运行时变量的传递,比如 MDC 上下文遇到线程池就 GG。
+- 无法执行优雅关闭,当项目关闭时,大量正在运行的线程池任务被丢弃。
+- 线程池运行中,任务执行停止,怀疑发生死锁或执行耗时操作,但是无从下手。
-- 👐 功能扩展 - 支持线程池任务传递上下文;项目关闭时,支持等待线程池在指定时间内完成任务。
+## 什么是 Hippo-4J
-- 👯♀️ 多种模式 - 内置两种使用模式:[依赖配置中心](https://hippo4j.cn/docs/user_docs/getting-started/config/hippo4j-config-start) 和 [无中间件依赖](https://hippo4j.cn/docs/user_docs/getting-started/server/hippo4j-server-start)。
+Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池等功能,为业务系统提高线上运行保障能力。
-- 🛠 容器管理 - Tomcat、Jetty、Undertow 容器线程池运行时查看和线程数变更。
+提供以下功能支持:
-- 🌈 中间件适配 - Apache RocketMQ、Dubbo、RabbitMQ、Hystrix 消费线程池运行时数据查看和线程数变更。
+- 全局管控 - 管理应用线程池实例。
-> 看完有收获,GitHub 右上角帮忙点个小星星,开源作者为爱发电也不容易 🤣
+- 动态变更 - 应用运行时动态变更线程池参数,包括不限于:核心、最大线程数、阻塞队列容量、拒绝策略等。
+- 通知报警 - 内置四种报警通知策略,线程池活跃度、容量水位、拒绝策略以及任务执行时间超长。
+- 运行监控 - 实时查看线程池运行时数据,最近半小时线程池运行数据图表展示。
+- 功能扩展 - 支持线程池任务传递上下文;项目关闭时,支持等待线程池在指定时间内完成任务。
+- 多种模式 - 内置两种使用模式:[依赖配置中心](https://hippo4j.cn/docs/user_docs/getting_started/config/hippo4j-config-start) 和 [无中间件依赖](https://hippo4j.cn/docs/user_docs/getting_started/server/hippo4j-server-start)。
+- 容器管理 - Tomcat、Jetty、Undertow 容器线程池运行时查看和线程数变更。
+- 框架适配 - Dubbo、Hystrix、RabbitMQ、RocketMQ 等消费线程池运行时数据查看和线程数变更。
## 快速开始
-对于本地演示目的,请参阅 [Quick start](docs/user_docs/getting_started/server/hippo4j-server-start)
-
-演示环境:
-- [http://console.hippo4j.cn/index.html](http://console.hippo4j.cn/index.html)
-- 用户/密码:hippo4j/hippo4j
-
-## 联系我
-
-
-
-## 开发者
+对于本地演示目的,请参阅 [Quick start](https://hippo4j.cn/docs/user_docs/user_guide/quick-start)
-感谢所有为 Hippo-4J 做出贡献的开发者!
+演示环境: [http://console.hippo4j.cn/index.html](http://console.hippo4j.cn/index.html)
-
+## 接入登记
-## 我们的荣誉
+更多接入的公司,欢迎在 [登记地址](https://github.com/opengoofy/hippo4j/issues/13) 登记,登记仅仅为了产品推广。
-Hippo-4J 获得了一些宝贵的荣誉,这属于每一位对 Hippo-4J 做出过贡献的成员,谢谢各位的付出。
-
-
+## 联系我
-## Stars 趋势
+
-
+扫码添加微信,备注:hippo4j,邀您加入群聊。若图片加载不出来,访问 [官网站点](https://hippo4j.cn/docs/user_docs/other/group)。
## 友情链接
-- [[ LiteFlow ]](https://liteflow.yomahub.com/):轻量,快速,稳定可编排的组件式规则引擎。
-
- [[ Sa-Token ]](https://github.com/dromara/sa-token):一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!
-- [[ HertzBeat ]](https://github.com/dromara/hertzbeat):易用友好的云监控系统, 无需 Agent, 强大自定义监控能力。
-
+- [[ HertzBeat ]](https://github.com/dromara/hertzbeat):易用友好的云监控系统, 无需 Agent, 强大自定义监控能力。
- [[ JavaGuide ]](https://github.com/Snailclimb/JavaGuide):一份涵盖大部分 Java 程序员所需要掌握的核心知识。
-
-- [[ toBeBetterJavaer ]](https://github.com/itwanger/toBeBetterJavaer):一份通俗易懂、风趣幽默的Java学习指南,内容涵盖Java基础、Java并发编程等核心知识点。
-
-## 鸣谢
-
-Hippo4J 项目基于或参考以下项目:[Nacos](https://github.com/alibaba/nacos)、[Eureka](https://github.com/Netflix/Eureka)。
-
-感谢 JetBrains 提供的免费开源 License
+- [[ toBeBetterJavaer ]](https://github.com/itwanger/toBeBetterJavaer):一份通俗易懂、风趣幽默的 Java 学习指南。
+
+## 贡献者
+
+感谢所有为项目作出贡献的开发者。如果有意贡献,参考 [good first issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)。
+
+
diff --git a/docs/docs/user_docs/user_guide/notify.md b/docs/docs/user_docs/user_guide/notify.md
index 216840e9..924d5a7e 100644
--- a/docs/docs/user_docs/user_guide/notify.md
+++ b/docs/docs/user_docs/user_guide/notify.md
@@ -41,7 +41,6 @@ WECHART:填写user_id会以@的消息发给用户,填写姓名则是普通
LARK:填写ou_开头用户唯一标识会以@的消息发给用户,填写手机号则是普通的@
```
-
## 钉钉平台
[钉钉创建群机器人](https://www.dingtalk.com/qidian/help-detail-20781541.html)
@@ -54,6 +53,10 @@ LARK:填写ou_开头用户唯一标识会以@的消息发给用户,填写手

+:::tip
+如果使用 1.4.3 及以上版本,`警报` 替换为 `告警`。
+:::
+
## 企业微信
[企业微信创建群机器人](https://open.work.weixin.qq.com/help2/pc/14931?person_id=1&from=homesearch)
diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js
index c83cb4a2..ee1748d7 100644
--- a/docs/docusaurus.config.js
+++ b/docs/docusaurus.config.js
@@ -22,10 +22,20 @@ const config = {
// Even if you don't use internalization, you can use this field to set useful
// metadata like html lang. For example, if your site is Chinese, you may want
// to replace "en" with "zh-Hans".
- i18n: {
- defaultLocale: 'zh-CN',
- locales: ['zh-CN'],
+ i18n: {
+ defaultLocale: "en",
+ locales: ["en", "zh"],
+ localeConfigs: {
+ en: {
+ label: "English",
+ direction: "ltr",
+ },
+ zh: {
+ label: "简体中文",
+ direction: "ltr",
+ },
},
+ },
presets: [
[
@@ -60,14 +70,15 @@ const config = {
announcementBar: {
id: 'announcementBar-1', // Increment on change
// content: `⭐️ If you like hippo4j, give it a star on Gitee, thanks.`,
- content: `⭐️ 如果您喜欢 hippo4j,请在 Gitee 和 GitHub 上给它一个 star,谢谢!`,
+ // content: `⭐️ 如果您喜欢 hippo4j,请在 Gitee 和 GitHub 上给它一个 star,谢谢!`,
+ content: `⭐️ 开源不易,hippo4j 如果对您工作有帮助,请在 GitHub 上给它一个 🌟`,
// content: `👉 《小马哥的代码实战课》官方知识星球来啦!!!`,
},
navbar: {
- title: 'HIPPO-4J',
+ title: '',
logo: {
alt: 'HIPPO-4J 动态可观测线程池框架',
- src: 'img/web.png',
+ src: 'img/hippo4j.png',
},
items: [
{
@@ -95,6 +106,11 @@ const config = {
label: '🥇代码实战课',
position: 'left',
},
+ {
+ type: 'docsVersionDropdown',
+ position: 'right',
+ dropdownActiveClassDisabled: true,
+ },
{type: 'localeDropdown', position: 'right'},
/*{
diff --git a/docs/i18n/zh/code.json b/docs/i18n/zh/code.json
new file mode 100644
index 00000000..fd6dd555
--- /dev/null
+++ b/docs/i18n/zh/code.json
@@ -0,0 +1,257 @@
+{
+ "theme.ErrorPageContent.title": {
+ "message": "页面已崩溃。",
+ "description": "The title of the fallback page when the page crashed"
+ },
+ "theme.ErrorPageContent.tryAgain": {
+ "message": "重试",
+ "description": "The label of the button to try again when the page crashed"
+ },
+ "theme.NotFound.title": {
+ "message": "找不到页面",
+ "description": "The title of the 404 page"
+ },
+ "theme.NotFound.p1": {
+ "message": "我们找不到您要找的页面。",
+ "description": "The first paragraph of the 404 page"
+ },
+ "theme.NotFound.p2": {
+ "message": "请联系原始链接来源网站的所有者,并告知他们链接已损坏。",
+ "description": "The 2nd paragraph of the 404 page"
+ },
+ "theme.admonition.note": {
+ "message": "备注",
+ "description": "The default label used for the Note admonition (:::note)"
+ },
+ "theme.admonition.tip": {
+ "message": "提示",
+ "description": "The default label used for the Tip admonition (:::tip)"
+ },
+ "theme.admonition.danger": {
+ "message": "危险",
+ "description": "The default label used for the Danger admonition (:::danger)"
+ },
+ "theme.admonition.info": {
+ "message": "信息",
+ "description": "The default label used for the Info admonition (:::info)"
+ },
+ "theme.admonition.caution": {
+ "message": "警告",
+ "description": "The default label used for the Caution admonition (:::caution)"
+ },
+ "theme.BackToTopButton.buttonAriaLabel": {
+ "message": "回到顶部",
+ "description": "The ARIA label for the back to top button"
+ },
+ "theme.blog.paginator.navAriaLabel": {
+ "message": "博文列表分页导航",
+ "description": "The ARIA label for the blog pagination"
+ },
+ "theme.blog.paginator.newerEntries": {
+ "message": "较新的博文",
+ "description": "The label used to navigate to the newer blog posts page (previous page)"
+ },
+ "theme.blog.paginator.olderEntries": {
+ "message": "较旧的博文",
+ "description": "The label used to navigate to the older blog posts page (next page)"
+ },
+ "theme.blog.archive.title": {
+ "message": "历史博文",
+ "description": "The page & hero title of the blog archive page"
+ },
+ "theme.blog.archive.description": {
+ "message": "历史博文",
+ "description": "The page & hero description of the blog archive page"
+ },
+ "theme.blog.post.paginator.navAriaLabel": {
+ "message": "博文分页导航",
+ "description": "The ARIA label for the blog posts pagination"
+ },
+ "theme.blog.post.paginator.newerPost": {
+ "message": "较新一篇",
+ "description": "The blog post button label to navigate to the newer/previous post"
+ },
+ "theme.blog.post.paginator.olderPost": {
+ "message": "较旧一篇",
+ "description": "The blog post button label to navigate to the older/next post"
+ },
+ "theme.colorToggle.ariaLabel": {
+ "message": "切换浅色/暗黑模式(当前为{mode})",
+ "description": "The ARIA label for the navbar color mode toggle"
+ },
+ "theme.colorToggle.ariaLabel.mode.dark": {
+ "message": "暗黑模式",
+ "description": "The name for the dark color mode"
+ },
+ "theme.colorToggle.ariaLabel.mode.light": {
+ "message": "浅色模式",
+ "description": "The name for the light color mode"
+ },
+ "theme.blog.post.plurals": {
+ "message": "{count} 篇博文",
+ "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
+ },
+ "theme.blog.tagTitle": {
+ "message": "{nPosts} 含有标签「{tagName}」",
+ "description": "The title of the page for a blog tag"
+ },
+ "theme.tags.tagsPageLink": {
+ "message": "查看所有标签",
+ "description": "The label of the link targeting the tag list page"
+ },
+ "theme.docs.breadcrumbs.home": {
+ "message": "主页面",
+ "description": "The ARIA label for the home page in the breadcrumbs"
+ },
+ "theme.docs.breadcrumbs.navAriaLabel": {
+ "message": "页面路径",
+ "description": "The ARIA label for the breadcrumbs"
+ },
+ "theme.docs.DocCard.categoryDescription": {
+ "message": "{count} 个项目",
+ "description": "The default description for a category card in the generated index about how many items this category includes"
+ },
+ "theme.docs.paginator.navAriaLabel": {
+ "message": "文档分页导航",
+ "description": "The ARIA label for the docs pagination"
+ },
+ "theme.docs.paginator.previous": {
+ "message": "上一页",
+ "description": "The label used to navigate to the previous doc"
+ },
+ "theme.docs.paginator.next": {
+ "message": "下一页",
+ "description": "The label used to navigate to the next doc"
+ },
+ "theme.docs.tagDocListPageTitle.nDocsTagged": {
+ "message": "{count} 篇文档带有标签",
+ "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
+ },
+ "theme.docs.tagDocListPageTitle": {
+ "message": "{nDocsTagged}「{tagName}」",
+ "description": "The title of the page for a docs tag"
+ },
+ "theme.docs.versionBadge.label": {
+ "message": "版本:{versionLabel}"
+ },
+ "theme.docs.versions.unreleasedVersionLabel": {
+ "message": "此为 {siteTitle} {versionLabel} 版尚未发行的文档。",
+ "description": "The label used to tell the user that he's browsing an unreleased doc version"
+ },
+ "theme.docs.versions.unmaintainedVersionLabel": {
+ "message": "此为 {siteTitle} {versionLabel} 版的文档,现已不再积极维护。",
+ "description": "The label used to tell the user that he's browsing an unmaintained doc version"
+ },
+ "theme.docs.versions.latestVersionSuggestionLabel": {
+ "message": "最新的文档请参阅 {latestVersionLink} ({versionLabel})。",
+ "description": "The label used to tell the user to check the latest version"
+ },
+ "theme.docs.versions.latestVersionLinkLabel": {
+ "message": "最新版本",
+ "description": "The label used for the latest version suggestion link label"
+ },
+ "theme.common.editThisPage": {
+ "message": "编辑此页",
+ "description": "The link label to edit the current page"
+ },
+ "theme.common.headingLinkTitle": {
+ "message": "标题的直接链接",
+ "description": "Title for link to heading"
+ },
+ "theme.lastUpdated.atDate": {
+ "message": "于 {date} ",
+ "description": "The words used to describe on which date a page has been last updated"
+ },
+ "theme.lastUpdated.byUser": {
+ "message": "由 {user} ",
+ "description": "The words used to describe by who the page has been last updated"
+ },
+ "theme.lastUpdated.lastUpdatedAtBy": {
+ "message": "最后{byUser}{atDate}更新",
+ "description": "The sentence used to display when a page has been last updated, and by who"
+ },
+ "theme.navbar.mobileVersionsDropdown.label": {
+ "message": "选择版本",
+ "description": "The label for the navbar versions dropdown on mobile view"
+ },
+ "theme.common.skipToMainContent": {
+ "message": "跳到主要内容",
+ "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation"
+ },
+ "theme.tags.tagsListLabel": {
+ "message": "标签:",
+ "description": "The label alongside a tag list"
+ },
+ "theme.AnnouncementBar.closeButtonAriaLabel": {
+ "message": "关闭",
+ "description": "The ARIA label for close button of announcement bar"
+ },
+ "theme.blog.sidebar.navAriaLabel": {
+ "message": "最近博文导航",
+ "description": "The ARIA label for recent posts in the blog sidebar"
+ },
+ "theme.CodeBlock.copied": {
+ "message": "复制成功",
+ "description": "The copied button label on code blocks"
+ },
+ "theme.CodeBlock.copyButtonAriaLabel": {
+ "message": "复制代码到剪贴板",
+ "description": "The ARIA label for copy code blocks button"
+ },
+ "theme.CodeBlock.copy": {
+ "message": "复制",
+ "description": "The copy button label on code blocks"
+ },
+ "theme.CodeBlock.wordWrapToggle": {
+ "message": "切换自动换行",
+ "description": "The title attribute for toggle word wrapping button of code block lines"
+ },
+ "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": {
+ "message": "打开/收起侧边栏菜单「{label}」",
+ "description": "The ARIA label to toggle the collapsible sidebar category"
+ },
+ "theme.navbar.mobileLanguageDropdown.label": {
+ "message": "选择语言",
+ "description": "The label for the mobile language switcher dropdown"
+ },
+ "theme.TOCCollapsible.toggleButtonLabel": {
+ "message": "本页总览",
+ "description": "The label used by the button on the collapsible TOC component"
+ },
+ "theme.docs.sidebar.collapseButtonTitle": {
+ "message": "收起侧边栏",
+ "description": "The title attribute for collapse button of doc sidebar"
+ },
+ "theme.docs.sidebar.collapseButtonAriaLabel": {
+ "message": "收起侧边栏",
+ "description": "The title attribute for collapse button of doc sidebar"
+ },
+ "theme.blog.post.readingTime.plurals": {
+ "message": "阅读需 {readingTime} 分钟",
+ "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
+ },
+ "theme.blog.post.readMore": {
+ "message": "阅读更多",
+ "description": "The label used in blog post item excerpts to link to full blog posts"
+ },
+ "theme.blog.post.readMoreLabel": {
+ "message": "阅读 {title} 的全文",
+ "description": "The ARIA label for the link to full blog posts from excerpts"
+ },
+ "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": {
+ "message": "← 回到主菜单",
+ "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)"
+ },
+ "theme.docs.sidebar.expandButtonTitle": {
+ "message": "展开侧边栏",
+ "description": "The ARIA label and title attribute for expand button of doc sidebar"
+ },
+ "theme.docs.sidebar.expandButtonAriaLabel": {
+ "message": "展开侧边栏",
+ "description": "The ARIA label and title attribute for expand button of doc sidebar"
+ },
+ "theme.tags.tagsPageTitle": {
+ "message": "标签",
+ "description": "The title of the tag list page"
+ }
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-blog/2022-06-06-hippo4j/index.md b/docs/i18n/zh/docusaurus-plugin-content-blog/2022-06-06-hippo4j/index.md
new file mode 100644
index 00000000..6f2d833b
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-blog/2022-06-06-hippo4j/index.md
@@ -0,0 +1,145 @@
+---
+slug: Hippo-4J发布1.3.0版本
+title: Hippo-4J发布1.3.0版本
+authors: [xiaomage]
+tags: [hippo4j, release, 1.3.0]
+---
+
+大家好,我是 **小马哥**。
+
+Hippo-4J 距离上一个版本 1.2.1 已经过去一个月的时间。在此期间,由 **8 位贡献者** 提交了 **170+ commits**,正式发布 **1.3.0** 版本。
+
+注:这是一个 **兼容历史版本** 的重大升级。
+
+## HIPPO-4J 1.3.0
+
+### Feature
+
+1. 添加 RabbitMQ 线程池监控及动态变更
+2. 添加 RocketMQ 线程池监控及动态变更
+3. 添加 Dubbo 线程池监控及动态变更
+4. 添加 SpringCloud Stream RocketMQ 消费线程池监控及动态变更
+
+### Refactor
+
+1. 重构容器线程池查询及修改功能
+2. 优化配置中心触发监听后,所执行的数据变更逻辑
+
+### Optimize
+
+1. 前端控制台删除无用组件
+2. 服务端页面字段未显示中文
+3. 控制台 UI 优化
+4. 修改线程池实例后实时刷新列表参数
+5. 容器线程池编辑仅限 Admin 权限
+6. SpringBoot Starter 变更包路径
+
+### BUG
+
+1. 修复 SpringBoot Nacos 动态刷新不生效
+2. 报警配置 alarm=false 不配置通知报警平台和接收人报错
+
+## 三方框架线程池适配
+
+Hippo-4J 1.3.0 最大的功能发布就是开发出了 **适配三方框架的基础框架**。
+
+目前已完成 **Dubbo、RabbitMQ、RocketMQ、RocketMQSpringCloudStream** 的线程池适配,后续还会接入 **Kafka、Hystrix** 等框架或中间件的线程池适配。
+
+### 引入适配三方框架 Jar 包
+
+引入 Hippo-4J server 或 core 的 maven jar 坐标后,还需要引入对应的框架适配 jar:
+
+```xml
+
+ cn.hippo4j
+
+ hippo4j-spring-boot-starter-adapter-dubbo
+
+ hippo4j-spring-boot-starter-adapter-rabbitmq
+
+ hippo4j-spring-boot-starter-adapter-rocketmq
+
+ hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rocketmq
+ 1.3.0
+
+```
+
+如果想觉得引入多个 jar 包繁琐,可以仅需引入一个全量包,Hippo-4J 框架底层会根据各中间件的条件,判断加载具体线程池适配器。
+
+```xml
+
+ cn.hippo4j
+ hippo4j-spring-boot-starter-adapter-all
+ 1.3.0
+
+```
+
+### HIPPO-4J Server
+
+Hippo-4J server 引入上述适配 jar 包后,即可在 Hippo-4J server 的控制台进行查看及修改三方框架线程池。
+
+
+
+
+
+点击编辑即可修改该 Java 应用对应的框架底层线程池。
+
+
+
+
+
+点击 **全部修改** 按钮可以修改当前组下所有应用实例的线程池配置。
+
+修改成功后,应用控制台打印以下日志,即为修改成功。
+
+```java
+[input] RocketMQ consumption thread pool parameter change. coreSize :: 1 => 10, maximumSize :: 1 => 10
+```
+
+### HIPPO-4J Core
+
+Hippo-4J core 除了依赖上述适配 Jar 包外,还需要在配置中心添加以下配置项。
+
+```yaml
+spring:
+ dynamic:
+ thread-pool:
+ # 省略其它配置
+ adapter-executors:
+ # threadPoolKey 代表线程池标识
+ - threadPoolKey: 'input'
+ # mark 为三方线程池框架类型,参见文初已支持框架集合
+ mark: 'RocketMQSpringCloudStream'
+ corePoolSize: 10
+ maximumPoolSize: 10
+```
+
+## Gitee GVP
+
+Hippo-4J 获得了一些宝贵的荣誉,这属于每一位对 Hippo-4J 做出过贡献的成员。
+
+
+
+
+
+感谢所有为 Hippo-4J 做出贡献的开发者!
+
+https://github.com/opengoofy/hippo4j/graphs/contributors
+
+
+
+
+
+## 最后总结
+
+开源不易,如果各位小伙伴看了 Hippo-4J 框架后有所收获,希望能帮忙在 Github、Gitee 点个 star,谢谢。
+
+**Github**:https://github.com/opengoofy/hippo4j
+
+**Gitee**:https://gitee.com/mabaiwancn/hippo4j
+
+目前已有 **10+** 公司在生产环境使用 Hippo-4J,如果贵公司使用了 Hippo-4J,请在下方 Issue 登记,谢谢。
+
+**Issue**:https://github.com/opengoofy/hippo4j/issues/13
+
+登记使用不会对公司有任何影响,仅为了扩大 Hippo-4J 影响力,帮助它能走得更远。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-blog/authors.yml b/docs/i18n/zh/docusaurus-plugin-content-blog/authors.yml
new file mode 100644
index 00000000..ffffe8d4
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-blog/authors.yml
@@ -0,0 +1,5 @@
+xiaomage:
+ name: 小马哥
+ title: hippo4j 作者
+ url: https://github.com/magegoofy
+ image_url: https://avatars.githubusercontent.com/u/77398366?v=4
diff --git a/docs/i18n/zh/docusaurus-plugin-content-blog/options.json b/docs/i18n/zh/docusaurus-plugin-content-blog/options.json
new file mode 100644
index 00000000..9239ff70
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-blog/options.json
@@ -0,0 +1,14 @@
+{
+ "title": {
+ "message": "Blog",
+ "description": "The title for the blog used in SEO"
+ },
+ "description": {
+ "message": "Blog",
+ "description": "The description for the blog used in SEO"
+ },
+ "sidebar.title": {
+ "message": "Recent posts",
+ "description": "The label for the left sidebar"
+ }
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current.json b/docs/i18n/zh/docusaurus-plugin-content-docs/current.json
new file mode 100644
index 00000000..52732047
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current.json
@@ -0,0 +1,94 @@
+{
+ "version.label": {
+ "message": "Next",
+ "description": "The label for version current"
+ },
+ "sidebar.tutorialSidebar.category.社区": {
+ "message": "社区",
+ "description": "The label for category 社区 in sidebar tutorialSidebar"
+ },
+ "sidebar.tutorialSidebar.category.贡献规约": {
+ "message": "贡献规约",
+ "description": "The label for category 贡献规约 in sidebar tutorialSidebar"
+ },
+ "sidebar.tutorialSidebar.category.user_docs": {
+ "message": "user_docs",
+ "description": "The label for category user_docs in sidebar tutorialSidebar"
+ },
+ "sidebar.tutorialSidebar.category.用户指南": {
+ "message": "用户指南",
+ "description": "The label for category 用户指南 in sidebar tutorialSidebar"
+ },
+ "sidebar.tutorialSidebar.category.用户指南.link.generated-index.description": {
+ "message": "帮助想要了解 Hippo4J 的用户快速掌握核心开发理念。",
+ "description": "The generated-index page description for category 用户指南 in sidebar tutorialSidebar"
+ },
+ "sidebar.tutorialSidebar.category.快速开始": {
+ "message": "快速开始",
+ "description": "The label for category 快速开始 in sidebar tutorialSidebar"
+ },
+ "sidebar.tutorialSidebar.category.依赖配置中心": {
+ "message": "依赖配置中心",
+ "description": "The label for category 依赖配置中心 in sidebar tutorialSidebar"
+ },
+ "sidebar.tutorialSidebar.category.无中间件依赖": {
+ "message": "无中间件依赖",
+ "description": "The label for category 无中间件依赖 in sidebar tutorialSidebar"
+ },
+ "sidebar.tutorialSidebar.category.运维指南": {
+ "message": "运维指南",
+ "description": "The label for category 运维指南 in sidebar tutorialSidebar"
+ },
+ "sidebar.tutorialSidebar.category.开发者手册": {
+ "message": "开发者手册",
+ "description": "The label for category 开发者手册 in sidebar tutorialSidebar"
+ },
+ "sidebar.tutorialSidebar.category.开发者手册.link.generated-index.description": {
+ "message": "Hippo4J 留给使用者能够扩展的知识点。",
+ "description": "The generated-index page description for category 开发者手册 in sidebar tutorialSidebar"
+ },
+ "sidebar.tutorialSidebar.category.其它": {
+ "message": "其它",
+ "description": "The label for category 其它 in sidebar tutorialSidebar"
+ },
+ "sidebar.user_docs.category.用户指南": {
+ "message": "用户指南",
+ "description": "The label for category 用户指南 in sidebar user_docs"
+ },
+ "sidebar.user_docs.category.用户指南.link.generated-index.description": {
+ "message": "帮助想要了解 Hippo4J 的用户快速掌握核心开发理念。",
+ "description": "The generated-index page description for category 用户指南 in sidebar user_docs"
+ },
+ "sidebar.user_docs.category.快速开始": {
+ "message": "快速开始",
+ "description": "The label for category 快速开始 in sidebar user_docs"
+ },
+ "sidebar.user_docs.category.依赖配置中心": {
+ "message": "依赖配置中心",
+ "description": "The label for category 依赖配置中心 in sidebar user_docs"
+ },
+ "sidebar.user_docs.category.无中间件依赖": {
+ "message": "无中间件依赖",
+ "description": "The label for category 无中间件依赖 in sidebar user_docs"
+ },
+ "sidebar.user_docs.category.运维指南": {
+ "message": "运维指南",
+ "description": "The label for category 运维指南 in sidebar user_docs"
+ },
+ "sidebar.user_docs.category.开发者手册": {
+ "message": "开发者手册",
+ "description": "The label for category 开发者手册 in sidebar user_docs"
+ },
+ "sidebar.user_docs.category.开发者手册.link.generated-index.description": {
+ "message": "Hippo4J 留给使用者能够扩展的知识点。",
+ "description": "The generated-index page description for category 开发者手册 in sidebar user_docs"
+ },
+ "sidebar.user_docs.category.其它": {
+ "message": "其它",
+ "description": "The label for category 其它 in sidebar user_docs"
+ },
+ "sidebar.community.category.贡献规约": {
+ "message": "贡献规约",
+ "description": "The label for category 贡献规约 in sidebar community"
+ }
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/_category_.json b/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/_category_.json
new file mode 100644
index 00000000..bcd256c9
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/_category_.json
@@ -0,0 +1,7 @@
+{
+ "label": "社区",
+ "position": 1,
+ "link": {
+ "type": "generated-index"
+ }
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/contributor.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/contributor.md
new file mode 100644
index 00000000..f0185ad3
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/contributor.md
@@ -0,0 +1,24 @@
+---
+sidebar_position: 1
+---
+
+# 贡献指南
+
+Git Commit Log 尽量使用英文。
+
+Pull Request 尽量保持单一,不同语义的代码贡献应拆分多个 Pull Request。
+
+为了让您的 GitHub ID 显示在 Contributor 列表中,别忘了以下设置:
+
+```shell
+git config --global user.name "username"
+git config --global user.email "GitHub 账号邮箱"
+```
+
+## 贡献者列表
+
+您可以在 [Hippo4J](https://github.com/opengoofy/hippo4j/graphs/contributors) 和 [Hippo4J Console](https://github.com/opengoofy/hippo4j-console) 的贡献列表中找到全部的贡献者名单。
+
+
+
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/dev_convention/_category_.json b/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/dev_convention/_category_.json
new file mode 100644
index 00000000..cb875453
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/dev_convention/_category_.json
@@ -0,0 +1,7 @@
+{
+ "label": "贡献规约",
+ "position": 2,
+ "link": {
+ "type": "generated-index"
+ }
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/dev_convention/code.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/dev_convention/code.md
new file mode 100644
index 00000000..f91acdbe
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/dev_convention/code.md
@@ -0,0 +1,8 @@
+---
+sidebar_position: 2
+---
+
+# 代码规约
+
+1. 代码提交前,执行 `mvn spotless:apply` 保证代码格式符合规范。
+2. 代码中不要出现无意义的空行。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/dev_convention/document.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/dev_convention/document.md
new file mode 100644
index 00000000..923ad81d
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/dev_convention/document.md
@@ -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 Gbps,SSD 一共有 20 TB。
+
+錯誤:
+
+> 我家的光纖入屋寬頻有 10Gbps,SSD 一共有 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 元。
+
+錯誤:
+
+> 這件蛋糕只賣 1000 元。
+
+例外:在設計稿、宣傳海報中如出現極少量數字的情形時,為方便文字對齊,是可以使用全形數字的。
+
+### 遇到完整的英文整句、特殊名詞,其內容使用半形標點
+
+正確:
+
+> 賈伯斯那句話是怎麼說的?「Stay hungry, stay foolish.」
+
+> 推薦你閱讀《Hackers & Painters: Big Ideas from the Computer Age》,非常的有趣。
+
+錯誤:
+
+> 賈伯斯那句話是怎麼說的?「Stay hungry,stay foolish。」
+
+> 推薦你閱讀《Hackers&Painters:Big 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](#) 並分配给相關同事。
+
+> 訪問我們網站的最新動態,請[點擊這裡](#)進行訂閱!
+
+### 簡體中文使用直角引號
+
+用法:
+
+> 「老师,『有条不紊』的『紊』是什么意思?」
+
+對比用法:
+
+> “老师,‘有条不紊’的‘紊’是什么意思?”
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/developer.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/developer.md
new file mode 100644
index 00000000..03cdd4e3
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/developer.md
@@ -0,0 +1,82 @@
+---
+sidebar_position: 2
+---
+
+# 核心开发者
+
+
+
+## 成为核心开发者
+
+持续对 Hippo-4J 进行贡献, 粗略评估,完成 10 次 PR 贡献即可成为核心开发者。 其中包括完成 2 个 [good pro issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+pro+issue%22) 或以上,以及 若干个 [good first issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)。
+
+:::note
+会根据 PR 质量提供个性化评估,有可能一个或两个质量较高 PR 即可成为核心开发者。参考:[重构 DynamicThreadPoolExecutor 功能扩展逻辑](https://github.com/opengoofy/hippo4j/pull/854)
+:::
+
+成为核心开发者后,会为该 GitHub 账号获取 Jetbrains 全家桶 Licenses,有效期为 1 年。不用再为破解而烦恼,感受随时升级的快乐。
+
+:::note
+距离到期两周前,会再次申请 Jetbrains Licenses。有点类似于无限续约的感觉,在此感谢 Jetbrains 公司对开源的支持。
+:::
+
+截至 `2022-10-30` 当天,已为登记的 7 位核心开发者成功申请 Licenses。
+
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/powered-by.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/powered-by.md
new file mode 100644
index 00000000..635d9011
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/powered-by.md
@@ -0,0 +1,37 @@
+---
+sidebar_position: 3
+---
+
+# 采用公司
+
+## 登记
+
+欢迎采用了 Hippo4J 的公司在此登记,非常感谢大家对 Hippo4J 的关注和支持,这是我们前进最大的动力。
+
+请按公司名 + 首页的格式在 [此处](https://github.com/opengoofy/hippo4j/issues/13) 登记。
+
+## 谁在使用 Hippo4J
+
+共计 21+ 家公司生产接入 Hippo4J。按照公司登记时间排序。
+
+- [身边云](https://serviceshare.com)
+- [Medbanks](https://www.medbanks.cn)
+- [北京智合联创科技有限公司](http://www.zhlc.com.cn)
+- [神州数码](http://www.digitalchina.com)
+- [payermax](https://www.payermax.com/)
+- [轻松到家](http://www.uyess.com/index.html)
+- [某商业银行股份有限公司](https://github.com/opengoofy/hippo4j/issues/13)
+- [某国际物流信息股份有限公司](https://github.com/opengoofy/hippo4j/issues/13)
+- [萨科(深圳)科技有限公司](https://www.lbdj.com/)
+- [广东天枢新能源科技有限公司](https://gd-tianshu.com/)
+- [FitTime](http://fittime.com/)
+- [百强国际物流](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/)
+- [远眺网络科技有限公司](https://www.yuantiaokj.com/)
+- [浙江吉利控股集团有限公司](https://www.geely.com/)
+- [三立人(深圳)科技有限公司-焦内](https://www.bananain.com/)
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/sponsor.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/sponsor.md
new file mode 100644
index 00000000..c73fc64a
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/community/sponsor.md
@@ -0,0 +1,23 @@
+---
+sidebar_position: 4
+---
+
+# 支持开源
+
+如果您正在使用这个项目并感觉良好,或者是想支持我继续开发,通过以下二维码一次性捐款。
+
+在这里承诺将,将收到的所有赞助支持资金完全公开化,且后续资金用途仅 Hippo-4J 项目的运转。
+
+
+
+感谢给予支持的朋友,您的支持是 Hippo-4J 社区前进的动力 🎉
+
+| | ID | 赞赏金额 | 时间 | 备注 |
+|-----|--|-------|------------|--------------------|
+| 1 | 六月飞雪 | 30.00 | 2021-12-30 | 代码设计很优雅的一款框架,继续加油! |
+| 2 | 孙大圣 | 26.6 | 2022-03-23 | 学习一下😁😁 |
+| 3 | Easy 点 | 66.00 | 2022-04-09 | 好货好技术当加赏 |
+| 4 | 捷克 | 30.00 | 2022-05-21 | 非常不错的框架,点赞 |
+| 5 | 吃猫的饼干 | 88.00 | 2022-08-21 | 👍 |
+| 6 | 不忘初心· | 66.00 | 2022-10-28 | Nice! |
+| 7 | 时刻· | 6.00 | 2022-10-30 | -! |
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/dev_manual/_category_.json b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/dev_manual/_category_.json
new file mode 100644
index 00000000..11f12432
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/dev_manual/_category_.json
@@ -0,0 +1,8 @@
+{
+ "label": "开发者手册",
+ "position": 5,
+ "link": {
+ "type": "generated-index",
+ "description": "Hippo4J 留给使用者能够扩展的知识点。"
+ }
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/dev_manual/rejected-policy-custom.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/dev_manual/rejected-policy-custom.md
new file mode 100644
index 00000000..1f2cf694
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/dev_manual/rejected-policy-custom.md
@@ -0,0 +1,57 @@
+---
+sidebar_position: 1
+---
+
+# 拒绝策略自定义
+
+Hippo4J 通过 SPI 的方式对拒绝策略进行扩展,可以让用户在 Hippo4J 中完成自定义拒绝策略实现。
+
+## Hippo4J Server 拒绝策略扩展
+
+自定义拒绝策略,实现 `CustomRejectedExecutionHandler` 接口,示例如下:
+
+```java
+public class ErrorLogRejectedExecutionHandler implements CustomRejectedExecutionHandler {
+
+ @Override
+ public Integer getType() {
+ return 12;
+ }
+
+ @Override
+ public RejectedExecutionHandler generateRejected() {
+ return new CustomErrorLogRejectedExecutionHandler();
+ }
+
+ public static class CustomErrorLogRejectedExecutionHandler implements RejectedExecutionHandler {
+
+ @Override
+ public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
+ Logger logger = LoggerFactory.getLogger(this.getClass());
+ logger.error("线程池抛出拒绝策略");
+ }
+ }
+}
+```
+
+创建 `src/main/resources/META-INF/services` 目录,创建 SPI 自定义拒绝策略文件 `cn.hippo4j.common.executor.support.CustomRejectedExecutionHandler`。
+
+`cn.hippo4j.common.executor.support.CustomRejectedExecutionHandler` 文件内仅放一行自定义拒绝策略全限定名即可,示例:
+
+```text
+cn.hippo4j.example.core.handler.ErrorLogRejectedExecutionHandler
+```
+
+创建、修改线程池页面选择 `CustomRejectedPolicy(自定义 SPI 策略)`。
+
+
+
+拒绝策略触发时,完成上述代码效果,仅打印异常日志提示。
+
+```text
+2022-08-01 21:27:49.515 ERROR 48928 --- [ateHandler.test] r$CustomErrorLogRejectedExecutionHandler : 线程池抛出拒绝策略
+```
+
+:::note
+具体参考 `hippo4j-example/hippo4j-spring-boot-starter-example` 模块。
+:::
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/dev_manual/rejected-policy-info.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/dev_manual/rejected-policy-info.md
new file mode 100644
index 00000000..d5c68138
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/dev_manual/rejected-policy-info.md
@@ -0,0 +1,50 @@
+---
+sidebar_position: 0
+---
+
+# 内置拒绝策略
+
+内置两种拒绝策略说明:
+
+**RunsOldestTaskPolicy**:添加新任务并由主线程运行最早的任务。
+
+```java
+public class RunsOldestTaskPolicy implements RejectedExecutionHandler {
+
+ @Override
+ public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
+ if (executor.isShutdown()) {
+ return;
+ }
+ BlockingQueue workQueue = executor.getQueue();
+ Runnable firstWork = workQueue.poll();
+ boolean newTaskAdd = workQueue.offer(r);
+ if (firstWork != null) {
+ firstWork.run();
+ }
+ if (!newTaskAdd) {
+ executor.execute(r);
+ }
+ }
+}
+```
+
+**SyncPutQueuePolicy**:主线程把拒绝任务以阻塞的方式添加到队列。
+
+```java
+@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);
+ }
+ }
+}
+```
\ No newline at end of file
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/_category_.json b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/_category_.json
new file mode 100644
index 00000000..72b1e151
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/_category_.json
@@ -0,0 +1,7 @@
+{
+ "label": "快速开始",
+ "position": 3,
+ "link": {
+ "type": "generated-index"
+ }
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/config/_category_.json b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/config/_category_.json
new file mode 100644
index 00000000..78b3d9c4
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/config/_category_.json
@@ -0,0 +1,5 @@
+{
+ "label": "依赖配置中心",
+ "position": 2,
+ "collapsed": true
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/config/hippo4j-config-default.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/config/hippo4j-config-default.md
new file mode 100644
index 00000000..9c9e0fc9
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/config/hippo4j-config-default.md
@@ -0,0 +1,45 @@
+---
+sidebar_position: 4
+---
+
+# 参数默认配置
+
+曾有多名小伙伴反馈说,项目中线程池一多,配置文件中配置就显得很臃肿。为此 hippo4j-config 开发出了动态线程池默认配置。
+
+```yaml
+spring:
+ dynamic:
+ thread-pool:
+ default-executor:
+ core-pool-size: 4
+ maximum-pool-size: 6
+ blocking-queue: ResizableCapacityLinkedBlockingQueue
+ queue-capacity: 1024
+ execute-time-out: 1000
+ keep-alive-time: 9999
+ rejected-handler: AbortPolicy
+ active-alarm: 90
+ capacity-alarm: 85
+ alarm: true
+ allow-core-thread-time-out: true
+ notify:
+ interval: 5
+ receives: chen.ma
+ executors:
+ - thread-pool-id: message-produce
+ - thread-pool-id: message-consume
+ core-pool-size: 80
+ maximum-pool-size: 100
+ execute-time-out: 1000
+ notify:
+ interval: 6
+ receives: chen.ma
+```
+
+`spring.dynamic.thread-pool.executors` 层级下,仅需要配置 `thread-pool-id`,其余配置从 `spring.dynamic.thread-pool.default-executor` 读取。
+
+如果 `spring.dynamic.thread-pool.executors` 下配置和 `spring.dynamic.thread-pool.default-executor` 冲突,以前者为主。
+
+通过该自定义配置方式,可减少大量重复线程池参数配置项,提高核心配置简洁度。
+
+提示:`spring.dynamic.thread-pool.default-executor` 层级下参数,不提供动态刷新功能。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/config/hippo4j-config-monitor.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/config/hippo4j-config-monitor.md
new file mode 100644
index 00000000..72528638
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/config/hippo4j-config-monitor.md
@@ -0,0 +1,117 @@
+---
+sidebar_position: 3
+---
+
+# 线程池监控
+
+## 线程池监控配置
+
+监控前置条件:需要先完成 hippo4j-config 的 [接入工作](/docs/user_docs/getting_started/config/hippo4j-config-start)。
+
+接下来引入 SpringBoot Actuator。Spring 2.x 一般都有版本指定,所以这里不用写版本号。
+
+```xml
+
+ io.micrometer
+ micrometer-registry-prometheus
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+```
+
+添加动态线程池监控相关配置:
+
+```yaml
+management:
+ metrics:
+ export:
+ prometheus:
+ enabled: true
+ server:
+ port: 29999 # 可选配置,如果不配置该 port,直接使用 ${server.port}
+ endpoints:
+ web:
+ exposure:
+ include: '*' # 测试使用,开启了所有端点,生产环境不建议 *
+spring:
+ dynamic:
+ thread-pool:
+ collect-type: micrometer
+```
+
+项目启动,访问 `http://localhost:29999/actuator/prometheus` 出现 `dynamic_thread_pool_` 前缀的指标,即为成功。
+
+
+
+## 配置 Prometheus
+
+通过 Docker 启动 Prometheus 服务。
+
+```shell
+docker run -d -p 9090:9090 --name prometheus prom/prometheus
+```
+
+添加 Prometheus 抽取数据任务。
+
+```shell
+# 进入 prometheus 容器内部
+docker exec -it prometheus /bin/sh
+# 编辑 prometheus 配置文件
+vi /etc/prometheus/prometheus.yml
+```
+
+scrape_configs 节点下新添加一个 job,如果 Prometheus 是 Docker 方式部署,`{scrape_configs.static_configs.targets}` 需要写本机的 IP。
+
+```yaml
+scrape_configs:
+ - job_name: 'dynamic-thread-pool-job'
+ scrape_interval: 5s
+ metrics_path: '/actuator/prometheus'
+ static_configs:
+ - targets: [ '127.0.0.1:29999' ]
+```
+
+配置成功后 `exit` 退出容器,并进行 Prometheus 容器重启 `docker restart prometheus`。
+
+访问 Prometheus 控制台 `http://localhost:9090/graph` 路径,能够展示相关指标即为配置成功。
+
+
+
+## 配置 Grafana
+
+```shell
+docker run -d -p 3000:3000 --name=grafana grafana/grafana
+```
+
+访问 Grafana 地址,[http://localhost:3000](http://localhost:3000) 用户名密码:`admin`
+
+Grafana 访问 `http://localhost:3000/datasources` 导入 Prometheus 数据源。
+
+
+
+> 如果 Prometheus 为 Docker 方式部署,HTTP URL 需要为本地 IP,比如:http://192.168.1.5:9090
+
+关注公众号 `龙台的技术笔记`,回复:`监控`,获取 Hippo4J Grafana DashBoard JSON 配置。
+
+| 公众号 | 回复关键词 |
+|:------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------------------------------:|
+|  |  |
+
+获取到 JSON 文件后,通过 `http://localhost:3000/dashboard/import` 将 JSON 文件导入至 Grafana DashBoard。
+
+
+
+下拉框内动态选择创建好的 Prometheus 数据源,并点击 `Import`。
+
+
+
+即可使用炫酷的 Hippo-4J 动态线程池监控 DashBoard。大家伙儿也可以根据个人喜好进行定制 DashBoard,如果觉得有优化点,欢迎和我联系贡献。
+
+
+
+如果项目客户端启动多个示例,动态线程池监控效果图如下:
+
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/config/hippo4j-config-more.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/config/hippo4j-config-more.md
new file mode 100644
index 00000000..2511b4f3
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/config/hippo4j-config-more.md
@@ -0,0 +1,80 @@
+---
+sidebar_position: 3
+---
+
+# 个性化配置
+
+以下所述特性自 hippo4j-config v1.4.2 及以上版本提供,由 hippo4j 核心开发者 [@pizihao](https://github.com/pizihao) 完成相应功能开发。
+
+## 需求背景
+
+**1)容器及三方框架线程池自定义启用**
+
+最初设计容器线程池和三方框架线程池的动态变更是和启动无关的。也就是说,启动时不会根据配置文件中相关参数去修改两者对应的线程池配置。
+
+这么设计的初衷是因为,不想让 hippo4j 过多的去介入框架原有的功能。因为容器和三方框架都支持线程池参数的自定义。
+
+也就造成,可能你在配置中心配置了对应的容器和三方框架线程池参数,启动时是无效的。但当修改配置文件任一配置,容器和三方框架线程池配置将生效。
+
+为了更好的用户体验,决定加入启用标识来控制:是否在项目初始化启动时,对容器和三方框架线程池参数进行修改。
+
+**2)客户端集群个性化配置**
+
+大家都知道,hippo4j-config 是依赖配置中心做线程池配置动态变更。这种模式有一种缺点:改动配置文件后,所有客户端都会变更。
+
+有些小伙伴希望 hippo4j-config 能够像 hippo4j-server 一样,能够针对单独的客户端进行配置变更。
+
+## 容器及三方框架线程池自定义启用
+
+容器及三方框架线程池添加启用配置,为了保持统一,动态线程池配置中也有该参数配置。配置项默认开启。
+
+```yaml
+spring:
+ dynamic:
+ thread-pool:
+ tomcat:
+ enable: true
+ executors:
+ - thread-pool-id: message-consume
+ enable: false
+ adapter-executors:
+ - threadPoolKey: 'input'
+ enable: true
+```
+
+## 客户端集群个性化配置
+
+分别在动态线程池、容器线程池以及三方框架线程池配置下增加 `nodes` 配置节点,通过该配置可匹配需要变更的节点。
+
+```yaml
+spring:
+ dynamic:
+ thread-pool:
+ tomcat:
+ nodes: 192.168.1.5:*,192.168.1.6:8080
+ executors:
+ - thread-pool-id: message-consume
+ nodes: 192.168.1.5:*
+ adapter-executors:
+ - threadPoolKey: 'input'
+ nodes: 192.168.1.5:*
+```
+
+来一段代码方法中的注释,大家就基本明白如何使用了。
+
+```java
+/**
+ * Matching nodes
+ * nodes is ip + port.Get 'nodes' in the new Properties,Compare this with the ip + port of Application.
+ * support prefix pattern matching. e.g:
+ *
+ * - 192.168.1.5:* -- Matches all ports of 192.168.1.5
+ * - 192.168.1.*:2009 -- Matches 2009 port of 192.168.1.*
+ * - * -- all
+ * - empty -- all
+ *
+ * The format of ip + port is ip : port.
+ */
+```
+
+`nodes` 可与 `enable` 同时使用。如此,基于配置中心的动态线程池实现方式,将能够更方便的支持个性化需求。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/config/hippo4j-config-springboot1x-adapter.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/config/hippo4j-config-springboot1x-adapter.md
new file mode 100644
index 00000000..693dd341
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/config/hippo4j-config-springboot1x-adapter.md
@@ -0,0 +1,121 @@
+---
+sidebar_position: 5
+---
+
+# 适配SpringBoot1x
+
+目前已支持 Nacos、Apollo 配置中心适配 SpringBoot 1.5.x 版本。
+
+```xml
+
+ cn.hippo4j
+ hippo4j-config-spring-boot-1x-starter
+ 1.4.2
+
+```
+
+Nacos SpringBoot 配置如下:
+
+```yaml
+spring:
+ cloud:
+ nacos:
+ config:
+ ext-config:
+ - data-id: hippo4j-nacos.yaml
+ group: DEFAULT_GROUP
+ refresh: true
+ server-addr: 127.0.0.1:8848
+ dynamic:
+ thread-pool:
+ config-file-type: yml
+ nacos:
+ data-id: hippo4j-nacos.yaml
+ group: DEFAULT_GROUP
+```
+
+Apollo SpringBoot 配置如下:
+
+```yaml
+apollo:
+ autoUpdateInjectedSpringProperties: true
+ bootstrap:
+ eagerLoad:
+ enabled: true
+ enabled: true
+ namespaces: application
+ meta: http://127.0.0.1:8080
+app:
+ id: dynamic-threadpool-example
+spring:
+ dynamic:
+ thread-pool:
+ apollo:
+ namespace: application
+```
+
+动态线程池通用配置如下:
+
+```yaml
+management:
+ context-path: /actuator
+ security:
+ enabled: false
+server:
+ port: 8091
+ servlet:
+ context-path: /example
+spring:
+ application:
+ name: dynamic-threadpool-example
+ dynamic:
+ thread-pool:
+ banner: true
+ check-state-interval: 5
+ collect-type: micrometer
+ config-file-type: properties
+ enable: true
+ executors:
+ - active-alarm: 80
+ alarm: true
+ allow-core-thread-time-out: true
+ blocking-queue: LinkedBlockingQueue
+ capacity-alarm: 80
+ core-pool-size: 1
+ execute-time-out: 1000
+ keep-alive-time: 6691
+ maximum-pool-size: 1
+ notify:
+ interval: 8
+ receives: chen.ma
+ queue-capacity: 1
+ rejected-handler: AbortPolicy
+ thread-name-prefix: message-consume
+ thread-pool-id: message-consume
+ - active-alarm: 80
+ alarm: true
+ allow-core-thread-time-out: true
+ blocking-queue: LinkedBlockingQueue
+ capacity-alarm: 80
+ core-pool-size: 1
+ execute-time-out: 1000
+ keep-alive-time: 6691
+ maximum-pool-size: 1
+ notify:
+ interval: 8
+ receives: chen.ma
+ queue-capacity: 1
+ rejected-handler: AbortPolicy
+ thread-name-prefix: message-produce
+ thread-pool-id: message-produce
+ notify-platforms:
+ - platform: WECHAT
+ token: ac0426a5-c712-474c-9bff-72b8b8f5caff
+ profiles:
+ active: dev
+```
+
+具体 Demo 运行请参考以下示例模块,已验证对应线程池动态变更、报警以及运行时监控功能。
+
+- `/hippo4j-config-nacos-spring-boot-1x-starter-example`
+- `hippo4j-example/hippo4j-config-apollo-spring-boot-1x-starter-example`
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/config/hippo4j-config-start.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/config/hippo4j-config-start.md
new file mode 100644
index 00000000..33f658c2
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/config/hippo4j-config-start.md
@@ -0,0 +1,193 @@
+---
+sidebar_position: 1
+---
+
+# 接入流程
+
+Nacos、Apollo、Zookeeper、ETCD、Polaris 配置中心任选其一。
+
+## hippo4j 配置
+
+```xml
+
+ cn.hippo4j
+ hippo4j-config-spring-boot-starter
+ 1.4.2
+
+```
+
+启动类上添加注解 `@EnableDynamicThreadPool`。
+
+```java
+@SpringBootApplication
+@EnableDynamicThreadPool
+public class ExampleApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(ExampleApplication.class, args);
+ }
+}
+```
+
+SpringBoot 应用配置文件添加:
+
+```yaml
+server:
+ port: 8090
+ servlet:
+ context-path: /example
+
+spring:
+ profiles:
+ active: dev
+
+ dynamic:
+ thread-pool:
+ # 是否开启动态线程池
+ enable: true
+ # 是否打印 banner
+ banner: true
+ # 是否开启线程池数据采集,对接 Micrometer、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、ETCD、Polaris 任选其一
+ nacos:
+ data-id: xxx
+ group: xxx
+ apollo:
+ namespace: xxxx
+ # 配置中心文件格式
+ config-file-type: yml
+ # tomcat、undertow、jetty 三种容器线程池,任选其一
+ undertow:
+ core-pool-size: 100
+ maximum-pool-size: 200
+ keep-alive-time: 1000
+ # 全局通知配置-是否报警
+ 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
+ # 阻塞队列名称,参考 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
+ queue-capacity: 1
+ execute-time-out: 1000
+ blocking-queue: 'LinkedBlockingQueue'
+ rejected-handler: 'AbortPolicy'
+ keep-alive-time: 1024
+ allow-core-thread-time-out: true
+ thread-name-prefix: 'message-consume'
+ alarm: true
+ active-alarm: 80
+ capacity-alarm: 80
+ notify:
+ interval: 8
+ receives: xxx
+```
+
+## ThreadPoolExecutor 适配
+
+添加线程池配置类,通过 `@DynamicThreadPool` 注解修饰。`threadPoolId` 为服务端创建的线程池 ID。
+
+```java
+package cn.hippo4j.example;
+
+import cn.hippo4j.core.executor.DynamicThreadPool;
+import cn.hippo4j.core.executor.support.ThreadPoolBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import java.util.concurrent.ThreadPoolExecutor;
+
+@Configuration
+public class ThreadPoolConfig {
+
+ @Bean
+ @DynamicThreadPool
+ public ThreadPoolExecutor messageConsumeDynamicExecutor() {
+ String threadPoolId = "message-consume";
+ ThreadPoolExecutor messageConsumeDynamicExecutor = ThreadPoolBuilder.builder()
+ .threadFactory(threadPoolId)
+ .threadPoolId(threadPoolId)
+ .dynamicPool()
+ .build();
+ return messageConsumeDynamicExecutor;
+ }
+
+ @Bean
+ @DynamicThreadPool
+ public ThreadPoolExecutor messageProduceDynamicExecutor() {
+ String threadPoolId = "message-produce";
+ ThreadPoolExecutor messageProduceDynamicExecutor = ThreadPoolBuilder.builder()
+ .threadFactory(threadPoolId)
+ .threadPoolId(threadPoolId)
+ .dynamicPool()
+ .build();
+ return messageProduceDynamicExecutor;
+ }
+
+}
+```
+
+通过 ThreadPoolBuilder 构建动态线程池,只有 threadFactory、threadPoolId 为必填项,其它参数会从配置中心拉取。
+
+项目中使用上述定义的动态线程池,如下所示:
+
+```java
+@Resource
+private ThreadPoolExecutor messageConsumeDynamicExecutor;
+
+messageConsumeDynamicExecutor.execute(() -> xxx);
+
+@Resource
+private ThreadPoolExecutor messageProduceDynamicExecutor;
+
+messageProduceDynamicExecutor.execute(() -> xxx);
+```
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/difference.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/difference.md
new file mode 100644
index 00000000..4e07d71b
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/difference.md
@@ -0,0 +1,37 @@
+---
+sidebar_position: 0
+---
+
+# 运行模式介绍
+
+1.1.0 版本发布后,Hippo-4J 分为两种使用模式:轻量级依赖配置中心以及无中间件依赖版本。
+
+
+
+### hippo4j-config
+
+**轻量级动态线程池管理**,依赖 Nacos、Apollo、Zookeeper、ETCD、Polaris 等三方配置中心(任选其一)完成线程池参数动态变更,支持运行时报警、监控等功能。
+
+> 监控功能配置详见:[线程池监控](/docs/user_docs/getting_started/config/hippo4j-config-monitor)
+
+
+
+### hippo4j-server
+
+**部署 hippo4j-server 服务**,通过可视化 Web 界面完成线程池的创建、变更以及查看,不依赖三方中间件。
+
+相比较 hippo4j-config,功能会更强大,但同时也引入了一定的复杂性。需要部署一个 Java 服务,以及依赖 MySQL 数据库。
+
+
+
+### 使用总结
+
+| | hippo4j-config | hippo4j-server |
+| ---- | ---------------------------------------------------- | ------------------------------------------------------------ |
+| 依赖 | Nacos、Apollo、Zookeeper、ETCD、Polaris 配置中心(任选其一) | 部署 Hippo-4J Server(内部无依赖中间件) |
+| 使用 | 配置中心补充线程池相关参数 | Hippo-4J Server Web 控制台添加线程池记录 |
+| 功能 | 包含基础功能:参数动态化、运行时监控、报警等 | 基础功能之外扩展控制台界面、线程池堆栈查看、线程池运行信息实时查看、历史运行信息查看、线程池配置集群个性化等 |
+
+使用建议:根据公司情况选择,如果基本功能可以满足使用,选择 hippo4j-config 使用即可;如果希望更多的功能,可以选择 hippo4j-server。
+
+**两者在进行替换的时候,无需修改业务代码**。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/hippo4j-adapter.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/hippo4j-adapter.md
new file mode 100644
index 00000000..030367e1
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/hippo4j-adapter.md
@@ -0,0 +1,72 @@
+---
+sidebar_position: 6
+---
+
+# 三方框架线程池适配
+
+Hippo4J 目前已支持的三方框架线程池列表:
+
+- Dubbo
+- Hystrix
+- RabbitMQ
+- RocketMQ
+- AlibabaDubbo
+- RocketMQSpringCloudStream
+- RabbitMQSpringCloudStream
+
+引入 Hippo4J Server 或 Core 的 Maven Jar 坐标后,还需要引入对应的框架适配 Jar:
+
+```xml
+
+ cn.hippo4j
+
+ hippo4j-spring-boot-starter-adapter-dubbo
+
+ hippo4j-spring-boot-starter-adapter-alibaba-dubbo
+
+ hippo4j-spring-boot-starter-adapter-hystrix
+
+ hippo4j-spring-boot-starter-adapter-rabbitmq
+
+ hippo4j-spring-boot-starter-adapter-rocketmq
+
+ hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rocketmq
+
+ hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rabbitmq
+ 1.4.2
+
+```
+
+如果想省事,仅需引入一个全量包,框架底层会根据条件判断加载具体线程池适配器。
+
+```xml
+
+ cn.hippo4j
+ hippo4j-spring-boot-starter-adapter-all
+ 1.4.2
+
+```
+
+## Hippo4J Server
+
+Hippo4J Server 仅需要引入上述 Jar 包,即可在 Hippo4J Server 的控制台进行查看及修改三方框架线程池。
+
+
+
+## Hippo4J Config
+
+Hippo4J Config 除了依赖上述适配 Jar 包外,还需要在配置中心添加以下配置项。
+
+```yaml
+spring:
+ dynamic:
+ thread-pool:
+ # 省略其它配置
+ adapter-executors:
+ # threadPoolKey 代表线程池标识
+ - threadPoolKey: 'input'
+ # mark 为三方线程池框架类型,参见文初已支持框架集合
+ mark: 'RocketMQSpringCloudStream'
+ corePoolSize: 10
+ maximumPoolSize: 10
+```
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/img/docsVersionDropdown.png b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/img/docsVersionDropdown.png
new file mode 100644
index 00000000..97e41646
Binary files /dev/null and b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/img/docsVersionDropdown.png differ
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/img/grafana-monitor.jpg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/img/grafana-monitor.jpg
new file mode 100644
index 00000000..336bd980
Binary files /dev/null and b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/img/grafana-monitor.jpg differ
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/img/localeDropdown.png b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/img/localeDropdown.png
new file mode 100644
index 00000000..e257edc1
Binary files /dev/null and b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/img/localeDropdown.png differ
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/server/_category_.json b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/server/_category_.json
new file mode 100644
index 00000000..4063c17f
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/server/_category_.json
@@ -0,0 +1,5 @@
+{
+ "label": "无中间件依赖",
+ "position": 3,
+ "collapsed": true
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/server/hippo4j-server-config.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/server/hippo4j-server-config.md
new file mode 100644
index 00000000..24bf9a13
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/server/hippo4j-server-config.md
@@ -0,0 +1,19 @@
+---
+sidebar_position: 4
+---
+
+# 服务端配置
+
+`hippo4j.core.clean-history-data-enable`
+
+是否开启线程池历史数据清洗,默认开启。
+
+`hippo4j.core.clean-history-data-period`
+
+线程池历史数据保留时间,默认值:30,单位分钟。
+
+服务端会保留这个配置时间的数据,超过这个时间则会被清理。比如按照默认值 30 分钟来说,12:00 收集到的数据,12:30 就会被清理删除。
+
+`hippo4j.core.monitor.report-type`
+
+客户端监控上报服务端类型,可选值:http、netty,默认 http。服务端开启 netty 配置后,需要在客户端对应开启才可生效。用来应对大量动态线程池监控场景。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/server/hippo4j-server-start.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/server/hippo4j-server-start.md
new file mode 100644
index 00000000..64b94ee3
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/getting_started/server/hippo4j-server-start.md
@@ -0,0 +1,127 @@
+---
+sidebar_position: 3
+---
+
+# 接入流程
+
+部署服务端,参考 [部署手册](/docs/user_docs/ops/hippo4j-server-deploy)。
+
+服务端创建 [租户、项目](/docs/user_docs/other/issue#租户和项目在-hippo4j-中是什么意思) 和线程池记录。
+
+需要注意,项目 ID 需要与配置文件 `{application.name}` 保持一致。
+
+:::note
+租户、项目、线程池 ID 如果由多个词组成,建议以 - 进行分割。比如:message-center。
+:::
+
+## Hippo4J 配置
+
+SpringBoot Pom 引入 Hippo4j Starter Jar。
+
+```xml
+
+ cn.hippo4j
+ hippo4j-spring-boot-starter
+ 1.4.2
+
+```
+
+启动类上添加注解 `@EnableDynamicThreadPool`。
+
+```java
+@SpringBootApplication
+@EnableDynamicThreadPool
+public class ExampleApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(ExampleApplication.class, args);
+ }
+}
+```
+
+SpringBoot 应用配置文件添加:
+
+```yaml
+spring:
+ profiles:
+ active: dev
+ application:
+ # 服务端创建的项目 id 需要与 application.name 保持一致
+ name: dynamic-threadpool-example
+ dynamic:
+ thread-pool:
+ # 服务端地址
+ server-addr: http://localhost:6691
+ # 用户名
+ username: admin
+ # 密码
+ password: 123456
+ # 租户 id, 对应 tenant 表
+ namespace: prescription
+ # 项目 id, 对应 item 表
+ item-id: ${spring.application.name}
+```
+
+## ThreadPoolExecutor 适配
+
+添加线程池配置类,通过 `@DynamicThreadPool` 注解修饰。`threadPoolId` 为服务端创建的线程池 ID。
+
+```java
+package cn.hippo4j.example;
+
+import cn.hippo4j.core.executor.DynamicThreadPool;
+import cn.hippo4j.core.executor.support.ThreadPoolBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+@Configuration
+public class ThreadPoolConfig {
+
+ @Bean
+ @DynamicThreadPool
+ public ThreadPoolExecutor messageConsumeDynamicExecutor() {
+ String threadPoolId = "message-consume";
+ ThreadPoolExecutor messageConsumeDynamicExecutor = ThreadPoolBuilder.builder()
+ .threadFactory(threadPoolId)
+ .threadPoolId(threadPoolId)
+ .dynamicPool()
+ .build();
+ return messageConsumeDynamicExecutor;
+ }
+
+ @Bean
+ @DynamicThreadPool
+ public ThreadPoolExecutor messageProduceDynamicExecutor() {
+ String threadPoolId = "message-produce";
+ ThreadPoolExecutor messageProduceDynamicExecutor = ThreadPoolBuilder.builder()
+ .threadFactory(threadPoolId)
+ .threadPoolId(threadPoolId)
+ .dynamicPool()
+ .build();
+ return messageProduceDynamicExecutor;
+ }
+
+}
+```
+
+通过 ThreadPoolBuilder 构建动态线程池,只有 threadFactory、threadPoolId 为必填项,其它参数会从 hippo4j-server 服务拉取。
+
+:::note
+创建线程池时建议填充实际的参数。如果在连接 Hippo4J Server 端失败时,会使用填充配置创建线程池。
+:::
+
+项目中使用上述定义的动态线程池,如下所示:
+
+```java
+@Resource
+private ThreadPoolExecutor messageConsumeDynamicExecutor;
+
+messageConsumeDynamicExecutor.execute(() -> xxx);
+
+@Resource
+private ThreadPoolExecutor messageProduceDynamicExecutor;
+
+messageProduceDynamicExecutor.execute(() -> xxx);
+```
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/intro.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/intro.md
new file mode 100644
index 00000000..fd9e5dcb
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/intro.md
@@ -0,0 +1,616 @@
+---
+sidebar_position: 1
+---
+
+# 简介
+
+## 线程池痛点
+
+线程池是一种基于池化思想管理线程的工具,使用线程池可以减少创建销毁线程的开销,避免线程过多导致系统资源耗尽。在高并发以及大批量的任务处理场景,线程池的使用是必不可少的。
+
+如果有在项目中实际使用线程池,相信你可能会遇到以下痛点:
+
+- 线程池随便定义,线程资源过多,造成服务器高负载。
+
+- 线程池参数不易评估,随着业务的并发提升,业务面临出现故障的风险。
+- 线程池任务执行时间超过平均执行周期,开发人员无法感知。
+- 线程池任务堆积,触发拒绝策略,影响既有业务正常运行。
+- 当业务出现超时、熔断等问题时,因为没有监控,无法确定是不是线程池引起。
+- 原生线程池不支持运行时变量的传递,比如 MDC 上下文遇到线程池就 GG。
+- 无法执行优雅关闭,当项目关闭时,大量正在运行的线程池任务被丢弃。
+- 线程池运行中,任务执行停止,怀疑发生死锁或执行耗时操作,但是无从下手。
+
+## 什么是 Hippo-4J
+
+Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池等功能,为业务系统提高线上运行保障能力。
+
+提供以下功能支持:
+
+- 全局管控 - 管理应用线程池实例。
+
+- 动态变更 - 应用运行时动态变更线程池参数,包括不限于:核心、最大线程数、阻塞队列容量、拒绝策略等。
+- 通知报警 - 内置四种报警通知策略,线程池活跃度、容量水位、拒绝策略以及任务执行时间超长。
+- 运行监控 - 实时查看线程池运行时数据,最近半小时线程池运行数据图表展示。
+- 功能扩展 - 支持线程池任务传递上下文;项目关闭时,支持等待线程池在指定时间内完成任务。
+- 多种模式 - 内置两种使用模式:[依赖配置中心](https://hippo4j.cn/docs/user_docs/getting_started/config/hippo4j-config-start) 和 [无中间件依赖](https://hippo4j.cn/docs/user_docs/getting_started/server/hippo4j-server-start)。
+- 容器管理 - Tomcat、Jetty、Undertow 容器线程池运行时查看和线程数变更。
+- 框架适配 - Dubbo、Hystrix、RabbitMQ、RocketMQ 等消费线程池运行时数据查看和线程数变更。
+
+## 快速开始
+
+对于本地演示目的,请参阅 [Quick start](https://hippo4j.cn/docs/user_docs/user_guide/quick-start)
+
+演示环境: [http://console.hippo4j.cn/index.html](http://console.hippo4j.cn/index.html)
+
+## 接入登记
+
+更多接入的公司,欢迎在 [登记地址](https://github.com/opengoofy/hippo4j/issues/13) 登记,登记仅仅为了产品推广。
+
+## 联系我
+
+
+
+扫码添加微信,备注:hippo4j,邀您加入群聊。若图片加载不出来,访问 [官网站点](https://hippo4j.cn/docs/user_docs/other/group)。
+
+## 友情链接
+
+- [[ 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 学习指南。
+
+## 贡献者
+
+感谢所有为项目作出贡献的开发者。如果有意贡献,参考 [good first issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)。
+
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/ops/_category_.json b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/ops/_category_.json
new file mode 100644
index 00000000..d5b7d1e8
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/ops/_category_.json
@@ -0,0 +1,7 @@
+{
+ "label": "运维指南",
+ "position": 4,
+ "link": {
+ "type": "generated-index"
+ }
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/ops/hippo4j-server-deploy.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/ops/hippo4j-server-deploy.md
new file mode 100644
index 00000000..f78457ba
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/ops/hippo4j-server-deploy.md
@@ -0,0 +1,45 @@
+---
+sidebar_position: 1
+---
+
+# 源码包部署
+
+[RELEASE](https://github.com/opengoofy/hippo4j/releases) 页面下载对应版本并进行解压。
+
+## 初始化
+
+修改数据库相关信息。
+
+```txt
+/conf/application.properties
+```
+
+如果是新运行 Hippo-4J,数据库执行下述 SQL 脚本即可。
+
+```txt
+/conf/hippo4j_manager.sql
+```
+
+如果是对已运行 Hippo-4J 升级,请查看 `/conf/sql-upgrade` 目录下,是否有目标版本对应的升级脚本。
+
+## 直接运行
+
+Mac Linux 启动执行。
+
+```txt
+sh ./bin/startup.sh
+```
+
+Windows 启动执行。
+
+```txt
+bin/startup.cmd
+```
+
+## 访问控制台
+
+启动成功后,访问链接。用户名密码:admin 123456
+
+```txt
+localhost:6691/index.html
+```
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/ops/server-docker.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/ops/server-docker.md
new file mode 100644
index 00000000..141c597a
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/ops/server-docker.md
@@ -0,0 +1,50 @@
+---
+sidebar_position: 2
+---
+
+# Docker部署
+
+## 镜像启动
+
+Docker 镜像默认使用内置 H2 数据库,数据持久化到 Docker 容器存储卷中。
+
+```shell
+docker run -d -p 6691:6691 --name hippo4j-server hippo4j/hippo4j-server
+```
+
+或者,底层存储数据库切换为 MySQL。`DATASOURCE_HOST` 需要切换为本地 IP,不能使用 `127.0.0.1` 或 `localhost`。
+
+```shell
+docker run -d -p 6691:6691 --name hippo4j-server \
+-e DATASOURCE_MODE=mysql \
+-e DATASOURCE_HOST=xxx.xxx.xxx.xxx \
+-e DATASOURCE_PORT=3306 \
+-e DATASOURCE_DB=hippo4j_manager \
+-e DATASOURCE_USERNAME=root \
+-e DATASOURCE_PASSWORD=root \
+hippo4j/hippo4j-server
+```
+
+访问 Server 控制台,路径 `http://localhost:6691/index.html` ,默认用户名密码:admin / 123456
+
+## 镜像构建
+
+如果想要自定义镜像,可以通过以下命令快速构建 Hippo4J Server:
+
+方式一:
+
+```shell
+# 进入到 hippo4j-server/hippo4j-bootstrap 工程路径下
+mvn clean package -Dskip.spotless.apply=true
+# 默认打包是打包的 tag 是 latest
+docker build -t hippo4j/hippo4j-server ../hippo4j-bootstrap
+```
+
+方式二:
+
+通过 `maven docker plugin`
+
+```shell
+# 进入到 hippo4j-server 工程路径下
+mvn clean package -DskipTests -Dskip.spotless.apply=true docker:build
+```
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/_category_.json b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/_category_.json
new file mode 100644
index 00000000..a74d7432
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/_category_.json
@@ -0,0 +1,7 @@
+{
+ "label": "其它",
+ "position": 6,
+ "link": {
+ "type": "generated-index"
+ }
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/group.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/group.md
new file mode 100644
index 00000000..e75e96be
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/group.md
@@ -0,0 +1,9 @@
+---
+sidebar_position: 1
+---
+
+# 加群沟通
+
+扫码添加微信,备注:`hippo4j`,邀您加入群聊。
+
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/issue.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/issue.md
new file mode 100644
index 00000000..11f48a12
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/issue.md
@@ -0,0 +1,90 @@
+---
+sidebar_position: 2
+---
+
+# 常见问题
+
+- 租户和项目在 Hippo4J 中是什么意思
+- 控制台线程池管理和线程池实例的区别
+- 示例项目为什么会有跨域请求
+- 更新代码后运行时服务端SQL报错
+- 生产环境如何不启用动态线程池
+- Server 端宕机会影响 Client 运行么
+- Hippo4J 的发布方式是怎样的?如何选择正确的版本
+- 群机器人接受不到通知报警
+- 设置线程池参数优先级问题
+- 线程池实例中修改队列容量参数问题
+- 控制台 SocketTimeoutException: connect timed out
+
+## 租户和项目在 Hippo4J 中是什么意思
+
+Hippo4J 按照租户、项目、线程池的维度划分。
+
+举个例子,小编在一家公司的公共组件团队,团队中负责消息、短链接网关等项目。公共组件是租户,消息或短链接就是项目。
+
+## 控制台线程池管理和线程池实例的区别
+
+在线程池管理中修改线程池参数,客户端并不能实时感知到并变更参数,需要重启客户端。而线程池实例中去对具体的实例修改参数时,客户端无需重启,可以实时感知到参数变化。如果二者针对同一线程
+池的参数配置不同,则在重启客户端时,客户端会去拉去线程池管理中的参数配置。
+
+二者对应的定位:线程池管理中的配置是常态化配置。而线程池实例里的配置变更像是一种临时修改,比如突发的流量激增等场景,并不具备普适性。
+
+## 示例项目为什么会有跨域请求
+
+~~正常大家在部署时,服务端项目和客户端都在同一网络下,进行内网通信,是没有问题的。~~
+
+~~因为示例项目中,服务端部署在外网,而客户端注册到服务端 IP 是内网的,所以不通。~~
+
+~~涉及功能:线程池实例-查看、编辑,容器线程池。~~
+
+1.2.0 版本后,服务端访问客户端已变成,浏览器访问服务端,服务端转发客户端的形式完成调用,跨域问题已解决。
+
+## 更新代码后运行时服务端SQL报错
+
+如果更新代码运行功能出错,大概率是因为项目新增或修改了表结构。如版本升级迭代涉及数据库表变更,会额外提供 SQL 变更文件。
+
+如若第一次使用,初始化 SQL 脚本地址:[hippo4j_manager.sql](https://github.com/longtai-cn/hippo4j/blob/develop/hippo4j-server/conf/hippo4j_manager.sql)。
+
+> 友情提示:每次执行数据库表或数据变更时,一定要保持提前备份的好习惯。
+
+## 生产环境如何不启用动态线程池
+
+测试环境已经引入 Hippo4J,暂时不打算上线生产环境。
+
+生产环境指定配置 `spring.dynamic.thread-pool.enable=false`,测试环境和生产环境配置就会隔离。
+
+## Server 端宕机会影响 Client 运行么
+
+不会。Client 端包含对 Server 端的健康检查机制,Server 端不可用时会停止交互,检查到可用时重新建立连接交互。
+
+## Hippo4J 的发布方式是怎样的?如何选择正确的版本
+
+Hippo4J 发布时可能会涉及到两端发布,分别是 Server 和 Starter。如无特殊说明,**每一次的版本升级将兼容上一版本代码**。
+
+- 如涉及 Server 发布,会在 [发布列表页面](https://github.com/longtai-cn/hippo4j/releases) 创建最新的发行版本;
+- 如涉及 Starter 发布,将直接推送 Starter Jar 至中央仓库,Server 包版本不变。
+
+## 群机器人接受不到通知报警
+
+如果是钉钉机器人,需在机器人配置自定义关键字,才可发送成功。如下所示:
+
+
+
+如果使用 hippo4j-server,请检查在 hippo4j-server 添加的报警通知记录,是否在客户端项目启动前,因为客户端只有在启动时会去 hippo4j-server 拉取报警通知记录。
+
+重启客户端项目,会重新拉取最新报警推送配置,问题解决。
+
+## 设置线程池参数优先级问题
+
+- 当使用 `@DynamicThreadPool` 进行修饰的方法中和在管理界面设置中同时存在的话,则管理界面设置的优先级最高;
+- 如果连接 server 端失败的话,使用 `@DynamicThreadPool` 进行修饰设置的优先级最高。
+
+## 线程池实例中修改队列容量参数问题
+
+在线程池管理中添加时,只有当选择队列类型为 `ResizableCapacityLinkedBlockingQueue` 时,后续再进行修改容量大小时才会实时的刷新修改成功。
+
+## 控制台 SocketTimeoutException: connect timed out
+
+控制台中触发的某些操作涉及到 hippo4j-server 调用客户端项目。如果 hippo4j-server 部署在测试环境,而客户端项目为本地启动,则会触发该问题。
+
+为什么编辑线程池参数不报错?因为线程池的动态变更是客户端主动发起连接,和服务端保持了一个长轮询,所以不存在服务端主动调用客户端行为。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/official-ccounts.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/official-ccounts.md
new file mode 100644
index 00000000..61a1a5c6
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/official-ccounts.md
@@ -0,0 +1,23 @@
+---
+sidebar_position: 5
+---
+
+# 推荐公众号
+
+## JavaGuide
+
+专注Java后端学习和大厂面试的公众号!
+
+
+
+## HelloGitHub
+
+HelloGitHub,专注于开源社区技术和知识内容分享。
+
+
+
+## macrozheng
+
+专注Java技术分享,解析优质开源项目。涵盖SpringBoot、SpringCloud、Docker、K8S等实用技术,作者Github开源项目mall(50K+Star)。
+
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/operation.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/operation.md
new file mode 100644
index 00000000..ba9ed7f0
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/operation.md
@@ -0,0 +1,23 @@
+---
+sidebar_position: 6
+---
+
+# 公众号合作
+
+## 推荐须知
+
+hippo4j 作为一款新兴动态线程池框架,开源出来的时间比较晚,目前迫切需要不同的途径进行推广。
+
+如果您是公众号运营者或者开源爱好者,欢迎将 hippo4j 推荐给您的粉丝。
+
+1. 您无需为 hippo4j 专门撰写文案,只需要直接导入 [推荐文章](https://mp.weixin.qq.com/s/JTTwcBEiK_MnFcPTZl3zGA) 即可。
+2. 在文章底部或内容中留下项目官网或者 GitHub 仓库链接。
+3. 文章需至少 1000+ 的阅读量。
+
+作为推荐回报,hippo4j 可以为您:
+
+1. 在框架官方文档 [推荐公众号](/docs/user_docs/other/official-ccounts) 页面处留下您的公众号二维码。
+2. 在框架官方交流群里@全体成员推广您的公众号一次,附带介绍语。
+3. 您的公众号所有新推文章都可以将链接发送到 hippo4j 交流群中,增加阅读量。
+
+如果您还有除公众号以外的其它途径可以与 hippo4j 相互推荐,欢迎 [加群沟通](/docs/user_docs/other/group)。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/question.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/question.md
new file mode 100644
index 00000000..49fd4d77
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/question.md
@@ -0,0 +1,246 @@
+---
+sidebar_position: 3
+---
+
+# 问题提问
+
+文档引用自:[提问的智慧](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way)
+
+## 在提问之前
+
+在你准备要通过电子邮件、新闻群组或者聊天室提出技术问题前,请先做到以下事情:
+
+1. 尝试在你准备提问的论坛的旧文章中搜索答案。
+2. 尝试上网搜索以找到答案。
+3. 尝试阅读手册以找到答案。
+4. 尝试阅读常见问题文件(FAQ)以找到答案。
+5. 尝试自己检查或试验以找到答案。
+6. 向你身边的强者朋友打听以找到答案。
+7. 如果你是程序开发者,请尝试阅读源代码以找到答案。
+
+当你提出问题的时候,请先表明你已经做了上述的努力;这将有助于树立你并不是一个不劳而获且浪费别人的时间的提问者。如果你能一并表达在做了上述努力的过程中所**学到**的东西会更好,因为我们更乐于回答那些表现出能从答案中学习的人的问题。
+
+## 当你提问时
+
+### 慎选提问的论坛
+小心选择你要提问的场合。如果你做了下述的事情,你很可能被忽略掉或者被看作失败者:
+
+* 在与主题不合的论坛上贴出你的问题。
+* 在探讨进阶技术问题的论坛张贴非常初级的问题;反之亦然。
+* 在太多的不同新闻群组上重复转贴同样的问题(cross-post)。
+* 向既非熟人也没有义务解决你问题的人发送私人电邮。
+
+因此,第一步是找到对的论坛。再说一次,Google 和其它搜索引擎还是你的朋友,用它们来找到与你遭遇到困难的软硬件问题最相关的网站。通常那儿都有常见问题(FAQ)、邮件列表及相关说明文件的链接。如果你的努力(包括**阅读** FAQ)都没有结果,网站上也许还有报告 Bug(Bug-reporting)的流程或链接,如果是这样,链过去看看。
+
+### 使用有意义且描述明确的标题
+
+在邮件列表、新闻群组或论坛中,大约 50 字以内的标题是抓住资深专家注意力的好机会。别用喋喋不休的帮帮忙、跪求、急(更别说救命啊!!!!这样让人反感的话,用这种标题会被条件反射式地忽略)来浪费这个机会。不要妄想用你的痛苦程度来打动我们,而应该是在这点空间中使用极简单扼要的描述方式来提出问题。
+
+一个好标题范例是`目标 —— 差异`式的描述,许多技术支持组织就是这样做的。在`目标`部分指出是哪一个或哪一组东西有问题,在`差异`部分则描述与期望的行为不一致的地方。
+
+> 蠢问题:救命啊!我的笔记本电脑不能正常显示了!
+
+> 聪明问题:X.org 6.8.1 的鼠标指针会变形,某牌显卡 MV1005 芯片组。
+
+> 更聪明问题:X.org 6.8.1 的鼠标指针,在某牌显卡 MV1005 芯片组环境下 - 会变形。
+
+### 使用清晰、正确、精准且合乎语法的语句
+
+我们从经验中发现,粗心的提问者通常也会粗心地写程序与思考(我敢打包票)。回答粗心大意者的问题很不值得,我们宁愿把时间耗在别处。
+
+正确的拼写、标点符号和大小写是很重要的。一般来说,如果你觉得这样做很麻烦,不想在乎这些,那我们也觉得麻烦,不想在乎你的提问。花点额外的精力斟酌一下字句,用不着太僵硬与正式 —— 事实上,黑客文化很看重能准确地使用非正式、俚语和幽默的语句。但它**必须很**准确,而且有迹象表明你是在思考和关注问题。
+
+### 精确地描述问题并言之有物
+
+* 仔细、清楚地描述你的问题或 Bug 的症状。
+* 描述问题发生的环境(机器配置、操作系统、应用程序、以及相关的信息),提供经销商的发行版和版本号(如:`Fedora Core 4`、`Slackware 9.1`等)。
+* 描述在提问前你是怎样去研究和理解这个问题的。
+* 描述在提问前为确定问题而采取的诊断步骤。
+* 描述最近做过什么可能相关的硬件或软件变更。
+* 尽可能地提供一个可以`重现这个问题的可控环境`的方法。
+
+尽量去揣测一个黑客会怎样反问你,在你提问之前预先将黑客们可能提出的问题回答一遍。
+
+以上几点中,当你报告的是你认为可能在代码中的问题时,给黑客一个可以重现你的问题的环境尤其重要。当你这么做时,你得到有效的回答的机会和速度都会大大的提升。
+
+[Simon Tatham](http://www.chiark.greenend.org.uk/~sgtatham/) 写过一篇名为《[如何有效的报告 Bug](http://www.chiark.greenend.org.uk/~sgtatham/bugs-cn.html)》的出色文章。强力推荐你也读一读。
+
+### 话不在多而在精
+
+你需要提供精确有内容的信息。这并不是要求你简单的把成堆的出错代码或者资料完全转录到你的提问中。如果你有庞大而复杂的测试样例能重现程序挂掉的情境,尽量将它剪裁得越小越好。
+
+这样做的用处至少有三点。
+第一,表现出你为简化问题付出了努力,这可以使你得到回答的机会增加;
+第二,简化问题使你更有可能得到**有用**的答案;
+第三,在精炼你的 bug 报告的过程中,你很可能就自己找到了解决方法或权宜之计。
+
+### 别动辄声称找到 Bug
+
+当你在使用软件中遇到问题,除非你非常、**非常**的有根据,不要动辄声称找到了 Bug。提示:除非你能提供解决问题的源代码补丁,或者提供回归测试来表明前一版本中行为不正确,否则你都多半不够完全确信。这同样适用在网页和文件,如果你(声称)发现了文件的`Bug`,你应该能提供相应位置的修正或替代文件。
+
+请记得,还有其他许多用户没遇到你发现的问题,否则你在阅读文件或搜索网页时就应该发现了(你在抱怨前[已经做了这些,是吧](#在提问之前)?)。这也意味着很有可能是你弄错了而不是软件本身有问题。
+
+编写软件的人总是非常辛苦地使它尽可能完美。如果你声称找到了 Bug,也就是在质疑他们的能力,即使你是对的,也有可能会冒犯到其中某部分人。当你在标题中嚷嚷着有`Bug`时,这尤其严重。
+
+提问时,即使你私下非常确信已经发现一个真正的 Bug,最好写得像是**你**做错了什么。如果真的有 Bug,你会在回复中看到这点。这样做的话,如果真有 Bug,维护者就会向你道歉,这总比你惹恼别人然后欠别人一个道歉要好一点。
+
+### 低声下气不能代替你的功课
+
+有些人明白他们不该粗鲁或傲慢的提问并要求得到答复,但他们选择另一个极端 —— 低声下气:`我知道我只是个可悲的新手,一个撸瑟,但...`。这既使人困扰,也没有用,尤其是伴随着与实际问题含糊不清的描述时更令人反感。
+
+别用原始灵长类动物的把戏来浪费你我的时间。取而代之的是,尽可能清楚地描述背景条件和你的问题情况。这比低声下气更好地定位了你的位置。
+
+有时网页论坛会设有专为新手提问的版面,如果你真的认为遇到了初学者的问题,到那去就是了,但一样别那么低声下气。
+
+### 描述问题症状而非你的猜测
+
+告诉黑客们你认为问题是怎样造成的并没什么帮助。(如果你的推断如此有效,还用向别人求助吗?),因此要确信你原原本本告诉了他们问题的症状,而不是你的解释和理论;让黑客们来推测和诊断。如果你认为陈述自己的猜测很重要,清楚地说明这只是你的猜测,并描述为什么它们不起作用。
+
+**蠢问题**
+
+> 我在编译内核时接连遇到 SIG11 错误,
+> 我怀疑某条飞线搭在主板的走线上了,这种情况应该怎样检查最好?
+
+**聪明问题**
+
+> 我的组装电脑是 FIC-PA2007 主机板搭载 AMD K6/233 CPU(威盛 Apollo VP2 芯片组),
+> 256MB Corsair PC133 SDRAM 内存,在编译内核时,从开机 20 分钟以后就频频产生 SIG11 错误,
+> 但是在头 20 分钟内从没发生过相同的问题。重新启动也没有用,但是关机一晚上就又能工作 20 分钟。
+> 所有内存都换过了,没有效果。相关部分的标准编译记录如下…
+
+由于以上这点似乎让许多人觉得难以配合,这里有句话可以提醒你:`所有的诊断专家都来自密苏里州。` 美国国务院的官方座右铭则是:`让我看看`(出自国会议员 Willard D. Vandiver 在 1899 年时的讲话:`我来自一个出产玉米,棉花,牛蒡和民主党人的国家,滔滔雄辩既不能说服我,也不会让我满意。我来自密苏里州,你必须让我看看。`) 针对诊断者而言,这并不是一种怀疑,而只是一种真实而有用的需求,以便让他们看到的是与你看到的原始证据尽可能一致的东西,而不是你的猜测与归纳的结论。所以,大方的展示给我们看吧!
+
+### 按发生时间先后列出问题症状
+
+问题发生前的一系列操作,往往就是对找出问题最有帮助的线索。因此,你的说明里应该包含你的操作步骤,以及机器和软件的反应,直到问题发生。在命令行处理的情况下,提供一段操作记录(例如运行脚本工具所生成的),并引用相关的若干行(如 20 行)记录会非常有帮助。
+
+如果挂掉的程序有诊断选项(如 -v 的详述开关),试着选择这些能在记录中增加调试信息的选项。记住,`多`不等于`好`。试着选取适当的调试级别以便提供有用的信息而不是让读者淹没在垃圾中。
+
+如果你的说明很长(如超过四个段落),在开头简述问题,接下来再按时间顺序详述会有所帮助。这样黑客们在读你的记录时就知道该注意哪些内容了。
+
+### 描述目标而不是过程
+
+如果你想弄清楚如何做某事(而不是报告一个 Bug),在开头就描述你的目标,然后才陈述重现你所卡住的特定步骤。
+
+经常寻求技术帮助的人在心中有个更高层次的目标,而他们在自以为能达到目标的特定道路上被卡住了,然后跑来问该怎么走,但没有意识到这条路本身就有问题。结果要费很大的劲才能搞定。
+
+**蠢问题**
+
+> 我怎样才能从某绘图程序的颜色选择器中取得十六进制的 RGB 值?
+
+**聪明问题**
+
+> 我正试着用替换一幅图片的色码(color table)成自己选定的色码,我现在知道的唯一方法是编辑每个色码区块(table slot),
+> 但却无法从某绘图程序的颜色选择器取得十六进制的 RGB 值。
+
+第二种提问法比较聪明,你可能得到像是```建议采用另一个更合适的工具```的回复。
+
+### 清楚明确的表达你的问题以及需求
+
+漫无边际的提问是近乎无休无止的时间黑洞。最有可能给你有用答案的人通常也正是最忙的人(他们忙是因为要亲自完成大部分工作)。这样的人对无节制的时间黑洞相当厌恶,所以他们也倾向于厌恶那些漫无边际的提问。
+
+如果你明确表述需要回答者做什么(如提供指点、发送一段代码、检查你的补丁、或是其他等等),就最有可能得到有用的答案。因为这会定出一个时间和精力的上限,便于回答者能集中精力来帮你。这么做很棒。
+
+要理解专家们所处的世界,请把专业技能想像为充裕的资源,而回复的时间则是稀缺的资源。你要求他们奉献的时间越少,你越有可能从真正专业而且很忙的专家那里得到解答。
+
+所以,界定一下你的问题,使专家花在辨识你的问题和回答所需要付出的时间减到最少,这技巧对你有用答案相当有帮助 —— 但这技巧通常和简化问题有所区别。因此,问`我想更好地理解 X,可否指点一下哪有好一点说明?`通常比问`你能解释一下 X 吗?`更好。如果你的代码不能运作,通常请别人看看哪里有问题,比要求别人替你改正要明智得多。
+
+### 礼多人不怪,而且有时还很有帮助
+
+彬彬有礼,多用`请`和`谢谢您的关注`,或`谢谢你的关照`。让大家都知道你对他们花时间免费提供帮助心存感激。
+
+坦白说,这一点并没有比使用清晰、正确、精准且合乎语法和避免使用专用格式重要(也不能取而代之)。黑客们一般宁可读有点唐突但技术上鲜明的 Bug 报告,而不是那种有礼但含糊的报告。(如果这点让你不解,记住我们是按问题能教给我们什么来评价问题的价值的)
+
+然而,如果你有一串的问题待解决,客气一点肯定会增加你得到有用回应的机会。
+
+(我们注意到,自从本指南发布后,从资深黑客那里得到的唯一严重缺陷反馈,就是对预先道谢这一条。一些黑客觉得`先谢了`意味着事后就不用再感谢任何人的暗示。我们的建议是要么先说`先谢了`,**然后**事后再对回复者表示感谢,或者换种方式表达感激,譬如用`谢谢你的关注`或`谢谢你的关照`。)
+
+## 不该问的问题
+
+以下是几个经典蠢问题,以及黑客没回答时心中所想的:
+
+问题:[我能在哪找到 X 程序或 X 资源?](#q1)
+
+问题:[我怎样用 X 做 Y?](#q2)
+
+问题:[我的程序/设定/SQL 语句没有用](#q3)
+
+问题:[我的 Windows 电脑有问题,你能帮我吗?](#q4)
+
+问题:[我的程序不会动了,我认为系统工具 X 有问题](#q5)
+
+问题:[我在安装 Linux(或者 X )时有问题,你能帮我吗?](#q6)
+
+问题:[我怎么才能破解 root 帐号/窃取 OP 特权/读别人的邮件呢?](#q7)
+
+---
+
+> 问题:我能在哪找到 X 程序或 X 资源?
+
+回答:就在我找到它的地方啊,白痴 —— 搜索引擎的那一头。天哪!难道还有人不会用 [Google](https://www.google.com) 吗?
+
+> 问题:我怎样用 X 做 Y?
+
+回答:如果你想解决的是 Y ,提问时别给出可能并不恰当的方法。这种问题说明提问者不但对 X 完全无知,也对 Y 要解决的问题糊涂,还被特定形势禁锢了思维。最好忽略这种人,等他们把问题搞清楚了再说。
+
+> 问题:我的{程序/设定/SQL 语句}没有用
+
+回答:这不算是问题吧,我对要我问你二十个问题才找得出你真正问题的问题没兴趣 —— 我有更有意思的事要做呢。在看到这类问题的时候,我的反应通常不外如下三种
+
+* 你还有什么要补充的吗?
+* 真糟糕,希望你能搞定。
+* 这关我屁事?
+
+> 问题:我的 Windows 电脑有问题,你能帮我吗?
+
+回答:能啊,扔掉微软的垃圾,换个像 Linux 或 BSD 的开源操作系统吧。
+
+注意:如果程序有官方版 Windows 或者与 Windows 有互动(如 Samba),你**可以**问与 Windows 相关的问题,只是别对问题是由 Windows 操作系统而不是程序本身造成的回复感到惊讶, 因为 Windows 一般来说实在太烂,这种说法通常都是对的。
+
+> 问题:我的程序不会动了,我认为系统工具 X 有问题
+
+回答:你完全有可能是第一个注意到被成千上万用户反复使用的系统调用与函数库文件有明显缺陷的人,更有可能的是你完全没有根据。不同凡响的说法需要不同凡响的证据,当你这样声称时,你必须有清楚而详尽的缺陷说明文件作后盾。
+
+> 问题:我在安装 Linux(或者 X )时有问题,你能帮我吗?
+
+回答:不能,我只有亲自在你的电脑上动手才能找到毛病。还是去找你当地的 Linux 使用群组者寻求实际的指导吧(你能在[这儿](http://www.linux.org/groups/index.html)找到用户群组的清单)。
+
+注意:如果安装问题与某 Linux 的发行版有关,在它的邮件列表、论坛或本地用户群组中提问也许是恰当的。此时,应描述问题的准确细节。在此之前,先用 `Linux` 和**所有**被怀疑的硬件作关键词仔细搜索。
+
+> 问题:我怎么才能破解 root 帐号/窃取 OP 特权/读别人的邮件呢?
+
+回答:想要这样做,说明了你是个卑鄙小人;想找个黑客帮你,说明你是个白痴!
+
+## 好问题与蠢问题
+
+最后,我将透过举一些例子,来说明怎样聪明的提问;同一个问题的两种问法被放在一起,一种是愚蠢的,另一种才是明智的。
+
+**蠢问题**:
+
+> 我从 foo 项目找来的源码没法编译。它怎么这么烂?
+
+他觉得都是别人的错,这个傲慢自大的提问者。
+
+**聪明问题**:
+
+> foo 项目代码在 Nulix 6.2 版下无法编译通过。我读过了 FAQ,但里面没有提到跟 Nulix 有关的问题。这是我编译过程的记录,我有什么做的不对的地方吗?
+
+提问者已经指明了环境,也读过了 FAQ,还列出了错误,并且他没有把问题的责任推到别人头上,他的问题值得被关注。
+
+**蠢问题**:
+
+> 我的主机板有问题了,谁来帮我?
+
+某黑客对这类问题的回答通常是:`好的,还要帮你拍拍背和换尿布吗?`,然后按下删除键。
+
+**聪明问题**:
+
+> 我在 S2464 主机板上试过了 X 、 Y 和 Z ,但没什么作用,我又试了 A 、 B 和 C 。请注意当我尝试 C 时的奇怪现象。显然 florbish 正在 grommicking,但结果出人意料。通常在 Athlon MP 主机板上引起 grommicking 的原因是什么?有谁知道接下来我该做些什么测试才能找出问题?
+
+## 如果得不到回答
+
+如果仍得不到回答,请不要以为我们觉得无法帮助你。有时只是看到你问题的人不知道答案罢了。没有回应不代表你被忽视,虽然不可否认这种差别很难区分。
+
+总的来说,简单的重复张贴问题是个很糟的点子。这将被视为无意义的喧闹。有点耐心,知道你问题答案的人可能生活在不同的时区,可能正在睡觉,也有可能你的问题一开始就没有组织好。
+
+你可以通过其他渠道获得帮助,这些渠道通常更适合初学者的需要。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/update-log.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/update-log.md
new file mode 100644
index 00000000..fc7b2fda
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/other/update-log.md
@@ -0,0 +1,299 @@
+---
+sidebar_position: 4
+---
+
+# 更新日志
+
+## 1.4.2 (Oct 18, 2022)
+
+这是一个功能增强版本,修复了少量 BUG。建议按照当前版本升级。具体信息可查看 Release 标签地址:[1.4.2](https://github.com/opengoofy/hippo4j/milestone/12?closed=1)
+
+**Feature**
+
+- 强制指定客户端注册的 ip + port
+- 支持 spring-cloud-tencent Polaris 线程池动态更新 @weihubeats
+- 服务启动时加载 MySQL、H2 数据库初始化语句
+- Adapter 初始化覆盖核心参数 @pizihao
+- Server 端新增是否开启认证模式 @baymax55
+
+**Refactor**
+
+- 替换底层网络工具类 OkHttp @yanrongzhen
+- 全局移除 commons-lang3 工具包依赖 @yanrongzhen
+- 去除三方工具类依赖 @pizihao
+- 全局移除 Guava 工具包依赖 @road2master
+- DockerFile 基于 H2 数据库重新构建 @BigXin0109
+
+**Bug**
+
+- Dubbo 2.7.15 无法获取线程池引用 @iwangjie
+- 动态线程池报警参数颠倒 @jinlingmei
+
+**Optimize**
+
+- 线程池实例运行数据采集,如果线程池id不存在,且长度超长,会报异常 @Gdk666
+- 项目中动态线程池数量为空时,存在 CPU 空转情况
+- 客户端注册服务端失败,输出服务端返回信息 @wulangcode
+- 调整数据库项目 id 和线程池 id 字段长度
+- 增加代码检查工具 maven-checkstyle-plugin
+- 调整控制台监控图表颜色展示
+
+## 1.4.1 (Sep 12, 2022)
+
+这是一个功能增强版本,修复了若干 BUG。建议按照当前版本升级。具体信息可查看 Release 标签地址:[1.4.1](https://github.com/opengoofy/hippo4j/milestone/11?closed=1)
+
+**Feature**
+
+- 支持 H2 数据库 @weihubeats
+- 动态线程池配置变更时,支持单个、多个或全部节点变 @pizihao
+- 增加线程池活跃度和容量报警可选择关闭
+- @DynamicThreadPool 线程池不存在则创建 @shanjianq
+- 支持 ETCD 配置中心动态调整参数 @weihubeats
+- 创建动态线程池支持 spring 线程池 @BigXin0109
+- 线程池实例变更增加执行超时时间
+- 线程池相关查询页面增加阻塞队列属性
+- 定义动态线程池时,抽象默认配置
+- 提供 ExecutorContext 封装上下文细节 @road2master
+- Docker 制作服务端镜像,帮助开发者快速启动 @BigXin0109
+- RabbitMQ 适配器增加多个 MQ 数据源 @weihubeats
+
+**Bug**
+
+- 动态线程池设置关闭时启动报错 @dousp
+- ExecutorTtlWrapper 类型的 Executor 不生效 @BigXin0109
+- Undertow 获取 WebServer 类型参数异常 @shining-stars-lk
+- 修复线程池核心、最大线程数校验限制
+- ByteConvertUtil#getPrintSize 单位转换错误 @onesimplecoder
+- 创建线程池单选框选择错误
+- ReflectUtil#getFieldsDirectly missing fields @BigXin0109
+- 本地代码中设置的 capacity 无效 @BigXin0109
+- 服务端线程池超时时间存在拆箱空指针异常 @oreoft
+- 未读取服务端返回执行超时时间属性
+- ResizableCapacityLinkedBlockingQueue#put 当前元素数量大于 capacity 未阻塞
+
+**Optimize**
+
+- 长轮询任务判断逻辑优化 @shining-stars-lk
+- 线程池存在实例不允许删除线程池 @shanjianq
+- 优化租户、项目列表展示排版
+- 通知报警模块项目和线程池下拉查询排序修改
+- 动态线程池拒绝策略触发,以异步的方式报警
+- 优化框架中线程池工厂产生的线程名称 @road2master
+
+## 1.4.0 (Aug 16, 2022)
+
+`hippo4j server` 兼容历史低版本,`hippo4j config` 中部分属性名进行了调整,请参考 [hippo4j config 快速开始](https://hippo4j.cn/docs/user_docs/getting-started/hippo4j-core-start)。
+
+注意事项:
+1. 如果是对已运行 hippo4j server 升级,执行 `/conf/sql-upgrade` 目录下对应的升级脚本。
+2. 需客户端在 1.4.0 及以上版本才可在 hippo4j server 设置线程执行超时时间属性。
+
+**Feature**
+
+- 添加 Alibaba Dubbo 线程池监控及动态变更
+- hippo4j server 支持任务执行超时时间动态修改
+- 阿里 TTL 框架线程池适配
+- 添加动态线程池自动注册功能
+- 订阅回调线程池参数变更
+- 动态线程池监控增加 SPI 自定义功能
+- hippo4j server 支持多种线程池监控方式,例如 Prometheus
+- 通知相关参数添加动态变更功能
+
+**Bug**
+
+- 线程池变更:executeTimeOut 变更极端情况下会出现异常
+- 用户登录时候,如果输入了不存在的用户名,后台报空指针异常
+- 修复了对 spring-boot 服务中 tomcat 线程池的兼容问题
+- 排除 Tomcat Jar 使用 Undertow 启动报错
+
+**Optimize**
+
+- hippo4j-core-spring-boot-starter 模块修改名称为 hippo4j-config-spring-boot-starter
+- 拆分容器线程池子页面:Tomcat、Undertow、Jetty
+- 服务端访问客户端时对 URL 转码
+- MyBatisPlus 修改全局填充方法优化
+- 控制台线程池列表下拉框默认正序
+- 控制台线程池实例菜单,对于非可修改容量队列外,不允许修改队列容量
+- 动态线程池控制台功能变更
+- 租户和项目列表分页查询按照创建时间倒序展示
+- 线程池监控页面图表 UI 优化
+- 设置 maven-gpg-plugin 插件默认不执行
+- 前端控制台相关搜索条件添加必填提示
+- hippo4j 消息通知 & 报警抽象优化
+- 配置中心未配置线程池启动报错
+- 控制台线程池报警 UI 以及功能优化
+- Web、框架线程池编辑弹框 UI 优化
+- 线程池添加、编辑页面 UI 优化
+- 线程池运行详情页前端 UI 优化
+
+**Refactor**
+
+- 删除自定义日志组件
+- 线程池监控功能重构
+- hippo4j core 配置中心生效判断重构
+- 配置变更通知 & 报警通知重构
+- Web 容器线程池适配迁移 hippo4j-adapter
+
+## 1.3.1 (July 17, 2022)
+
+注:这是一个兼容历史版本的小范围升级。
+
+**Feature**
+
+- 控制台新增线程池功能设置为 Admin 权限
+- 添加 Hystrix 线程池监控及动态变更
+- 添加 Netty 上传动态线程池监控数据方式
+- 添加 GitHub Actions CI 流程
+- 添加 Spring Kafka 示例项目
+- Tomcat 版本号 >= 9.0.55 线程池适配
+
+**Refactor**
+
+- 更多线程池拆分子目录页面
+
+**Optimize**
+
+- hippo4j core 添加 banner 打印
+- 优化可变更容量阻塞队列名称
+
+**BUG**
+
+- Apollo 配置修改延迟了一个版本
+- Spring Boot 环境下使用 hippo4j-core 接入,配置中心使用 nacos;启动时提示 ConfigService not found
+
+查看 1.3.1 版本发布:https://github.com/mabaiwan/hippo4j/milestone/9
+
+## 1.3.0 (June 06, 2022)
+
+1.3.0 发布 **适配三方框架的基础框架**。
+
+目前已完成 **Dubbo、RabbitMQ、RocketMQ、RocketMQSpringCloudStream** 的线程池适配,后续还会接入 **Kafka、Hystrix** 等框架或中间件的线程池适配。
+
+注:这是一个兼容历史版本的重大升级。
+
+**Feature**
+
+- 添加 RabbitMQ 线程池监控及动态变更
+- 添加 RocketMQ 线程池监控及动态变更
+- 添加 Dubbo 线程池监控及动态变更
+- 添加 SpringCloud Stream RocketMQ 消费线程池监控及动态变更
+
+**Refactor**
+
+- 重构容器线程池查询及修改功能
+- 优化配置中心触发监听后,所执行的数据变更逻辑
+
+**Optimize**
+
+- 前端控制台删除无用组件
+- 服务端页面字段未显示中文
+- 控制台 UI 优化
+- 修改线程池实例后实时刷新列表参数
+- 容器线程池编辑仅限 Admin 权限
+- SpringBoot Starter 变更包路径
+
+**BUG**
+
+- 修复 SpringBoot Nacos 动态刷新不生效
+- 报警配置 alarm=false 不配置通知报警平台和接收人报错
+
+## 1.2.1 (May 07, 2022)
+
+**BugFix**
+
+- apollo 动态配置不生效
+- 修复 hippo4j-core 后置处理器创建线程池问题
+- 重构 hippo4j-core spring 后置处理器逻辑
+- 优化ThreadPoolNotifyAlarmHandler下的空指针异常
+- 修复线程池核心、最大线程数变更问题
+- startup.cmd 未正常读取 conf 配置文件
+
+**Optimize**
+
+- 配置文件中字段歧义
+- 修改代码中历史网址
+- InstanceInfo 的 groupKey 参数重复设置
+- ConfigFileTypeEnum 枚举字段添加注释
+- 线程资源通过线程池创建,不允许自行显示创建线程
+- Guava 版本升级至 30.0-jre 及以上版本
+- SystemClock 替换 System.currentTimeMillis()
+- 添加代码格式化插件 Spotless
+- 修改线程池文案
+
+## 1.2.0 (Mar 13, 2022)
+
+**Feature**
+
+- hippo4j-core线程池资源对接 Prometheus 监控
+- hippo4j-core 支持 Zookeeper
+- hippo4j-core 支持 Apollo
+
+**Optimize**
+
+- 适配非 Web SpringBoot 项目使用 Hippo4J
+- 优化报警通知
+- 修复在 JDK 小版本中的兼容性问题
+
+**BugFix**
+
+- server 端查看容器线程池,参数为 null
+- 重构线程池查看及容器线程池查看等交互
+- 修复引入 hippo4j-spring-boot-starter 后,运行单元测试报错
+- 修复可能出现的空指针异常
+
+## 1.1.0 (Mar 13, 2022)
+
+Hippo4J 线程池框架 1.1.0 RELEASE 版本,添加了 Hippo4J-Core(依赖配置中心的动态线程池).
+
+**Feature**
+
+- 删除 DynamicThreadPoolExecutor 内代码实现,仅通过线程池扩展点进行扩展
+- 通过动态代理实现线程池拒绝策略执行次数统计
+- 抽象通知报警消息模块
+- 抽象 hippo4j 核心组件,不依赖 server 端即可完成动态调参、监控、报警等功能
+- 前端删除线程池按钮添加 Admin 权限
+- 添加线程池任务运行超长报警
+- 容器线程池支持 Undertow
+- 容器线程池支持 Jetty
+- 重构服务端异常体系
+
+**Optimize**
+
+- 前端项目 Token 失效跳转登录页
+- 优化 Server 启动脚本日志输出
+- 优化前端按钮权限控制粒度
+- 优化线程池报警推送文案
+- 前端弹框样式优化
+- 适配低版本 SpringBoot Bind
+- 优化消息通知模块
+
+**BugFix**
+
+- Duplicate entry 'xxx' for key 'uk_configinfo_datagrouptenant'
+
+## 1.0.0 (Feb 01, 2022)
+
+**Feature**
+
+- 线程池运行堆栈查看
+- 扩展 Web 容器线程池动态调参、监控
+
+**Optimize**
+
+- 删除高版本 SpringBoot Api
+- ListableBeanFactory#findAnnotationOnBean SpringBoot 低版本适配
+- 优化客户端关闭时调用服务端钩子函数
+- 线程池实例参数弹框添加实例 ID 和线程池状态
+- 补充线程池替换 Hippo4J 文档
+- 1.5.x springboot 引入hippo4j-spring-boot-starter配置项,bean初始化失败
+- 优化线程池参数编辑合理性校验
+- BaseInstanceRegistry 读写锁重构
+
+**BugFix**
+
+- 本地项目线程池实例缓存无法精确清理
+- 线程池实例页面多实例不同 Active 展示错误
+- 创建动态线程池逻辑判断修复
+- 创建动态线程池增强参数未设置
+- 控制消息推送报警频率的方法有并发安全的问题
+- tomcat线程池上下文获取失败
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/user_guide/_category_.json b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/user_guide/_category_.json
new file mode 100644
index 00000000..6dc10c33
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/user_guide/_category_.json
@@ -0,0 +1,8 @@
+{
+ "label": "用户指南",
+ "position": 2,
+ "link": {
+ "type": "generated-index",
+ "description": "帮助想要了解 Hippo4J 的用户快速掌握核心开发理念。"
+ }
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/user_guide/frame.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/user_guide/frame.md
new file mode 100644
index 00000000..47f568fa
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/user_guide/frame.md
@@ -0,0 +1,60 @@
+---
+sidebar_position: 1
+---
+
+# 为什么写
+
+[美团线程池文章](https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html "美团线程池文章") 介绍中,因为业务对线程池参数没有合理配置,触发过几起生产事故,进而引发了一系列思考。最终决定封装线程池动态参数调整,扩展线程池监控以及消息报警等功能。
+
+在开源平台找了挺多动态线程池项目,从功能性以及健壮性而言,个人感觉不满足企业级应用。
+
+因为对动态线程池比较感兴趣,加上想写一个有意义的项目,所以决定自己来造一个轻量级的轮子。
+
+想给项目起一个简单易记的名字,类似于 Eureka、Nacos、Redis;后和朋友商量,决定命名:**Hippo4J**。
+
+
+
+## 它解决了什么问题
+
+线程池在业务系统应该都有使用到,帮助业务流程提升效率以及管理线程,多数场景应用于大量的异步任务处理。
+
+虽然线程池提供了我们许多便利,但也并非尽善尽美,比如下面这些问题就无法很好解决。
+
+- 线程池随便定义,线程资源过多,造成服务器高负载。
+
+- 线程池参数不易评估,随着业务的并发提升,业务面临出现故障的风险。
+
+- 线程池任务执行时间超过平均执行周期,开发人员无法感知。
+
+- 线程池任务堆积,触发拒绝策略,影响既有业务正常运行。
+
+- 当业务出现超时、熔断等问题时,因为没有监控,无法确定是不是线程池引起。
+
+- 原生线程池不支持运行时变量的传递,比如 MDC 上下文遇到线程池就 GG。
+
+- 无法执行优雅关闭,当项目关闭时,大量正在运行的线程池任务被丢弃。
+
+- 线程池运行中,任务执行停止,怀疑发生死锁或执行耗时操作,但是无从下手。
+
+Hippo4J 很好解决了这些问题,它将业务中所有线程池统一管理,增强原生线程池系列功能。
+
+## 它有什么特性
+
+应用系统中线程池并不容易管理。参考美团的设计,Hippo4J 按照租户、项目、线程池的维度划分。再加上系统权限,让不同的开发、管理人员负责自己系统的线程池操作。
+
+举个例子,小编在一家公司的公共组件团队,团队中负责消息、短链接网关等项目。公共组件是租户,消息或短链接就是项目。
+
+Hippo4J 除去动态修改线程池,还包含实时查看线程池运行时指标、负载报警、配置日志管理等。
+
+- `hippo4j-adapter`:适配对第三方框架中的线程池进行监控,如 Dubbo、RocketMQ、Hystrix 等;
+- `hippo4j-auth`:用户、角色、权限等;
+- `hippo4j-common`:多个模块公用代码实现;
+- `hippo4j-config`:提供线程池准实时参数更新功能;
+- `hippo4j-console`:对接前端控制台;
+- `hippo4j-core`:核心的依赖,包括配置、核心包装类等;
+- `hippo4j-discovery`:提供线程池项目实例注册、续约、下线等功能;
+- `hippo4j-example` :示例工程;
+- `hippo4j-message` :配置变更以及报警通知发送;
+- `hippo4j-monitor` :线程池运行时监控;
+- `hippo4j-server` :Server 端发布需要的模块聚合;
+- `hippo4j-spring-boot`:SpringBoot Starter。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/user_guide/framework.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/user_guide/framework.md
new file mode 100644
index 00000000..226ddf61
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/user_guide/framework.md
@@ -0,0 +1,51 @@
+---
+sidebar_position: 2
+---
+
+# 架构设计
+
+简单来说,Hippo4J 从部署的角度上分为两种角色:Server 端和 Client 端。
+
+Server 端是 Hippo4J 项目打包出的 Java 进程,功能包括用户权限、线程池监控以及执行持久化的动作。
+
+Client 端指的是我们 SpringBoot 应用,通过引入 Hippo4J Starter Jar 包负责与 Server 端进行交互。
+
+比如拉取 Server 端线程池数据、动态更新线程池配置以及采集上报线程池运行时数据等。
+
+## 基础组件
+
+### 配置中心(Config)
+
+配置中心位于 Server 端,它的主要作用是监控 Server 端线程池配置变更,实时通知到 Client 实例执行线程池变更流程。
+
+代码设计基于 Nacos 1.x 版本的 **长轮询以及异步 Servlet 机制** 实现。
+
+### 注册中心(Discovery)
+
+负责管理 Client 端(单机或集群)注册到 Server 端的实例,包括不限于**实例注册、续约、过期剔除** 等操作,代码基于 Eureka 源码实现。
+
+上面的配置中心很容易理解,动态线程池参数变更的根本。但是注册中心是用来做什么的?
+
+注册中心管理 Client 端注册的实例,通过这些实例可以 **实时获取线程池的运行时参数信息**。
+
+目前的设计是如此,不排除后续基于 Discovery 做更多的扩展。
+
+### 控制台(Console)
+
+对接前端项目,包括不限于以下模块管理:
+
+
+
+## 消息通知(Notify)
+
+Hippo4J 内置了很多需要通知的事件,比如:线程池参数变更通知、线程池活跃度报警、拒绝策略执行报警以及阻塞队列容量报警等。
+
+目前 Notify 已经接入了钉钉、企业微信和飞书,后续持续集成邮件、短信等通知渠道;并且,Notify 模块提供了消息事件的 SPI 方案,可以接受三方自定义的推送。
+
+## Hippo4j-Spring-Boot-Starter
+
+熟悉 SpringBoot 的小伙伴对 Starter 应该不会陌生。Hippo4J 提供以 Starter Jar 包的形式嵌套在应用内,负责与 Server 端完成交互。
+
+## 功能架构
+
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/user_guide/notify.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/user_guide/notify.md
new file mode 100644
index 00000000..d4ca2bfd
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/user_guide/notify.md
@@ -0,0 +1,75 @@
+---
+sidebar_position: 4
+---
+
+# 通知报警
+
+现阶段已集成钉钉、企业微信、飞书的消息推送,后续会持续接入邮箱、短信和自定义通知渠道。
+
+
+
+**通知平台**
+
+- DING:钉钉平台;
+
+- LARK:飞书平台;
+
+- WECHAT:企业微信。
+
+**通知类型**
+
+- CONFIG:线程池配置变更推送;
+
+- ALARM:线程池运行报警推送。
+
+**Token**
+
+获取 DING、LARK、WECHAT 机器人 Token。
+
+**报警间隔**
+
+- CONFIG 类型通知没有报警间隔;
+
+- ALARM 类型设置报警间隔后,某一节点下的同一线程池指定间隔只会发送一次报警通知。
+
+**接收者**
+
+```tex
+多个接收者使用英文逗号 , 分割 (注意不要有空格)
+DING:填写手机号
+WECHART:填写user_id会以@的消息发给用户,填写姓名则是普通的@,如:龙台
+LARK:填写ou_开头用户唯一标识会以@的消息发给用户,填写手机号则是普通的@
+```
+
+
+## 钉钉平台
+
+[钉钉创建群机器人](https://www.dingtalk.com/qidian/help-detail-20781541.html)
+
+| 配置变更 | 报警通知 |
+| :---: | :---: |
+|  |  |
+
+添加钉钉机器人后,需在机器人配置自定义关键字,才可发送成功。如下所示:
+
+
+
+:::tip
+如果使用 1.4.3 及以上版本,`警报` 替换为 `告警`。
+:::
+
+## 企业微信
+
+[企业微信创建群机器人](https://open.work.weixin.qq.com/help2/pc/14931?person_id=1&from=homesearch)
+
+| 配置变更 | 报警通知 |
+| :---: | :---: |
+|  |  |
+
+## 飞书平台
+
+[飞书创建群机器人](https://www.feishu.cn/hc/zh-CN/articles/360024984973)
+
+
+
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/user_guide/quick-start.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/user_guide/quick-start.md
new file mode 100644
index 00000000..cce9e577
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/user_docs/user_guide/quick-start.md
@@ -0,0 +1,40 @@
+---
+sidebar_position: 3
+---
+
+# 快速开始
+
+## 服务启动
+
+使用 Docker 运行服务端,默认使用内置 H2 数据库,数据持久化到 Docker 容器存储卷中。
+
+```shell
+docker run -d -p 6691:6691 --name hippo4j-server hippo4j/hippo4j-server
+```
+
+> 如果没有 Docker,可以使用源码编译的方式,启动 [Hippo4J-Server/Hippo4J-Bootstrap](https://github.com/longtai-cn/hippo4j/tree/develop/hippo4j-server/hippo4j-bootstrap) 模块下 ServerApplication 应用类。
+
+启动示例项目,[hippo4j-spring-boot-starter-example](https://github.com/opengoofy/hippo4j/tree/develop/hippo4j-example/hippo4j-spring-boot-starter-example) 模块下 Hippo4JServerExampleApplication 应用类。
+
+访问 Server 控制台,路径 `http://localhost:6691/index.html`,默认用户名密码:admin / 123456
+
+## 配置变更
+
+访问控制台动态线程池菜单下线程池实例,修改动态线程池相关参数。
+
+
+
+观察 Hippo4j-Example 控制台日志输出,日志输出包括不限于此信息即为成功。
+
+```tex
+2022-09-10 00:23:29.783 INFO 50322 --- [change.config_0] c.h.s.s.c.ServerThreadPoolDynamicRefresh : [message-consume] Dynamic thread pool change parameter.
+ corePoolSize: 2 => 4
+ maximumPoolSize: 6 => 12
+ capacity: 1024 => 2048
+ keepAliveTime: 9999 => 9999
+ executeTimeOut: 800 => 3000
+ rejectedType: SyncPutQueuePolicy => RunsOldestTaskPolicy
+ allowCoreThreadTimeOut: true => true
+```
+
+另外,当 Client 集群部署时,可以修改某一个实例,或选择 `全部修改` 按钮,修改所有实例线程池信息。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/_category_.json b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/_category_.json
new file mode 100644
index 00000000..bcd256c9
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/_category_.json
@@ -0,0 +1,7 @@
+{
+ "label": "社区",
+ "position": 1,
+ "link": {
+ "type": "generated-index"
+ }
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/contributor.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/contributor.md
new file mode 100644
index 00000000..f0185ad3
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/contributor.md
@@ -0,0 +1,24 @@
+---
+sidebar_position: 1
+---
+
+# 贡献指南
+
+Git Commit Log 尽量使用英文。
+
+Pull Request 尽量保持单一,不同语义的代码贡献应拆分多个 Pull Request。
+
+为了让您的 GitHub ID 显示在 Contributor 列表中,别忘了以下设置:
+
+```shell
+git config --global user.name "username"
+git config --global user.email "GitHub 账号邮箱"
+```
+
+## 贡献者列表
+
+您可以在 [Hippo4J](https://github.com/opengoofy/hippo4j/graphs/contributors) 和 [Hippo4J Console](https://github.com/opengoofy/hippo4j-console) 的贡献列表中找到全部的贡献者名单。
+
+
+
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/dev_convention/_category_.json b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/dev_convention/_category_.json
new file mode 100644
index 00000000..cb875453
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/dev_convention/_category_.json
@@ -0,0 +1,7 @@
+{
+ "label": "贡献规约",
+ "position": 2,
+ "link": {
+ "type": "generated-index"
+ }
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/dev_convention/code.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/dev_convention/code.md
new file mode 100644
index 00000000..f91acdbe
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/dev_convention/code.md
@@ -0,0 +1,8 @@
+---
+sidebar_position: 2
+---
+
+# 代码规约
+
+1. 代码提交前,执行 `mvn spotless:apply` 保证代码格式符合规范。
+2. 代码中不要出现无意义的空行。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/dev_convention/document.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/dev_convention/document.md
new file mode 100644
index 00000000..923ad81d
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/dev_convention/document.md
@@ -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 Gbps,SSD 一共有 20 TB。
+
+錯誤:
+
+> 我家的光纖入屋寬頻有 10Gbps,SSD 一共有 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 元。
+
+錯誤:
+
+> 這件蛋糕只賣 1000 元。
+
+例外:在設計稿、宣傳海報中如出現極少量數字的情形時,為方便文字對齊,是可以使用全形數字的。
+
+### 遇到完整的英文整句、特殊名詞,其內容使用半形標點
+
+正確:
+
+> 賈伯斯那句話是怎麼說的?「Stay hungry, stay foolish.」
+
+> 推薦你閱讀《Hackers & Painters: Big Ideas from the Computer Age》,非常的有趣。
+
+錯誤:
+
+> 賈伯斯那句話是怎麼說的?「Stay hungry,stay foolish。」
+
+> 推薦你閱讀《Hackers&Painters:Big 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](#) 並分配给相關同事。
+
+> 訪問我們網站的最新動態,請[點擊這裡](#)進行訂閱!
+
+### 簡體中文使用直角引號
+
+用法:
+
+> 「老师,『有条不紊』的『紊』是什么意思?」
+
+對比用法:
+
+> “老师,‘有条不紊’的‘紊’是什么意思?”
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/developer.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/developer.md
new file mode 100644
index 00000000..03cdd4e3
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/developer.md
@@ -0,0 +1,82 @@
+---
+sidebar_position: 2
+---
+
+# 核心开发者
+
+
+
+## 成为核心开发者
+
+持续对 Hippo-4J 进行贡献, 粗略评估,完成 10 次 PR 贡献即可成为核心开发者。 其中包括完成 2 个 [good pro issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+pro+issue%22) 或以上,以及 若干个 [good first issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)。
+
+:::note
+会根据 PR 质量提供个性化评估,有可能一个或两个质量较高 PR 即可成为核心开发者。参考:[重构 DynamicThreadPoolExecutor 功能扩展逻辑](https://github.com/opengoofy/hippo4j/pull/854)
+:::
+
+成为核心开发者后,会为该 GitHub 账号获取 Jetbrains 全家桶 Licenses,有效期为 1 年。不用再为破解而烦恼,感受随时升级的快乐。
+
+:::note
+距离到期两周前,会再次申请 Jetbrains Licenses。有点类似于无限续约的感觉,在此感谢 Jetbrains 公司对开源的支持。
+:::
+
+截至 `2022-10-30` 当天,已为登记的 7 位核心开发者成功申请 Licenses。
+
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/powered-by.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/powered-by.md
new file mode 100644
index 00000000..635d9011
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/powered-by.md
@@ -0,0 +1,37 @@
+---
+sidebar_position: 3
+---
+
+# 采用公司
+
+## 登记
+
+欢迎采用了 Hippo4J 的公司在此登记,非常感谢大家对 Hippo4J 的关注和支持,这是我们前进最大的动力。
+
+请按公司名 + 首页的格式在 [此处](https://github.com/opengoofy/hippo4j/issues/13) 登记。
+
+## 谁在使用 Hippo4J
+
+共计 21+ 家公司生产接入 Hippo4J。按照公司登记时间排序。
+
+- [身边云](https://serviceshare.com)
+- [Medbanks](https://www.medbanks.cn)
+- [北京智合联创科技有限公司](http://www.zhlc.com.cn)
+- [神州数码](http://www.digitalchina.com)
+- [payermax](https://www.payermax.com/)
+- [轻松到家](http://www.uyess.com/index.html)
+- [某商业银行股份有限公司](https://github.com/opengoofy/hippo4j/issues/13)
+- [某国际物流信息股份有限公司](https://github.com/opengoofy/hippo4j/issues/13)
+- [萨科(深圳)科技有限公司](https://www.lbdj.com/)
+- [广东天枢新能源科技有限公司](https://gd-tianshu.com/)
+- [FitTime](http://fittime.com/)
+- [百强国际物流](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/)
+- [远眺网络科技有限公司](https://www.yuantiaokj.com/)
+- [浙江吉利控股集团有限公司](https://www.geely.com/)
+- [三立人(深圳)科技有限公司-焦内](https://www.bananain.com/)
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/sponsor.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/sponsor.md
new file mode 100644
index 00000000..c73fc64a
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/community/sponsor.md
@@ -0,0 +1,23 @@
+---
+sidebar_position: 4
+---
+
+# 支持开源
+
+如果您正在使用这个项目并感觉良好,或者是想支持我继续开发,通过以下二维码一次性捐款。
+
+在这里承诺将,将收到的所有赞助支持资金完全公开化,且后续资金用途仅 Hippo-4J 项目的运转。
+
+
+
+感谢给予支持的朋友,您的支持是 Hippo-4J 社区前进的动力 🎉
+
+| | ID | 赞赏金额 | 时间 | 备注 |
+|-----|--|-------|------------|--------------------|
+| 1 | 六月飞雪 | 30.00 | 2021-12-30 | 代码设计很优雅的一款框架,继续加油! |
+| 2 | 孙大圣 | 26.6 | 2022-03-23 | 学习一下😁😁 |
+| 3 | Easy 点 | 66.00 | 2022-04-09 | 好货好技术当加赏 |
+| 4 | 捷克 | 30.00 | 2022-05-21 | 非常不错的框架,点赞 |
+| 5 | 吃猫的饼干 | 88.00 | 2022-08-21 | 👍 |
+| 6 | 不忘初心· | 66.00 | 2022-10-28 | Nice! |
+| 7 | 时刻· | 6.00 | 2022-10-30 | -! |
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/dev_manual/_category_.json b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/dev_manual/_category_.json
new file mode 100644
index 00000000..11f12432
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/dev_manual/_category_.json
@@ -0,0 +1,8 @@
+{
+ "label": "开发者手册",
+ "position": 5,
+ "link": {
+ "type": "generated-index",
+ "description": "Hippo4J 留给使用者能够扩展的知识点。"
+ }
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/dev_manual/rejected-policy-custom.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/dev_manual/rejected-policy-custom.md
new file mode 100644
index 00000000..1f2cf694
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/dev_manual/rejected-policy-custom.md
@@ -0,0 +1,57 @@
+---
+sidebar_position: 1
+---
+
+# 拒绝策略自定义
+
+Hippo4J 通过 SPI 的方式对拒绝策略进行扩展,可以让用户在 Hippo4J 中完成自定义拒绝策略实现。
+
+## Hippo4J Server 拒绝策略扩展
+
+自定义拒绝策略,实现 `CustomRejectedExecutionHandler` 接口,示例如下:
+
+```java
+public class ErrorLogRejectedExecutionHandler implements CustomRejectedExecutionHandler {
+
+ @Override
+ public Integer getType() {
+ return 12;
+ }
+
+ @Override
+ public RejectedExecutionHandler generateRejected() {
+ return new CustomErrorLogRejectedExecutionHandler();
+ }
+
+ public static class CustomErrorLogRejectedExecutionHandler implements RejectedExecutionHandler {
+
+ @Override
+ public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
+ Logger logger = LoggerFactory.getLogger(this.getClass());
+ logger.error("线程池抛出拒绝策略");
+ }
+ }
+}
+```
+
+创建 `src/main/resources/META-INF/services` 目录,创建 SPI 自定义拒绝策略文件 `cn.hippo4j.common.executor.support.CustomRejectedExecutionHandler`。
+
+`cn.hippo4j.common.executor.support.CustomRejectedExecutionHandler` 文件内仅放一行自定义拒绝策略全限定名即可,示例:
+
+```text
+cn.hippo4j.example.core.handler.ErrorLogRejectedExecutionHandler
+```
+
+创建、修改线程池页面选择 `CustomRejectedPolicy(自定义 SPI 策略)`。
+
+
+
+拒绝策略触发时,完成上述代码效果,仅打印异常日志提示。
+
+```text
+2022-08-01 21:27:49.515 ERROR 48928 --- [ateHandler.test] r$CustomErrorLogRejectedExecutionHandler : 线程池抛出拒绝策略
+```
+
+:::note
+具体参考 `hippo4j-example/hippo4j-spring-boot-starter-example` 模块。
+:::
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/dev_manual/rejected-policy-info.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/dev_manual/rejected-policy-info.md
new file mode 100644
index 00000000..d5c68138
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/dev_manual/rejected-policy-info.md
@@ -0,0 +1,50 @@
+---
+sidebar_position: 0
+---
+
+# 内置拒绝策略
+
+内置两种拒绝策略说明:
+
+**RunsOldestTaskPolicy**:添加新任务并由主线程运行最早的任务。
+
+```java
+public class RunsOldestTaskPolicy implements RejectedExecutionHandler {
+
+ @Override
+ public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
+ if (executor.isShutdown()) {
+ return;
+ }
+ BlockingQueue workQueue = executor.getQueue();
+ Runnable firstWork = workQueue.poll();
+ boolean newTaskAdd = workQueue.offer(r);
+ if (firstWork != null) {
+ firstWork.run();
+ }
+ if (!newTaskAdd) {
+ executor.execute(r);
+ }
+ }
+}
+```
+
+**SyncPutQueuePolicy**:主线程把拒绝任务以阻塞的方式添加到队列。
+
+```java
+@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);
+ }
+ }
+}
+```
\ No newline at end of file
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/_category_.json b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/_category_.json
new file mode 100644
index 00000000..72b1e151
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/_category_.json
@@ -0,0 +1,7 @@
+{
+ "label": "快速开始",
+ "position": 3,
+ "link": {
+ "type": "generated-index"
+ }
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/config/_category_.json b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/config/_category_.json
new file mode 100644
index 00000000..78b3d9c4
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/config/_category_.json
@@ -0,0 +1,5 @@
+{
+ "label": "依赖配置中心",
+ "position": 2,
+ "collapsed": true
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-default.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-default.md
new file mode 100644
index 00000000..9c9e0fc9
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-default.md
@@ -0,0 +1,45 @@
+---
+sidebar_position: 4
+---
+
+# 参数默认配置
+
+曾有多名小伙伴反馈说,项目中线程池一多,配置文件中配置就显得很臃肿。为此 hippo4j-config 开发出了动态线程池默认配置。
+
+```yaml
+spring:
+ dynamic:
+ thread-pool:
+ default-executor:
+ core-pool-size: 4
+ maximum-pool-size: 6
+ blocking-queue: ResizableCapacityLinkedBlockingQueue
+ queue-capacity: 1024
+ execute-time-out: 1000
+ keep-alive-time: 9999
+ rejected-handler: AbortPolicy
+ active-alarm: 90
+ capacity-alarm: 85
+ alarm: true
+ allow-core-thread-time-out: true
+ notify:
+ interval: 5
+ receives: chen.ma
+ executors:
+ - thread-pool-id: message-produce
+ - thread-pool-id: message-consume
+ core-pool-size: 80
+ maximum-pool-size: 100
+ execute-time-out: 1000
+ notify:
+ interval: 6
+ receives: chen.ma
+```
+
+`spring.dynamic.thread-pool.executors` 层级下,仅需要配置 `thread-pool-id`,其余配置从 `spring.dynamic.thread-pool.default-executor` 读取。
+
+如果 `spring.dynamic.thread-pool.executors` 下配置和 `spring.dynamic.thread-pool.default-executor` 冲突,以前者为主。
+
+通过该自定义配置方式,可减少大量重复线程池参数配置项,提高核心配置简洁度。
+
+提示:`spring.dynamic.thread-pool.default-executor` 层级下参数,不提供动态刷新功能。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-monitor.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-monitor.md
new file mode 100644
index 00000000..72528638
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-monitor.md
@@ -0,0 +1,117 @@
+---
+sidebar_position: 3
+---
+
+# 线程池监控
+
+## 线程池监控配置
+
+监控前置条件:需要先完成 hippo4j-config 的 [接入工作](/docs/user_docs/getting_started/config/hippo4j-config-start)。
+
+接下来引入 SpringBoot Actuator。Spring 2.x 一般都有版本指定,所以这里不用写版本号。
+
+```xml
+
+ io.micrometer
+ micrometer-registry-prometheus
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+```
+
+添加动态线程池监控相关配置:
+
+```yaml
+management:
+ metrics:
+ export:
+ prometheus:
+ enabled: true
+ server:
+ port: 29999 # 可选配置,如果不配置该 port,直接使用 ${server.port}
+ endpoints:
+ web:
+ exposure:
+ include: '*' # 测试使用,开启了所有端点,生产环境不建议 *
+spring:
+ dynamic:
+ thread-pool:
+ collect-type: micrometer
+```
+
+项目启动,访问 `http://localhost:29999/actuator/prometheus` 出现 `dynamic_thread_pool_` 前缀的指标,即为成功。
+
+
+
+## 配置 Prometheus
+
+通过 Docker 启动 Prometheus 服务。
+
+```shell
+docker run -d -p 9090:9090 --name prometheus prom/prometheus
+```
+
+添加 Prometheus 抽取数据任务。
+
+```shell
+# 进入 prometheus 容器内部
+docker exec -it prometheus /bin/sh
+# 编辑 prometheus 配置文件
+vi /etc/prometheus/prometheus.yml
+```
+
+scrape_configs 节点下新添加一个 job,如果 Prometheus 是 Docker 方式部署,`{scrape_configs.static_configs.targets}` 需要写本机的 IP。
+
+```yaml
+scrape_configs:
+ - job_name: 'dynamic-thread-pool-job'
+ scrape_interval: 5s
+ metrics_path: '/actuator/prometheus'
+ static_configs:
+ - targets: [ '127.0.0.1:29999' ]
+```
+
+配置成功后 `exit` 退出容器,并进行 Prometheus 容器重启 `docker restart prometheus`。
+
+访问 Prometheus 控制台 `http://localhost:9090/graph` 路径,能够展示相关指标即为配置成功。
+
+
+
+## 配置 Grafana
+
+```shell
+docker run -d -p 3000:3000 --name=grafana grafana/grafana
+```
+
+访问 Grafana 地址,[http://localhost:3000](http://localhost:3000) 用户名密码:`admin`
+
+Grafana 访问 `http://localhost:3000/datasources` 导入 Prometheus 数据源。
+
+
+
+> 如果 Prometheus 为 Docker 方式部署,HTTP URL 需要为本地 IP,比如:http://192.168.1.5:9090
+
+关注公众号 `龙台的技术笔记`,回复:`监控`,获取 Hippo4J Grafana DashBoard JSON 配置。
+
+| 公众号 | 回复关键词 |
+|:------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------------------------------:|
+|  |  |
+
+获取到 JSON 文件后,通过 `http://localhost:3000/dashboard/import` 将 JSON 文件导入至 Grafana DashBoard。
+
+
+
+下拉框内动态选择创建好的 Prometheus 数据源,并点击 `Import`。
+
+
+
+即可使用炫酷的 Hippo-4J 动态线程池监控 DashBoard。大家伙儿也可以根据个人喜好进行定制 DashBoard,如果觉得有优化点,欢迎和我联系贡献。
+
+
+
+如果项目客户端启动多个示例,动态线程池监控效果图如下:
+
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-more.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-more.md
new file mode 100644
index 00000000..2511b4f3
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-more.md
@@ -0,0 +1,80 @@
+---
+sidebar_position: 3
+---
+
+# 个性化配置
+
+以下所述特性自 hippo4j-config v1.4.2 及以上版本提供,由 hippo4j 核心开发者 [@pizihao](https://github.com/pizihao) 完成相应功能开发。
+
+## 需求背景
+
+**1)容器及三方框架线程池自定义启用**
+
+最初设计容器线程池和三方框架线程池的动态变更是和启动无关的。也就是说,启动时不会根据配置文件中相关参数去修改两者对应的线程池配置。
+
+这么设计的初衷是因为,不想让 hippo4j 过多的去介入框架原有的功能。因为容器和三方框架都支持线程池参数的自定义。
+
+也就造成,可能你在配置中心配置了对应的容器和三方框架线程池参数,启动时是无效的。但当修改配置文件任一配置,容器和三方框架线程池配置将生效。
+
+为了更好的用户体验,决定加入启用标识来控制:是否在项目初始化启动时,对容器和三方框架线程池参数进行修改。
+
+**2)客户端集群个性化配置**
+
+大家都知道,hippo4j-config 是依赖配置中心做线程池配置动态变更。这种模式有一种缺点:改动配置文件后,所有客户端都会变更。
+
+有些小伙伴希望 hippo4j-config 能够像 hippo4j-server 一样,能够针对单独的客户端进行配置变更。
+
+## 容器及三方框架线程池自定义启用
+
+容器及三方框架线程池添加启用配置,为了保持统一,动态线程池配置中也有该参数配置。配置项默认开启。
+
+```yaml
+spring:
+ dynamic:
+ thread-pool:
+ tomcat:
+ enable: true
+ executors:
+ - thread-pool-id: message-consume
+ enable: false
+ adapter-executors:
+ - threadPoolKey: 'input'
+ enable: true
+```
+
+## 客户端集群个性化配置
+
+分别在动态线程池、容器线程池以及三方框架线程池配置下增加 `nodes` 配置节点,通过该配置可匹配需要变更的节点。
+
+```yaml
+spring:
+ dynamic:
+ thread-pool:
+ tomcat:
+ nodes: 192.168.1.5:*,192.168.1.6:8080
+ executors:
+ - thread-pool-id: message-consume
+ nodes: 192.168.1.5:*
+ adapter-executors:
+ - threadPoolKey: 'input'
+ nodes: 192.168.1.5:*
+```
+
+来一段代码方法中的注释,大家就基本明白如何使用了。
+
+```java
+/**
+ * Matching nodes
+ * nodes is ip + port.Get 'nodes' in the new Properties,Compare this with the ip + port of Application.
+ * support prefix pattern matching. e.g:
+ *
+ * - 192.168.1.5:* -- Matches all ports of 192.168.1.5
+ * - 192.168.1.*:2009 -- Matches 2009 port of 192.168.1.*
+ * - * -- all
+ * - empty -- all
+ *
+ * The format of ip + port is ip : port.
+ */
+```
+
+`nodes` 可与 `enable` 同时使用。如此,基于配置中心的动态线程池实现方式,将能够更方便的支持个性化需求。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-springboot1x-adapter.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-springboot1x-adapter.md
new file mode 100644
index 00000000..693dd341
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-springboot1x-adapter.md
@@ -0,0 +1,121 @@
+---
+sidebar_position: 5
+---
+
+# 适配SpringBoot1x
+
+目前已支持 Nacos、Apollo 配置中心适配 SpringBoot 1.5.x 版本。
+
+```xml
+
+ cn.hippo4j
+ hippo4j-config-spring-boot-1x-starter
+ 1.4.2
+
+```
+
+Nacos SpringBoot 配置如下:
+
+```yaml
+spring:
+ cloud:
+ nacos:
+ config:
+ ext-config:
+ - data-id: hippo4j-nacos.yaml
+ group: DEFAULT_GROUP
+ refresh: true
+ server-addr: 127.0.0.1:8848
+ dynamic:
+ thread-pool:
+ config-file-type: yml
+ nacos:
+ data-id: hippo4j-nacos.yaml
+ group: DEFAULT_GROUP
+```
+
+Apollo SpringBoot 配置如下:
+
+```yaml
+apollo:
+ autoUpdateInjectedSpringProperties: true
+ bootstrap:
+ eagerLoad:
+ enabled: true
+ enabled: true
+ namespaces: application
+ meta: http://127.0.0.1:8080
+app:
+ id: dynamic-threadpool-example
+spring:
+ dynamic:
+ thread-pool:
+ apollo:
+ namespace: application
+```
+
+动态线程池通用配置如下:
+
+```yaml
+management:
+ context-path: /actuator
+ security:
+ enabled: false
+server:
+ port: 8091
+ servlet:
+ context-path: /example
+spring:
+ application:
+ name: dynamic-threadpool-example
+ dynamic:
+ thread-pool:
+ banner: true
+ check-state-interval: 5
+ collect-type: micrometer
+ config-file-type: properties
+ enable: true
+ executors:
+ - active-alarm: 80
+ alarm: true
+ allow-core-thread-time-out: true
+ blocking-queue: LinkedBlockingQueue
+ capacity-alarm: 80
+ core-pool-size: 1
+ execute-time-out: 1000
+ keep-alive-time: 6691
+ maximum-pool-size: 1
+ notify:
+ interval: 8
+ receives: chen.ma
+ queue-capacity: 1
+ rejected-handler: AbortPolicy
+ thread-name-prefix: message-consume
+ thread-pool-id: message-consume
+ - active-alarm: 80
+ alarm: true
+ allow-core-thread-time-out: true
+ blocking-queue: LinkedBlockingQueue
+ capacity-alarm: 80
+ core-pool-size: 1
+ execute-time-out: 1000
+ keep-alive-time: 6691
+ maximum-pool-size: 1
+ notify:
+ interval: 8
+ receives: chen.ma
+ queue-capacity: 1
+ rejected-handler: AbortPolicy
+ thread-name-prefix: message-produce
+ thread-pool-id: message-produce
+ notify-platforms:
+ - platform: WECHAT
+ token: ac0426a5-c712-474c-9bff-72b8b8f5caff
+ profiles:
+ active: dev
+```
+
+具体 Demo 运行请参考以下示例模块,已验证对应线程池动态变更、报警以及运行时监控功能。
+
+- `/hippo4j-config-nacos-spring-boot-1x-starter-example`
+- `hippo4j-example/hippo4j-config-apollo-spring-boot-1x-starter-example`
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-start.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-start.md
new file mode 100644
index 00000000..33f658c2
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-start.md
@@ -0,0 +1,193 @@
+---
+sidebar_position: 1
+---
+
+# 接入流程
+
+Nacos、Apollo、Zookeeper、ETCD、Polaris 配置中心任选其一。
+
+## hippo4j 配置
+
+```xml
+
+ cn.hippo4j
+ hippo4j-config-spring-boot-starter
+ 1.4.2
+
+```
+
+启动类上添加注解 `@EnableDynamicThreadPool`。
+
+```java
+@SpringBootApplication
+@EnableDynamicThreadPool
+public class ExampleApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(ExampleApplication.class, args);
+ }
+}
+```
+
+SpringBoot 应用配置文件添加:
+
+```yaml
+server:
+ port: 8090
+ servlet:
+ context-path: /example
+
+spring:
+ profiles:
+ active: dev
+
+ dynamic:
+ thread-pool:
+ # 是否开启动态线程池
+ enable: true
+ # 是否打印 banner
+ banner: true
+ # 是否开启线程池数据采集,对接 Micrometer、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、ETCD、Polaris 任选其一
+ nacos:
+ data-id: xxx
+ group: xxx
+ apollo:
+ namespace: xxxx
+ # 配置中心文件格式
+ config-file-type: yml
+ # tomcat、undertow、jetty 三种容器线程池,任选其一
+ undertow:
+ core-pool-size: 100
+ maximum-pool-size: 200
+ keep-alive-time: 1000
+ # 全局通知配置-是否报警
+ 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
+ # 阻塞队列名称,参考 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
+ queue-capacity: 1
+ execute-time-out: 1000
+ blocking-queue: 'LinkedBlockingQueue'
+ rejected-handler: 'AbortPolicy'
+ keep-alive-time: 1024
+ allow-core-thread-time-out: true
+ thread-name-prefix: 'message-consume'
+ alarm: true
+ active-alarm: 80
+ capacity-alarm: 80
+ notify:
+ interval: 8
+ receives: xxx
+```
+
+## ThreadPoolExecutor 适配
+
+添加线程池配置类,通过 `@DynamicThreadPool` 注解修饰。`threadPoolId` 为服务端创建的线程池 ID。
+
+```java
+package cn.hippo4j.example;
+
+import cn.hippo4j.core.executor.DynamicThreadPool;
+import cn.hippo4j.core.executor.support.ThreadPoolBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import java.util.concurrent.ThreadPoolExecutor;
+
+@Configuration
+public class ThreadPoolConfig {
+
+ @Bean
+ @DynamicThreadPool
+ public ThreadPoolExecutor messageConsumeDynamicExecutor() {
+ String threadPoolId = "message-consume";
+ ThreadPoolExecutor messageConsumeDynamicExecutor = ThreadPoolBuilder.builder()
+ .threadFactory(threadPoolId)
+ .threadPoolId(threadPoolId)
+ .dynamicPool()
+ .build();
+ return messageConsumeDynamicExecutor;
+ }
+
+ @Bean
+ @DynamicThreadPool
+ public ThreadPoolExecutor messageProduceDynamicExecutor() {
+ String threadPoolId = "message-produce";
+ ThreadPoolExecutor messageProduceDynamicExecutor = ThreadPoolBuilder.builder()
+ .threadFactory(threadPoolId)
+ .threadPoolId(threadPoolId)
+ .dynamicPool()
+ .build();
+ return messageProduceDynamicExecutor;
+ }
+
+}
+```
+
+通过 ThreadPoolBuilder 构建动态线程池,只有 threadFactory、threadPoolId 为必填项,其它参数会从配置中心拉取。
+
+项目中使用上述定义的动态线程池,如下所示:
+
+```java
+@Resource
+private ThreadPoolExecutor messageConsumeDynamicExecutor;
+
+messageConsumeDynamicExecutor.execute(() -> xxx);
+
+@Resource
+private ThreadPoolExecutor messageProduceDynamicExecutor;
+
+messageProduceDynamicExecutor.execute(() -> xxx);
+```
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/difference.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/difference.md
new file mode 100644
index 00000000..4e07d71b
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/difference.md
@@ -0,0 +1,37 @@
+---
+sidebar_position: 0
+---
+
+# 运行模式介绍
+
+1.1.0 版本发布后,Hippo-4J 分为两种使用模式:轻量级依赖配置中心以及无中间件依赖版本。
+
+
+
+### hippo4j-config
+
+**轻量级动态线程池管理**,依赖 Nacos、Apollo、Zookeeper、ETCD、Polaris 等三方配置中心(任选其一)完成线程池参数动态变更,支持运行时报警、监控等功能。
+
+> 监控功能配置详见:[线程池监控](/docs/user_docs/getting_started/config/hippo4j-config-monitor)
+
+
+
+### hippo4j-server
+
+**部署 hippo4j-server 服务**,通过可视化 Web 界面完成线程池的创建、变更以及查看,不依赖三方中间件。
+
+相比较 hippo4j-config,功能会更强大,但同时也引入了一定的复杂性。需要部署一个 Java 服务,以及依赖 MySQL 数据库。
+
+
+
+### 使用总结
+
+| | hippo4j-config | hippo4j-server |
+| ---- | ---------------------------------------------------- | ------------------------------------------------------------ |
+| 依赖 | Nacos、Apollo、Zookeeper、ETCD、Polaris 配置中心(任选其一) | 部署 Hippo-4J Server(内部无依赖中间件) |
+| 使用 | 配置中心补充线程池相关参数 | Hippo-4J Server Web 控制台添加线程池记录 |
+| 功能 | 包含基础功能:参数动态化、运行时监控、报警等 | 基础功能之外扩展控制台界面、线程池堆栈查看、线程池运行信息实时查看、历史运行信息查看、线程池配置集群个性化等 |
+
+使用建议:根据公司情况选择,如果基本功能可以满足使用,选择 hippo4j-config 使用即可;如果希望更多的功能,可以选择 hippo4j-server。
+
+**两者在进行替换的时候,无需修改业务代码**。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/hippo4j-adapter.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/hippo4j-adapter.md
new file mode 100644
index 00000000..030367e1
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/hippo4j-adapter.md
@@ -0,0 +1,72 @@
+---
+sidebar_position: 6
+---
+
+# 三方框架线程池适配
+
+Hippo4J 目前已支持的三方框架线程池列表:
+
+- Dubbo
+- Hystrix
+- RabbitMQ
+- RocketMQ
+- AlibabaDubbo
+- RocketMQSpringCloudStream
+- RabbitMQSpringCloudStream
+
+引入 Hippo4J Server 或 Core 的 Maven Jar 坐标后,还需要引入对应的框架适配 Jar:
+
+```xml
+
+ cn.hippo4j
+
+ hippo4j-spring-boot-starter-adapter-dubbo
+
+ hippo4j-spring-boot-starter-adapter-alibaba-dubbo
+
+ hippo4j-spring-boot-starter-adapter-hystrix
+
+ hippo4j-spring-boot-starter-adapter-rabbitmq
+
+ hippo4j-spring-boot-starter-adapter-rocketmq
+
+ hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rocketmq
+
+ hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rabbitmq
+ 1.4.2
+
+```
+
+如果想省事,仅需引入一个全量包,框架底层会根据条件判断加载具体线程池适配器。
+
+```xml
+
+ cn.hippo4j
+ hippo4j-spring-boot-starter-adapter-all
+ 1.4.2
+
+```
+
+## Hippo4J Server
+
+Hippo4J Server 仅需要引入上述 Jar 包,即可在 Hippo4J Server 的控制台进行查看及修改三方框架线程池。
+
+
+
+## Hippo4J Config
+
+Hippo4J Config 除了依赖上述适配 Jar 包外,还需要在配置中心添加以下配置项。
+
+```yaml
+spring:
+ dynamic:
+ thread-pool:
+ # 省略其它配置
+ adapter-executors:
+ # threadPoolKey 代表线程池标识
+ - threadPoolKey: 'input'
+ # mark 为三方线程池框架类型,参见文初已支持框架集合
+ mark: 'RocketMQSpringCloudStream'
+ corePoolSize: 10
+ maximumPoolSize: 10
+```
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/img/docsVersionDropdown.png b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/img/docsVersionDropdown.png
new file mode 100644
index 00000000..97e41646
Binary files /dev/null and b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/img/docsVersionDropdown.png differ
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/img/grafana-monitor.jpg b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/img/grafana-monitor.jpg
new file mode 100644
index 00000000..336bd980
Binary files /dev/null and b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/img/grafana-monitor.jpg differ
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/img/localeDropdown.png b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/img/localeDropdown.png
new file mode 100644
index 00000000..e257edc1
Binary files /dev/null and b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/img/localeDropdown.png differ
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/server/_category_.json b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/server/_category_.json
new file mode 100644
index 00000000..4063c17f
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/server/_category_.json
@@ -0,0 +1,5 @@
+{
+ "label": "无中间件依赖",
+ "position": 3,
+ "collapsed": true
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/server/hippo4j-server-config.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/server/hippo4j-server-config.md
new file mode 100644
index 00000000..24bf9a13
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/server/hippo4j-server-config.md
@@ -0,0 +1,19 @@
+---
+sidebar_position: 4
+---
+
+# 服务端配置
+
+`hippo4j.core.clean-history-data-enable`
+
+是否开启线程池历史数据清洗,默认开启。
+
+`hippo4j.core.clean-history-data-period`
+
+线程池历史数据保留时间,默认值:30,单位分钟。
+
+服务端会保留这个配置时间的数据,超过这个时间则会被清理。比如按照默认值 30 分钟来说,12:00 收集到的数据,12:30 就会被清理删除。
+
+`hippo4j.core.monitor.report-type`
+
+客户端监控上报服务端类型,可选值:http、netty,默认 http。服务端开启 netty 配置后,需要在客户端对应开启才可生效。用来应对大量动态线程池监控场景。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/server/hippo4j-server-start.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/server/hippo4j-server-start.md
new file mode 100644
index 00000000..64b94ee3
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/getting_started/server/hippo4j-server-start.md
@@ -0,0 +1,127 @@
+---
+sidebar_position: 3
+---
+
+# 接入流程
+
+部署服务端,参考 [部署手册](/docs/user_docs/ops/hippo4j-server-deploy)。
+
+服务端创建 [租户、项目](/docs/user_docs/other/issue#租户和项目在-hippo4j-中是什么意思) 和线程池记录。
+
+需要注意,项目 ID 需要与配置文件 `{application.name}` 保持一致。
+
+:::note
+租户、项目、线程池 ID 如果由多个词组成,建议以 - 进行分割。比如:message-center。
+:::
+
+## Hippo4J 配置
+
+SpringBoot Pom 引入 Hippo4j Starter Jar。
+
+```xml
+
+ cn.hippo4j
+ hippo4j-spring-boot-starter
+ 1.4.2
+
+```
+
+启动类上添加注解 `@EnableDynamicThreadPool`。
+
+```java
+@SpringBootApplication
+@EnableDynamicThreadPool
+public class ExampleApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(ExampleApplication.class, args);
+ }
+}
+```
+
+SpringBoot 应用配置文件添加:
+
+```yaml
+spring:
+ profiles:
+ active: dev
+ application:
+ # 服务端创建的项目 id 需要与 application.name 保持一致
+ name: dynamic-threadpool-example
+ dynamic:
+ thread-pool:
+ # 服务端地址
+ server-addr: http://localhost:6691
+ # 用户名
+ username: admin
+ # 密码
+ password: 123456
+ # 租户 id, 对应 tenant 表
+ namespace: prescription
+ # 项目 id, 对应 item 表
+ item-id: ${spring.application.name}
+```
+
+## ThreadPoolExecutor 适配
+
+添加线程池配置类,通过 `@DynamicThreadPool` 注解修饰。`threadPoolId` 为服务端创建的线程池 ID。
+
+```java
+package cn.hippo4j.example;
+
+import cn.hippo4j.core.executor.DynamicThreadPool;
+import cn.hippo4j.core.executor.support.ThreadPoolBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+@Configuration
+public class ThreadPoolConfig {
+
+ @Bean
+ @DynamicThreadPool
+ public ThreadPoolExecutor messageConsumeDynamicExecutor() {
+ String threadPoolId = "message-consume";
+ ThreadPoolExecutor messageConsumeDynamicExecutor = ThreadPoolBuilder.builder()
+ .threadFactory(threadPoolId)
+ .threadPoolId(threadPoolId)
+ .dynamicPool()
+ .build();
+ return messageConsumeDynamicExecutor;
+ }
+
+ @Bean
+ @DynamicThreadPool
+ public ThreadPoolExecutor messageProduceDynamicExecutor() {
+ String threadPoolId = "message-produce";
+ ThreadPoolExecutor messageProduceDynamicExecutor = ThreadPoolBuilder.builder()
+ .threadFactory(threadPoolId)
+ .threadPoolId(threadPoolId)
+ .dynamicPool()
+ .build();
+ return messageProduceDynamicExecutor;
+ }
+
+}
+```
+
+通过 ThreadPoolBuilder 构建动态线程池,只有 threadFactory、threadPoolId 为必填项,其它参数会从 hippo4j-server 服务拉取。
+
+:::note
+创建线程池时建议填充实际的参数。如果在连接 Hippo4J Server 端失败时,会使用填充配置创建线程池。
+:::
+
+项目中使用上述定义的动态线程池,如下所示:
+
+```java
+@Resource
+private ThreadPoolExecutor messageConsumeDynamicExecutor;
+
+messageConsumeDynamicExecutor.execute(() -> xxx);
+
+@Resource
+private ThreadPoolExecutor messageProduceDynamicExecutor;
+
+messageProduceDynamicExecutor.execute(() -> xxx);
+```
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/intro.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/intro.md
new file mode 100644
index 00000000..fd9e5dcb
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/intro.md
@@ -0,0 +1,616 @@
+---
+sidebar_position: 1
+---
+
+# 简介
+
+## 线程池痛点
+
+线程池是一种基于池化思想管理线程的工具,使用线程池可以减少创建销毁线程的开销,避免线程过多导致系统资源耗尽。在高并发以及大批量的任务处理场景,线程池的使用是必不可少的。
+
+如果有在项目中实际使用线程池,相信你可能会遇到以下痛点:
+
+- 线程池随便定义,线程资源过多,造成服务器高负载。
+
+- 线程池参数不易评估,随着业务的并发提升,业务面临出现故障的风险。
+- 线程池任务执行时间超过平均执行周期,开发人员无法感知。
+- 线程池任务堆积,触发拒绝策略,影响既有业务正常运行。
+- 当业务出现超时、熔断等问题时,因为没有监控,无法确定是不是线程池引起。
+- 原生线程池不支持运行时变量的传递,比如 MDC 上下文遇到线程池就 GG。
+- 无法执行优雅关闭,当项目关闭时,大量正在运行的线程池任务被丢弃。
+- 线程池运行中,任务执行停止,怀疑发生死锁或执行耗时操作,但是无从下手。
+
+## 什么是 Hippo-4J
+
+Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池等功能,为业务系统提高线上运行保障能力。
+
+提供以下功能支持:
+
+- 全局管控 - 管理应用线程池实例。
+
+- 动态变更 - 应用运行时动态变更线程池参数,包括不限于:核心、最大线程数、阻塞队列容量、拒绝策略等。
+- 通知报警 - 内置四种报警通知策略,线程池活跃度、容量水位、拒绝策略以及任务执行时间超长。
+- 运行监控 - 实时查看线程池运行时数据,最近半小时线程池运行数据图表展示。
+- 功能扩展 - 支持线程池任务传递上下文;项目关闭时,支持等待线程池在指定时间内完成任务。
+- 多种模式 - 内置两种使用模式:[依赖配置中心](https://hippo4j.cn/docs/user_docs/getting_started/config/hippo4j-config-start) 和 [无中间件依赖](https://hippo4j.cn/docs/user_docs/getting_started/server/hippo4j-server-start)。
+- 容器管理 - Tomcat、Jetty、Undertow 容器线程池运行时查看和线程数变更。
+- 框架适配 - Dubbo、Hystrix、RabbitMQ、RocketMQ 等消费线程池运行时数据查看和线程数变更。
+
+## 快速开始
+
+对于本地演示目的,请参阅 [Quick start](https://hippo4j.cn/docs/user_docs/user_guide/quick-start)
+
+演示环境: [http://console.hippo4j.cn/index.html](http://console.hippo4j.cn/index.html)
+
+## 接入登记
+
+更多接入的公司,欢迎在 [登记地址](https://github.com/opengoofy/hippo4j/issues/13) 登记,登记仅仅为了产品推广。
+
+## 联系我
+
+
+
+扫码添加微信,备注:hippo4j,邀您加入群聊。若图片加载不出来,访问 [官网站点](https://hippo4j.cn/docs/user_docs/other/group)。
+
+## 友情链接
+
+- [[ 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 学习指南。
+
+## 贡献者
+
+感谢所有为项目作出贡献的开发者。如果有意贡献,参考 [good first issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)。
+
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/ops/_category_.json b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/ops/_category_.json
new file mode 100644
index 00000000..d5b7d1e8
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/ops/_category_.json
@@ -0,0 +1,7 @@
+{
+ "label": "运维指南",
+ "position": 4,
+ "link": {
+ "type": "generated-index"
+ }
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/ops/hippo4j-server-deploy.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/ops/hippo4j-server-deploy.md
new file mode 100644
index 00000000..f78457ba
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/ops/hippo4j-server-deploy.md
@@ -0,0 +1,45 @@
+---
+sidebar_position: 1
+---
+
+# 源码包部署
+
+[RELEASE](https://github.com/opengoofy/hippo4j/releases) 页面下载对应版本并进行解压。
+
+## 初始化
+
+修改数据库相关信息。
+
+```txt
+/conf/application.properties
+```
+
+如果是新运行 Hippo-4J,数据库执行下述 SQL 脚本即可。
+
+```txt
+/conf/hippo4j_manager.sql
+```
+
+如果是对已运行 Hippo-4J 升级,请查看 `/conf/sql-upgrade` 目录下,是否有目标版本对应的升级脚本。
+
+## 直接运行
+
+Mac Linux 启动执行。
+
+```txt
+sh ./bin/startup.sh
+```
+
+Windows 启动执行。
+
+```txt
+bin/startup.cmd
+```
+
+## 访问控制台
+
+启动成功后,访问链接。用户名密码:admin 123456
+
+```txt
+localhost:6691/index.html
+```
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/ops/server-docker.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/ops/server-docker.md
new file mode 100644
index 00000000..141c597a
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/ops/server-docker.md
@@ -0,0 +1,50 @@
+---
+sidebar_position: 2
+---
+
+# Docker部署
+
+## 镜像启动
+
+Docker 镜像默认使用内置 H2 数据库,数据持久化到 Docker 容器存储卷中。
+
+```shell
+docker run -d -p 6691:6691 --name hippo4j-server hippo4j/hippo4j-server
+```
+
+或者,底层存储数据库切换为 MySQL。`DATASOURCE_HOST` 需要切换为本地 IP,不能使用 `127.0.0.1` 或 `localhost`。
+
+```shell
+docker run -d -p 6691:6691 --name hippo4j-server \
+-e DATASOURCE_MODE=mysql \
+-e DATASOURCE_HOST=xxx.xxx.xxx.xxx \
+-e DATASOURCE_PORT=3306 \
+-e DATASOURCE_DB=hippo4j_manager \
+-e DATASOURCE_USERNAME=root \
+-e DATASOURCE_PASSWORD=root \
+hippo4j/hippo4j-server
+```
+
+访问 Server 控制台,路径 `http://localhost:6691/index.html` ,默认用户名密码:admin / 123456
+
+## 镜像构建
+
+如果想要自定义镜像,可以通过以下命令快速构建 Hippo4J Server:
+
+方式一:
+
+```shell
+# 进入到 hippo4j-server/hippo4j-bootstrap 工程路径下
+mvn clean package -Dskip.spotless.apply=true
+# 默认打包是打包的 tag 是 latest
+docker build -t hippo4j/hippo4j-server ../hippo4j-bootstrap
+```
+
+方式二:
+
+通过 `maven docker plugin`
+
+```shell
+# 进入到 hippo4j-server 工程路径下
+mvn clean package -DskipTests -Dskip.spotless.apply=true docker:build
+```
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/_category_.json b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/_category_.json
new file mode 100644
index 00000000..a74d7432
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/_category_.json
@@ -0,0 +1,7 @@
+{
+ "label": "其它",
+ "position": 6,
+ "link": {
+ "type": "generated-index"
+ }
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/group.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/group.md
new file mode 100644
index 00000000..e75e96be
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/group.md
@@ -0,0 +1,9 @@
+---
+sidebar_position: 1
+---
+
+# 加群沟通
+
+扫码添加微信,备注:`hippo4j`,邀您加入群聊。
+
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/issue.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/issue.md
new file mode 100644
index 00000000..11f48a12
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/issue.md
@@ -0,0 +1,90 @@
+---
+sidebar_position: 2
+---
+
+# 常见问题
+
+- 租户和项目在 Hippo4J 中是什么意思
+- 控制台线程池管理和线程池实例的区别
+- 示例项目为什么会有跨域请求
+- 更新代码后运行时服务端SQL报错
+- 生产环境如何不启用动态线程池
+- Server 端宕机会影响 Client 运行么
+- Hippo4J 的发布方式是怎样的?如何选择正确的版本
+- 群机器人接受不到通知报警
+- 设置线程池参数优先级问题
+- 线程池实例中修改队列容量参数问题
+- 控制台 SocketTimeoutException: connect timed out
+
+## 租户和项目在 Hippo4J 中是什么意思
+
+Hippo4J 按照租户、项目、线程池的维度划分。
+
+举个例子,小编在一家公司的公共组件团队,团队中负责消息、短链接网关等项目。公共组件是租户,消息或短链接就是项目。
+
+## 控制台线程池管理和线程池实例的区别
+
+在线程池管理中修改线程池参数,客户端并不能实时感知到并变更参数,需要重启客户端。而线程池实例中去对具体的实例修改参数时,客户端无需重启,可以实时感知到参数变化。如果二者针对同一线程
+池的参数配置不同,则在重启客户端时,客户端会去拉去线程池管理中的参数配置。
+
+二者对应的定位:线程池管理中的配置是常态化配置。而线程池实例里的配置变更像是一种临时修改,比如突发的流量激增等场景,并不具备普适性。
+
+## 示例项目为什么会有跨域请求
+
+~~正常大家在部署时,服务端项目和客户端都在同一网络下,进行内网通信,是没有问题的。~~
+
+~~因为示例项目中,服务端部署在外网,而客户端注册到服务端 IP 是内网的,所以不通。~~
+
+~~涉及功能:线程池实例-查看、编辑,容器线程池。~~
+
+1.2.0 版本后,服务端访问客户端已变成,浏览器访问服务端,服务端转发客户端的形式完成调用,跨域问题已解决。
+
+## 更新代码后运行时服务端SQL报错
+
+如果更新代码运行功能出错,大概率是因为项目新增或修改了表结构。如版本升级迭代涉及数据库表变更,会额外提供 SQL 变更文件。
+
+如若第一次使用,初始化 SQL 脚本地址:[hippo4j_manager.sql](https://github.com/longtai-cn/hippo4j/blob/develop/hippo4j-server/conf/hippo4j_manager.sql)。
+
+> 友情提示:每次执行数据库表或数据变更时,一定要保持提前备份的好习惯。
+
+## 生产环境如何不启用动态线程池
+
+测试环境已经引入 Hippo4J,暂时不打算上线生产环境。
+
+生产环境指定配置 `spring.dynamic.thread-pool.enable=false`,测试环境和生产环境配置就会隔离。
+
+## Server 端宕机会影响 Client 运行么
+
+不会。Client 端包含对 Server 端的健康检查机制,Server 端不可用时会停止交互,检查到可用时重新建立连接交互。
+
+## Hippo4J 的发布方式是怎样的?如何选择正确的版本
+
+Hippo4J 发布时可能会涉及到两端发布,分别是 Server 和 Starter。如无特殊说明,**每一次的版本升级将兼容上一版本代码**。
+
+- 如涉及 Server 发布,会在 [发布列表页面](https://github.com/longtai-cn/hippo4j/releases) 创建最新的发行版本;
+- 如涉及 Starter 发布,将直接推送 Starter Jar 至中央仓库,Server 包版本不变。
+
+## 群机器人接受不到通知报警
+
+如果是钉钉机器人,需在机器人配置自定义关键字,才可发送成功。如下所示:
+
+
+
+如果使用 hippo4j-server,请检查在 hippo4j-server 添加的报警通知记录,是否在客户端项目启动前,因为客户端只有在启动时会去 hippo4j-server 拉取报警通知记录。
+
+重启客户端项目,会重新拉取最新报警推送配置,问题解决。
+
+## 设置线程池参数优先级问题
+
+- 当使用 `@DynamicThreadPool` 进行修饰的方法中和在管理界面设置中同时存在的话,则管理界面设置的优先级最高;
+- 如果连接 server 端失败的话,使用 `@DynamicThreadPool` 进行修饰设置的优先级最高。
+
+## 线程池实例中修改队列容量参数问题
+
+在线程池管理中添加时,只有当选择队列类型为 `ResizableCapacityLinkedBlockingQueue` 时,后续再进行修改容量大小时才会实时的刷新修改成功。
+
+## 控制台 SocketTimeoutException: connect timed out
+
+控制台中触发的某些操作涉及到 hippo4j-server 调用客户端项目。如果 hippo4j-server 部署在测试环境,而客户端项目为本地启动,则会触发该问题。
+
+为什么编辑线程池参数不报错?因为线程池的动态变更是客户端主动发起连接,和服务端保持了一个长轮询,所以不存在服务端主动调用客户端行为。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/official-ccounts.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/official-ccounts.md
new file mode 100644
index 00000000..61a1a5c6
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/official-ccounts.md
@@ -0,0 +1,23 @@
+---
+sidebar_position: 5
+---
+
+# 推荐公众号
+
+## JavaGuide
+
+专注Java后端学习和大厂面试的公众号!
+
+
+
+## HelloGitHub
+
+HelloGitHub,专注于开源社区技术和知识内容分享。
+
+
+
+## macrozheng
+
+专注Java技术分享,解析优质开源项目。涵盖SpringBoot、SpringCloud、Docker、K8S等实用技术,作者Github开源项目mall(50K+Star)。
+
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/operation.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/operation.md
new file mode 100644
index 00000000..ba9ed7f0
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/operation.md
@@ -0,0 +1,23 @@
+---
+sidebar_position: 6
+---
+
+# 公众号合作
+
+## 推荐须知
+
+hippo4j 作为一款新兴动态线程池框架,开源出来的时间比较晚,目前迫切需要不同的途径进行推广。
+
+如果您是公众号运营者或者开源爱好者,欢迎将 hippo4j 推荐给您的粉丝。
+
+1. 您无需为 hippo4j 专门撰写文案,只需要直接导入 [推荐文章](https://mp.weixin.qq.com/s/JTTwcBEiK_MnFcPTZl3zGA) 即可。
+2. 在文章底部或内容中留下项目官网或者 GitHub 仓库链接。
+3. 文章需至少 1000+ 的阅读量。
+
+作为推荐回报,hippo4j 可以为您:
+
+1. 在框架官方文档 [推荐公众号](/docs/user_docs/other/official-ccounts) 页面处留下您的公众号二维码。
+2. 在框架官方交流群里@全体成员推广您的公众号一次,附带介绍语。
+3. 您的公众号所有新推文章都可以将链接发送到 hippo4j 交流群中,增加阅读量。
+
+如果您还有除公众号以外的其它途径可以与 hippo4j 相互推荐,欢迎 [加群沟通](/docs/user_docs/other/group)。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/question.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/question.md
new file mode 100644
index 00000000..49fd4d77
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/question.md
@@ -0,0 +1,246 @@
+---
+sidebar_position: 3
+---
+
+# 问题提问
+
+文档引用自:[提问的智慧](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way)
+
+## 在提问之前
+
+在你准备要通过电子邮件、新闻群组或者聊天室提出技术问题前,请先做到以下事情:
+
+1. 尝试在你准备提问的论坛的旧文章中搜索答案。
+2. 尝试上网搜索以找到答案。
+3. 尝试阅读手册以找到答案。
+4. 尝试阅读常见问题文件(FAQ)以找到答案。
+5. 尝试自己检查或试验以找到答案。
+6. 向你身边的强者朋友打听以找到答案。
+7. 如果你是程序开发者,请尝试阅读源代码以找到答案。
+
+当你提出问题的时候,请先表明你已经做了上述的努力;这将有助于树立你并不是一个不劳而获且浪费别人的时间的提问者。如果你能一并表达在做了上述努力的过程中所**学到**的东西会更好,因为我们更乐于回答那些表现出能从答案中学习的人的问题。
+
+## 当你提问时
+
+### 慎选提问的论坛
+小心选择你要提问的场合。如果你做了下述的事情,你很可能被忽略掉或者被看作失败者:
+
+* 在与主题不合的论坛上贴出你的问题。
+* 在探讨进阶技术问题的论坛张贴非常初级的问题;反之亦然。
+* 在太多的不同新闻群组上重复转贴同样的问题(cross-post)。
+* 向既非熟人也没有义务解决你问题的人发送私人电邮。
+
+因此,第一步是找到对的论坛。再说一次,Google 和其它搜索引擎还是你的朋友,用它们来找到与你遭遇到困难的软硬件问题最相关的网站。通常那儿都有常见问题(FAQ)、邮件列表及相关说明文件的链接。如果你的努力(包括**阅读** FAQ)都没有结果,网站上也许还有报告 Bug(Bug-reporting)的流程或链接,如果是这样,链过去看看。
+
+### 使用有意义且描述明确的标题
+
+在邮件列表、新闻群组或论坛中,大约 50 字以内的标题是抓住资深专家注意力的好机会。别用喋喋不休的帮帮忙、跪求、急(更别说救命啊!!!!这样让人反感的话,用这种标题会被条件反射式地忽略)来浪费这个机会。不要妄想用你的痛苦程度来打动我们,而应该是在这点空间中使用极简单扼要的描述方式来提出问题。
+
+一个好标题范例是`目标 —— 差异`式的描述,许多技术支持组织就是这样做的。在`目标`部分指出是哪一个或哪一组东西有问题,在`差异`部分则描述与期望的行为不一致的地方。
+
+> 蠢问题:救命啊!我的笔记本电脑不能正常显示了!
+
+> 聪明问题:X.org 6.8.1 的鼠标指针会变形,某牌显卡 MV1005 芯片组。
+
+> 更聪明问题:X.org 6.8.1 的鼠标指针,在某牌显卡 MV1005 芯片组环境下 - 会变形。
+
+### 使用清晰、正确、精准且合乎语法的语句
+
+我们从经验中发现,粗心的提问者通常也会粗心地写程序与思考(我敢打包票)。回答粗心大意者的问题很不值得,我们宁愿把时间耗在别处。
+
+正确的拼写、标点符号和大小写是很重要的。一般来说,如果你觉得这样做很麻烦,不想在乎这些,那我们也觉得麻烦,不想在乎你的提问。花点额外的精力斟酌一下字句,用不着太僵硬与正式 —— 事实上,黑客文化很看重能准确地使用非正式、俚语和幽默的语句。但它**必须很**准确,而且有迹象表明你是在思考和关注问题。
+
+### 精确地描述问题并言之有物
+
+* 仔细、清楚地描述你的问题或 Bug 的症状。
+* 描述问题发生的环境(机器配置、操作系统、应用程序、以及相关的信息),提供经销商的发行版和版本号(如:`Fedora Core 4`、`Slackware 9.1`等)。
+* 描述在提问前你是怎样去研究和理解这个问题的。
+* 描述在提问前为确定问题而采取的诊断步骤。
+* 描述最近做过什么可能相关的硬件或软件变更。
+* 尽可能地提供一个可以`重现这个问题的可控环境`的方法。
+
+尽量去揣测一个黑客会怎样反问你,在你提问之前预先将黑客们可能提出的问题回答一遍。
+
+以上几点中,当你报告的是你认为可能在代码中的问题时,给黑客一个可以重现你的问题的环境尤其重要。当你这么做时,你得到有效的回答的机会和速度都会大大的提升。
+
+[Simon Tatham](http://www.chiark.greenend.org.uk/~sgtatham/) 写过一篇名为《[如何有效的报告 Bug](http://www.chiark.greenend.org.uk/~sgtatham/bugs-cn.html)》的出色文章。强力推荐你也读一读。
+
+### 话不在多而在精
+
+你需要提供精确有内容的信息。这并不是要求你简单的把成堆的出错代码或者资料完全转录到你的提问中。如果你有庞大而复杂的测试样例能重现程序挂掉的情境,尽量将它剪裁得越小越好。
+
+这样做的用处至少有三点。
+第一,表现出你为简化问题付出了努力,这可以使你得到回答的机会增加;
+第二,简化问题使你更有可能得到**有用**的答案;
+第三,在精炼你的 bug 报告的过程中,你很可能就自己找到了解决方法或权宜之计。
+
+### 别动辄声称找到 Bug
+
+当你在使用软件中遇到问题,除非你非常、**非常**的有根据,不要动辄声称找到了 Bug。提示:除非你能提供解决问题的源代码补丁,或者提供回归测试来表明前一版本中行为不正确,否则你都多半不够完全确信。这同样适用在网页和文件,如果你(声称)发现了文件的`Bug`,你应该能提供相应位置的修正或替代文件。
+
+请记得,还有其他许多用户没遇到你发现的问题,否则你在阅读文件或搜索网页时就应该发现了(你在抱怨前[已经做了这些,是吧](#在提问之前)?)。这也意味着很有可能是你弄错了而不是软件本身有问题。
+
+编写软件的人总是非常辛苦地使它尽可能完美。如果你声称找到了 Bug,也就是在质疑他们的能力,即使你是对的,也有可能会冒犯到其中某部分人。当你在标题中嚷嚷着有`Bug`时,这尤其严重。
+
+提问时,即使你私下非常确信已经发现一个真正的 Bug,最好写得像是**你**做错了什么。如果真的有 Bug,你会在回复中看到这点。这样做的话,如果真有 Bug,维护者就会向你道歉,这总比你惹恼别人然后欠别人一个道歉要好一点。
+
+### 低声下气不能代替你的功课
+
+有些人明白他们不该粗鲁或傲慢的提问并要求得到答复,但他们选择另一个极端 —— 低声下气:`我知道我只是个可悲的新手,一个撸瑟,但...`。这既使人困扰,也没有用,尤其是伴随着与实际问题含糊不清的描述时更令人反感。
+
+别用原始灵长类动物的把戏来浪费你我的时间。取而代之的是,尽可能清楚地描述背景条件和你的问题情况。这比低声下气更好地定位了你的位置。
+
+有时网页论坛会设有专为新手提问的版面,如果你真的认为遇到了初学者的问题,到那去就是了,但一样别那么低声下气。
+
+### 描述问题症状而非你的猜测
+
+告诉黑客们你认为问题是怎样造成的并没什么帮助。(如果你的推断如此有效,还用向别人求助吗?),因此要确信你原原本本告诉了他们问题的症状,而不是你的解释和理论;让黑客们来推测和诊断。如果你认为陈述自己的猜测很重要,清楚地说明这只是你的猜测,并描述为什么它们不起作用。
+
+**蠢问题**
+
+> 我在编译内核时接连遇到 SIG11 错误,
+> 我怀疑某条飞线搭在主板的走线上了,这种情况应该怎样检查最好?
+
+**聪明问题**
+
+> 我的组装电脑是 FIC-PA2007 主机板搭载 AMD K6/233 CPU(威盛 Apollo VP2 芯片组),
+> 256MB Corsair PC133 SDRAM 内存,在编译内核时,从开机 20 分钟以后就频频产生 SIG11 错误,
+> 但是在头 20 分钟内从没发生过相同的问题。重新启动也没有用,但是关机一晚上就又能工作 20 分钟。
+> 所有内存都换过了,没有效果。相关部分的标准编译记录如下…
+
+由于以上这点似乎让许多人觉得难以配合,这里有句话可以提醒你:`所有的诊断专家都来自密苏里州。` 美国国务院的官方座右铭则是:`让我看看`(出自国会议员 Willard D. Vandiver 在 1899 年时的讲话:`我来自一个出产玉米,棉花,牛蒡和民主党人的国家,滔滔雄辩既不能说服我,也不会让我满意。我来自密苏里州,你必须让我看看。`) 针对诊断者而言,这并不是一种怀疑,而只是一种真实而有用的需求,以便让他们看到的是与你看到的原始证据尽可能一致的东西,而不是你的猜测与归纳的结论。所以,大方的展示给我们看吧!
+
+### 按发生时间先后列出问题症状
+
+问题发生前的一系列操作,往往就是对找出问题最有帮助的线索。因此,你的说明里应该包含你的操作步骤,以及机器和软件的反应,直到问题发生。在命令行处理的情况下,提供一段操作记录(例如运行脚本工具所生成的),并引用相关的若干行(如 20 行)记录会非常有帮助。
+
+如果挂掉的程序有诊断选项(如 -v 的详述开关),试着选择这些能在记录中增加调试信息的选项。记住,`多`不等于`好`。试着选取适当的调试级别以便提供有用的信息而不是让读者淹没在垃圾中。
+
+如果你的说明很长(如超过四个段落),在开头简述问题,接下来再按时间顺序详述会有所帮助。这样黑客们在读你的记录时就知道该注意哪些内容了。
+
+### 描述目标而不是过程
+
+如果你想弄清楚如何做某事(而不是报告一个 Bug),在开头就描述你的目标,然后才陈述重现你所卡住的特定步骤。
+
+经常寻求技术帮助的人在心中有个更高层次的目标,而他们在自以为能达到目标的特定道路上被卡住了,然后跑来问该怎么走,但没有意识到这条路本身就有问题。结果要费很大的劲才能搞定。
+
+**蠢问题**
+
+> 我怎样才能从某绘图程序的颜色选择器中取得十六进制的 RGB 值?
+
+**聪明问题**
+
+> 我正试着用替换一幅图片的色码(color table)成自己选定的色码,我现在知道的唯一方法是编辑每个色码区块(table slot),
+> 但却无法从某绘图程序的颜色选择器取得十六进制的 RGB 值。
+
+第二种提问法比较聪明,你可能得到像是```建议采用另一个更合适的工具```的回复。
+
+### 清楚明确的表达你的问题以及需求
+
+漫无边际的提问是近乎无休无止的时间黑洞。最有可能给你有用答案的人通常也正是最忙的人(他们忙是因为要亲自完成大部分工作)。这样的人对无节制的时间黑洞相当厌恶,所以他们也倾向于厌恶那些漫无边际的提问。
+
+如果你明确表述需要回答者做什么(如提供指点、发送一段代码、检查你的补丁、或是其他等等),就最有可能得到有用的答案。因为这会定出一个时间和精力的上限,便于回答者能集中精力来帮你。这么做很棒。
+
+要理解专家们所处的世界,请把专业技能想像为充裕的资源,而回复的时间则是稀缺的资源。你要求他们奉献的时间越少,你越有可能从真正专业而且很忙的专家那里得到解答。
+
+所以,界定一下你的问题,使专家花在辨识你的问题和回答所需要付出的时间减到最少,这技巧对你有用答案相当有帮助 —— 但这技巧通常和简化问题有所区别。因此,问`我想更好地理解 X,可否指点一下哪有好一点说明?`通常比问`你能解释一下 X 吗?`更好。如果你的代码不能运作,通常请别人看看哪里有问题,比要求别人替你改正要明智得多。
+
+### 礼多人不怪,而且有时还很有帮助
+
+彬彬有礼,多用`请`和`谢谢您的关注`,或`谢谢你的关照`。让大家都知道你对他们花时间免费提供帮助心存感激。
+
+坦白说,这一点并没有比使用清晰、正确、精准且合乎语法和避免使用专用格式重要(也不能取而代之)。黑客们一般宁可读有点唐突但技术上鲜明的 Bug 报告,而不是那种有礼但含糊的报告。(如果这点让你不解,记住我们是按问题能教给我们什么来评价问题的价值的)
+
+然而,如果你有一串的问题待解决,客气一点肯定会增加你得到有用回应的机会。
+
+(我们注意到,自从本指南发布后,从资深黑客那里得到的唯一严重缺陷反馈,就是对预先道谢这一条。一些黑客觉得`先谢了`意味着事后就不用再感谢任何人的暗示。我们的建议是要么先说`先谢了`,**然后**事后再对回复者表示感谢,或者换种方式表达感激,譬如用`谢谢你的关注`或`谢谢你的关照`。)
+
+## 不该问的问题
+
+以下是几个经典蠢问题,以及黑客没回答时心中所想的:
+
+问题:[我能在哪找到 X 程序或 X 资源?](#q1)
+
+问题:[我怎样用 X 做 Y?](#q2)
+
+问题:[我的程序/设定/SQL 语句没有用](#q3)
+
+问题:[我的 Windows 电脑有问题,你能帮我吗?](#q4)
+
+问题:[我的程序不会动了,我认为系统工具 X 有问题](#q5)
+
+问题:[我在安装 Linux(或者 X )时有问题,你能帮我吗?](#q6)
+
+问题:[我怎么才能破解 root 帐号/窃取 OP 特权/读别人的邮件呢?](#q7)
+
+---
+
+> 问题:我能在哪找到 X 程序或 X 资源?
+
+回答:就在我找到它的地方啊,白痴 —— 搜索引擎的那一头。天哪!难道还有人不会用 [Google](https://www.google.com) 吗?
+
+> 问题:我怎样用 X 做 Y?
+
+回答:如果你想解决的是 Y ,提问时别给出可能并不恰当的方法。这种问题说明提问者不但对 X 完全无知,也对 Y 要解决的问题糊涂,还被特定形势禁锢了思维。最好忽略这种人,等他们把问题搞清楚了再说。
+
+> 问题:我的{程序/设定/SQL 语句}没有用
+
+回答:这不算是问题吧,我对要我问你二十个问题才找得出你真正问题的问题没兴趣 —— 我有更有意思的事要做呢。在看到这类问题的时候,我的反应通常不外如下三种
+
+* 你还有什么要补充的吗?
+* 真糟糕,希望你能搞定。
+* 这关我屁事?
+
+> 问题:我的 Windows 电脑有问题,你能帮我吗?
+
+回答:能啊,扔掉微软的垃圾,换个像 Linux 或 BSD 的开源操作系统吧。
+
+注意:如果程序有官方版 Windows 或者与 Windows 有互动(如 Samba),你**可以**问与 Windows 相关的问题,只是别对问题是由 Windows 操作系统而不是程序本身造成的回复感到惊讶, 因为 Windows 一般来说实在太烂,这种说法通常都是对的。
+
+> 问题:我的程序不会动了,我认为系统工具 X 有问题
+
+回答:你完全有可能是第一个注意到被成千上万用户反复使用的系统调用与函数库文件有明显缺陷的人,更有可能的是你完全没有根据。不同凡响的说法需要不同凡响的证据,当你这样声称时,你必须有清楚而详尽的缺陷说明文件作后盾。
+
+> 问题:我在安装 Linux(或者 X )时有问题,你能帮我吗?
+
+回答:不能,我只有亲自在你的电脑上动手才能找到毛病。还是去找你当地的 Linux 使用群组者寻求实际的指导吧(你能在[这儿](http://www.linux.org/groups/index.html)找到用户群组的清单)。
+
+注意:如果安装问题与某 Linux 的发行版有关,在它的邮件列表、论坛或本地用户群组中提问也许是恰当的。此时,应描述问题的准确细节。在此之前,先用 `Linux` 和**所有**被怀疑的硬件作关键词仔细搜索。
+
+> 问题:我怎么才能破解 root 帐号/窃取 OP 特权/读别人的邮件呢?
+
+回答:想要这样做,说明了你是个卑鄙小人;想找个黑客帮你,说明你是个白痴!
+
+## 好问题与蠢问题
+
+最后,我将透过举一些例子,来说明怎样聪明的提问;同一个问题的两种问法被放在一起,一种是愚蠢的,另一种才是明智的。
+
+**蠢问题**:
+
+> 我从 foo 项目找来的源码没法编译。它怎么这么烂?
+
+他觉得都是别人的错,这个傲慢自大的提问者。
+
+**聪明问题**:
+
+> foo 项目代码在 Nulix 6.2 版下无法编译通过。我读过了 FAQ,但里面没有提到跟 Nulix 有关的问题。这是我编译过程的记录,我有什么做的不对的地方吗?
+
+提问者已经指明了环境,也读过了 FAQ,还列出了错误,并且他没有把问题的责任推到别人头上,他的问题值得被关注。
+
+**蠢问题**:
+
+> 我的主机板有问题了,谁来帮我?
+
+某黑客对这类问题的回答通常是:`好的,还要帮你拍拍背和换尿布吗?`,然后按下删除键。
+
+**聪明问题**:
+
+> 我在 S2464 主机板上试过了 X 、 Y 和 Z ,但没什么作用,我又试了 A 、 B 和 C 。请注意当我尝试 C 时的奇怪现象。显然 florbish 正在 grommicking,但结果出人意料。通常在 Athlon MP 主机板上引起 grommicking 的原因是什么?有谁知道接下来我该做些什么测试才能找出问题?
+
+## 如果得不到回答
+
+如果仍得不到回答,请不要以为我们觉得无法帮助你。有时只是看到你问题的人不知道答案罢了。没有回应不代表你被忽视,虽然不可否认这种差别很难区分。
+
+总的来说,简单的重复张贴问题是个很糟的点子。这将被视为无意义的喧闹。有点耐心,知道你问题答案的人可能生活在不同的时区,可能正在睡觉,也有可能你的问题一开始就没有组织好。
+
+你可以通过其他渠道获得帮助,这些渠道通常更适合初学者的需要。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/update-log.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/update-log.md
new file mode 100644
index 00000000..fc7b2fda
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/other/update-log.md
@@ -0,0 +1,299 @@
+---
+sidebar_position: 4
+---
+
+# 更新日志
+
+## 1.4.2 (Oct 18, 2022)
+
+这是一个功能增强版本,修复了少量 BUG。建议按照当前版本升级。具体信息可查看 Release 标签地址:[1.4.2](https://github.com/opengoofy/hippo4j/milestone/12?closed=1)
+
+**Feature**
+
+- 强制指定客户端注册的 ip + port
+- 支持 spring-cloud-tencent Polaris 线程池动态更新 @weihubeats
+- 服务启动时加载 MySQL、H2 数据库初始化语句
+- Adapter 初始化覆盖核心参数 @pizihao
+- Server 端新增是否开启认证模式 @baymax55
+
+**Refactor**
+
+- 替换底层网络工具类 OkHttp @yanrongzhen
+- 全局移除 commons-lang3 工具包依赖 @yanrongzhen
+- 去除三方工具类依赖 @pizihao
+- 全局移除 Guava 工具包依赖 @road2master
+- DockerFile 基于 H2 数据库重新构建 @BigXin0109
+
+**Bug**
+
+- Dubbo 2.7.15 无法获取线程池引用 @iwangjie
+- 动态线程池报警参数颠倒 @jinlingmei
+
+**Optimize**
+
+- 线程池实例运行数据采集,如果线程池id不存在,且长度超长,会报异常 @Gdk666
+- 项目中动态线程池数量为空时,存在 CPU 空转情况
+- 客户端注册服务端失败,输出服务端返回信息 @wulangcode
+- 调整数据库项目 id 和线程池 id 字段长度
+- 增加代码检查工具 maven-checkstyle-plugin
+- 调整控制台监控图表颜色展示
+
+## 1.4.1 (Sep 12, 2022)
+
+这是一个功能增强版本,修复了若干 BUG。建议按照当前版本升级。具体信息可查看 Release 标签地址:[1.4.1](https://github.com/opengoofy/hippo4j/milestone/11?closed=1)
+
+**Feature**
+
+- 支持 H2 数据库 @weihubeats
+- 动态线程池配置变更时,支持单个、多个或全部节点变 @pizihao
+- 增加线程池活跃度和容量报警可选择关闭
+- @DynamicThreadPool 线程池不存在则创建 @shanjianq
+- 支持 ETCD 配置中心动态调整参数 @weihubeats
+- 创建动态线程池支持 spring 线程池 @BigXin0109
+- 线程池实例变更增加执行超时时间
+- 线程池相关查询页面增加阻塞队列属性
+- 定义动态线程池时,抽象默认配置
+- 提供 ExecutorContext 封装上下文细节 @road2master
+- Docker 制作服务端镜像,帮助开发者快速启动 @BigXin0109
+- RabbitMQ 适配器增加多个 MQ 数据源 @weihubeats
+
+**Bug**
+
+- 动态线程池设置关闭时启动报错 @dousp
+- ExecutorTtlWrapper 类型的 Executor 不生效 @BigXin0109
+- Undertow 获取 WebServer 类型参数异常 @shining-stars-lk
+- 修复线程池核心、最大线程数校验限制
+- ByteConvertUtil#getPrintSize 单位转换错误 @onesimplecoder
+- 创建线程池单选框选择错误
+- ReflectUtil#getFieldsDirectly missing fields @BigXin0109
+- 本地代码中设置的 capacity 无效 @BigXin0109
+- 服务端线程池超时时间存在拆箱空指针异常 @oreoft
+- 未读取服务端返回执行超时时间属性
+- ResizableCapacityLinkedBlockingQueue#put 当前元素数量大于 capacity 未阻塞
+
+**Optimize**
+
+- 长轮询任务判断逻辑优化 @shining-stars-lk
+- 线程池存在实例不允许删除线程池 @shanjianq
+- 优化租户、项目列表展示排版
+- 通知报警模块项目和线程池下拉查询排序修改
+- 动态线程池拒绝策略触发,以异步的方式报警
+- 优化框架中线程池工厂产生的线程名称 @road2master
+
+## 1.4.0 (Aug 16, 2022)
+
+`hippo4j server` 兼容历史低版本,`hippo4j config` 中部分属性名进行了调整,请参考 [hippo4j config 快速开始](https://hippo4j.cn/docs/user_docs/getting-started/hippo4j-core-start)。
+
+注意事项:
+1. 如果是对已运行 hippo4j server 升级,执行 `/conf/sql-upgrade` 目录下对应的升级脚本。
+2. 需客户端在 1.4.0 及以上版本才可在 hippo4j server 设置线程执行超时时间属性。
+
+**Feature**
+
+- 添加 Alibaba Dubbo 线程池监控及动态变更
+- hippo4j server 支持任务执行超时时间动态修改
+- 阿里 TTL 框架线程池适配
+- 添加动态线程池自动注册功能
+- 订阅回调线程池参数变更
+- 动态线程池监控增加 SPI 自定义功能
+- hippo4j server 支持多种线程池监控方式,例如 Prometheus
+- 通知相关参数添加动态变更功能
+
+**Bug**
+
+- 线程池变更:executeTimeOut 变更极端情况下会出现异常
+- 用户登录时候,如果输入了不存在的用户名,后台报空指针异常
+- 修复了对 spring-boot 服务中 tomcat 线程池的兼容问题
+- 排除 Tomcat Jar 使用 Undertow 启动报错
+
+**Optimize**
+
+- hippo4j-core-spring-boot-starter 模块修改名称为 hippo4j-config-spring-boot-starter
+- 拆分容器线程池子页面:Tomcat、Undertow、Jetty
+- 服务端访问客户端时对 URL 转码
+- MyBatisPlus 修改全局填充方法优化
+- 控制台线程池列表下拉框默认正序
+- 控制台线程池实例菜单,对于非可修改容量队列外,不允许修改队列容量
+- 动态线程池控制台功能变更
+- 租户和项目列表分页查询按照创建时间倒序展示
+- 线程池监控页面图表 UI 优化
+- 设置 maven-gpg-plugin 插件默认不执行
+- 前端控制台相关搜索条件添加必填提示
+- hippo4j 消息通知 & 报警抽象优化
+- 配置中心未配置线程池启动报错
+- 控制台线程池报警 UI 以及功能优化
+- Web、框架线程池编辑弹框 UI 优化
+- 线程池添加、编辑页面 UI 优化
+- 线程池运行详情页前端 UI 优化
+
+**Refactor**
+
+- 删除自定义日志组件
+- 线程池监控功能重构
+- hippo4j core 配置中心生效判断重构
+- 配置变更通知 & 报警通知重构
+- Web 容器线程池适配迁移 hippo4j-adapter
+
+## 1.3.1 (July 17, 2022)
+
+注:这是一个兼容历史版本的小范围升级。
+
+**Feature**
+
+- 控制台新增线程池功能设置为 Admin 权限
+- 添加 Hystrix 线程池监控及动态变更
+- 添加 Netty 上传动态线程池监控数据方式
+- 添加 GitHub Actions CI 流程
+- 添加 Spring Kafka 示例项目
+- Tomcat 版本号 >= 9.0.55 线程池适配
+
+**Refactor**
+
+- 更多线程池拆分子目录页面
+
+**Optimize**
+
+- hippo4j core 添加 banner 打印
+- 优化可变更容量阻塞队列名称
+
+**BUG**
+
+- Apollo 配置修改延迟了一个版本
+- Spring Boot 环境下使用 hippo4j-core 接入,配置中心使用 nacos;启动时提示 ConfigService not found
+
+查看 1.3.1 版本发布:https://github.com/mabaiwan/hippo4j/milestone/9
+
+## 1.3.0 (June 06, 2022)
+
+1.3.0 发布 **适配三方框架的基础框架**。
+
+目前已完成 **Dubbo、RabbitMQ、RocketMQ、RocketMQSpringCloudStream** 的线程池适配,后续还会接入 **Kafka、Hystrix** 等框架或中间件的线程池适配。
+
+注:这是一个兼容历史版本的重大升级。
+
+**Feature**
+
+- 添加 RabbitMQ 线程池监控及动态变更
+- 添加 RocketMQ 线程池监控及动态变更
+- 添加 Dubbo 线程池监控及动态变更
+- 添加 SpringCloud Stream RocketMQ 消费线程池监控及动态变更
+
+**Refactor**
+
+- 重构容器线程池查询及修改功能
+- 优化配置中心触发监听后,所执行的数据变更逻辑
+
+**Optimize**
+
+- 前端控制台删除无用组件
+- 服务端页面字段未显示中文
+- 控制台 UI 优化
+- 修改线程池实例后实时刷新列表参数
+- 容器线程池编辑仅限 Admin 权限
+- SpringBoot Starter 变更包路径
+
+**BUG**
+
+- 修复 SpringBoot Nacos 动态刷新不生效
+- 报警配置 alarm=false 不配置通知报警平台和接收人报错
+
+## 1.2.1 (May 07, 2022)
+
+**BugFix**
+
+- apollo 动态配置不生效
+- 修复 hippo4j-core 后置处理器创建线程池问题
+- 重构 hippo4j-core spring 后置处理器逻辑
+- 优化ThreadPoolNotifyAlarmHandler下的空指针异常
+- 修复线程池核心、最大线程数变更问题
+- startup.cmd 未正常读取 conf 配置文件
+
+**Optimize**
+
+- 配置文件中字段歧义
+- 修改代码中历史网址
+- InstanceInfo 的 groupKey 参数重复设置
+- ConfigFileTypeEnum 枚举字段添加注释
+- 线程资源通过线程池创建,不允许自行显示创建线程
+- Guava 版本升级至 30.0-jre 及以上版本
+- SystemClock 替换 System.currentTimeMillis()
+- 添加代码格式化插件 Spotless
+- 修改线程池文案
+
+## 1.2.0 (Mar 13, 2022)
+
+**Feature**
+
+- hippo4j-core线程池资源对接 Prometheus 监控
+- hippo4j-core 支持 Zookeeper
+- hippo4j-core 支持 Apollo
+
+**Optimize**
+
+- 适配非 Web SpringBoot 项目使用 Hippo4J
+- 优化报警通知
+- 修复在 JDK 小版本中的兼容性问题
+
+**BugFix**
+
+- server 端查看容器线程池,参数为 null
+- 重构线程池查看及容器线程池查看等交互
+- 修复引入 hippo4j-spring-boot-starter 后,运行单元测试报错
+- 修复可能出现的空指针异常
+
+## 1.1.0 (Mar 13, 2022)
+
+Hippo4J 线程池框架 1.1.0 RELEASE 版本,添加了 Hippo4J-Core(依赖配置中心的动态线程池).
+
+**Feature**
+
+- 删除 DynamicThreadPoolExecutor 内代码实现,仅通过线程池扩展点进行扩展
+- 通过动态代理实现线程池拒绝策略执行次数统计
+- 抽象通知报警消息模块
+- 抽象 hippo4j 核心组件,不依赖 server 端即可完成动态调参、监控、报警等功能
+- 前端删除线程池按钮添加 Admin 权限
+- 添加线程池任务运行超长报警
+- 容器线程池支持 Undertow
+- 容器线程池支持 Jetty
+- 重构服务端异常体系
+
+**Optimize**
+
+- 前端项目 Token 失效跳转登录页
+- 优化 Server 启动脚本日志输出
+- 优化前端按钮权限控制粒度
+- 优化线程池报警推送文案
+- 前端弹框样式优化
+- 适配低版本 SpringBoot Bind
+- 优化消息通知模块
+
+**BugFix**
+
+- Duplicate entry 'xxx' for key 'uk_configinfo_datagrouptenant'
+
+## 1.0.0 (Feb 01, 2022)
+
+**Feature**
+
+- 线程池运行堆栈查看
+- 扩展 Web 容器线程池动态调参、监控
+
+**Optimize**
+
+- 删除高版本 SpringBoot Api
+- ListableBeanFactory#findAnnotationOnBean SpringBoot 低版本适配
+- 优化客户端关闭时调用服务端钩子函数
+- 线程池实例参数弹框添加实例 ID 和线程池状态
+- 补充线程池替换 Hippo4J 文档
+- 1.5.x springboot 引入hippo4j-spring-boot-starter配置项,bean初始化失败
+- 优化线程池参数编辑合理性校验
+- BaseInstanceRegistry 读写锁重构
+
+**BugFix**
+
+- 本地项目线程池实例缓存无法精确清理
+- 线程池实例页面多实例不同 Active 展示错误
+- 创建动态线程池逻辑判断修复
+- 创建动态线程池增强参数未设置
+- 控制消息推送报警频率的方法有并发安全的问题
+- tomcat线程池上下文获取失败
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/user_guide/_category_.json b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/user_guide/_category_.json
new file mode 100644
index 00000000..6dc10c33
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/user_guide/_category_.json
@@ -0,0 +1,8 @@
+{
+ "label": "用户指南",
+ "position": 2,
+ "link": {
+ "type": "generated-index",
+ "description": "帮助想要了解 Hippo4J 的用户快速掌握核心开发理念。"
+ }
+}
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/user_guide/frame.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/user_guide/frame.md
new file mode 100644
index 00000000..47f568fa
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/user_guide/frame.md
@@ -0,0 +1,60 @@
+---
+sidebar_position: 1
+---
+
+# 为什么写
+
+[美团线程池文章](https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html "美团线程池文章") 介绍中,因为业务对线程池参数没有合理配置,触发过几起生产事故,进而引发了一系列思考。最终决定封装线程池动态参数调整,扩展线程池监控以及消息报警等功能。
+
+在开源平台找了挺多动态线程池项目,从功能性以及健壮性而言,个人感觉不满足企业级应用。
+
+因为对动态线程池比较感兴趣,加上想写一个有意义的项目,所以决定自己来造一个轻量级的轮子。
+
+想给项目起一个简单易记的名字,类似于 Eureka、Nacos、Redis;后和朋友商量,决定命名:**Hippo4J**。
+
+
+
+## 它解决了什么问题
+
+线程池在业务系统应该都有使用到,帮助业务流程提升效率以及管理线程,多数场景应用于大量的异步任务处理。
+
+虽然线程池提供了我们许多便利,但也并非尽善尽美,比如下面这些问题就无法很好解决。
+
+- 线程池随便定义,线程资源过多,造成服务器高负载。
+
+- 线程池参数不易评估,随着业务的并发提升,业务面临出现故障的风险。
+
+- 线程池任务执行时间超过平均执行周期,开发人员无法感知。
+
+- 线程池任务堆积,触发拒绝策略,影响既有业务正常运行。
+
+- 当业务出现超时、熔断等问题时,因为没有监控,无法确定是不是线程池引起。
+
+- 原生线程池不支持运行时变量的传递,比如 MDC 上下文遇到线程池就 GG。
+
+- 无法执行优雅关闭,当项目关闭时,大量正在运行的线程池任务被丢弃。
+
+- 线程池运行中,任务执行停止,怀疑发生死锁或执行耗时操作,但是无从下手。
+
+Hippo4J 很好解决了这些问题,它将业务中所有线程池统一管理,增强原生线程池系列功能。
+
+## 它有什么特性
+
+应用系统中线程池并不容易管理。参考美团的设计,Hippo4J 按照租户、项目、线程池的维度划分。再加上系统权限,让不同的开发、管理人员负责自己系统的线程池操作。
+
+举个例子,小编在一家公司的公共组件团队,团队中负责消息、短链接网关等项目。公共组件是租户,消息或短链接就是项目。
+
+Hippo4J 除去动态修改线程池,还包含实时查看线程池运行时指标、负载报警、配置日志管理等。
+
+- `hippo4j-adapter`:适配对第三方框架中的线程池进行监控,如 Dubbo、RocketMQ、Hystrix 等;
+- `hippo4j-auth`:用户、角色、权限等;
+- `hippo4j-common`:多个模块公用代码实现;
+- `hippo4j-config`:提供线程池准实时参数更新功能;
+- `hippo4j-console`:对接前端控制台;
+- `hippo4j-core`:核心的依赖,包括配置、核心包装类等;
+- `hippo4j-discovery`:提供线程池项目实例注册、续约、下线等功能;
+- `hippo4j-example` :示例工程;
+- `hippo4j-message` :配置变更以及报警通知发送;
+- `hippo4j-monitor` :线程池运行时监控;
+- `hippo4j-server` :Server 端发布需要的模块聚合;
+- `hippo4j-spring-boot`:SpringBoot Starter。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/user_guide/framework.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/user_guide/framework.md
new file mode 100644
index 00000000..226ddf61
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/user_guide/framework.md
@@ -0,0 +1,51 @@
+---
+sidebar_position: 2
+---
+
+# 架构设计
+
+简单来说,Hippo4J 从部署的角度上分为两种角色:Server 端和 Client 端。
+
+Server 端是 Hippo4J 项目打包出的 Java 进程,功能包括用户权限、线程池监控以及执行持久化的动作。
+
+Client 端指的是我们 SpringBoot 应用,通过引入 Hippo4J Starter Jar 包负责与 Server 端进行交互。
+
+比如拉取 Server 端线程池数据、动态更新线程池配置以及采集上报线程池运行时数据等。
+
+## 基础组件
+
+### 配置中心(Config)
+
+配置中心位于 Server 端,它的主要作用是监控 Server 端线程池配置变更,实时通知到 Client 实例执行线程池变更流程。
+
+代码设计基于 Nacos 1.x 版本的 **长轮询以及异步 Servlet 机制** 实现。
+
+### 注册中心(Discovery)
+
+负责管理 Client 端(单机或集群)注册到 Server 端的实例,包括不限于**实例注册、续约、过期剔除** 等操作,代码基于 Eureka 源码实现。
+
+上面的配置中心很容易理解,动态线程池参数变更的根本。但是注册中心是用来做什么的?
+
+注册中心管理 Client 端注册的实例,通过这些实例可以 **实时获取线程池的运行时参数信息**。
+
+目前的设计是如此,不排除后续基于 Discovery 做更多的扩展。
+
+### 控制台(Console)
+
+对接前端项目,包括不限于以下模块管理:
+
+
+
+## 消息通知(Notify)
+
+Hippo4J 内置了很多需要通知的事件,比如:线程池参数变更通知、线程池活跃度报警、拒绝策略执行报警以及阻塞队列容量报警等。
+
+目前 Notify 已经接入了钉钉、企业微信和飞书,后续持续集成邮件、短信等通知渠道;并且,Notify 模块提供了消息事件的 SPI 方案,可以接受三方自定义的推送。
+
+## Hippo4j-Spring-Boot-Starter
+
+熟悉 SpringBoot 的小伙伴对 Starter 应该不会陌生。Hippo4J 提供以 Starter Jar 包的形式嵌套在应用内,负责与 Server 端完成交互。
+
+## 功能架构
+
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/user_guide/notify.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/user_guide/notify.md
new file mode 100644
index 00000000..216840e9
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/user_guide/notify.md
@@ -0,0 +1,71 @@
+---
+sidebar_position: 4
+---
+
+# 通知报警
+
+现阶段已集成钉钉、企业微信、飞书的消息推送,后续会持续接入邮箱、短信和自定义通知渠道。
+
+
+
+**通知平台**
+
+- DING:钉钉平台;
+
+- LARK:飞书平台;
+
+- WECHAT:企业微信。
+
+**通知类型**
+
+- CONFIG:线程池配置变更推送;
+
+- ALARM:线程池运行报警推送。
+
+**Token**
+
+获取 DING、LARK、WECHAT 机器人 Token。
+
+**报警间隔**
+
+- CONFIG 类型通知没有报警间隔;
+
+- ALARM 类型设置报警间隔后,某一节点下的同一线程池指定间隔只会发送一次报警通知。
+
+**接收者**
+
+```tex
+多个接收者使用英文逗号 , 分割 (注意不要有空格)
+DING:填写手机号
+WECHART:填写user_id会以@的消息发给用户,填写姓名则是普通的@,如:龙台
+LARK:填写ou_开头用户唯一标识会以@的消息发给用户,填写手机号则是普通的@
+```
+
+
+## 钉钉平台
+
+[钉钉创建群机器人](https://www.dingtalk.com/qidian/help-detail-20781541.html)
+
+| 配置变更 | 报警通知 |
+| :---: | :---: |
+|  |  |
+
+添加钉钉机器人后,需在机器人配置自定义关键字,才可发送成功。如下所示:
+
+
+
+## 企业微信
+
+[企业微信创建群机器人](https://open.work.weixin.qq.com/help2/pc/14931?person_id=1&from=homesearch)
+
+| 配置变更 | 报警通知 |
+| :---: | :---: |
+|  |  |
+
+## 飞书平台
+
+[飞书创建群机器人](https://www.feishu.cn/hc/zh-CN/articles/360024984973)
+
+
+
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/user_guide/quick-start.md b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/user_guide/quick-start.md
new file mode 100644
index 00000000..cce9e577
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-docs/version-1.4.2/user_docs/user_guide/quick-start.md
@@ -0,0 +1,40 @@
+---
+sidebar_position: 3
+---
+
+# 快速开始
+
+## 服务启动
+
+使用 Docker 运行服务端,默认使用内置 H2 数据库,数据持久化到 Docker 容器存储卷中。
+
+```shell
+docker run -d -p 6691:6691 --name hippo4j-server hippo4j/hippo4j-server
+```
+
+> 如果没有 Docker,可以使用源码编译的方式,启动 [Hippo4J-Server/Hippo4J-Bootstrap](https://github.com/longtai-cn/hippo4j/tree/develop/hippo4j-server/hippo4j-bootstrap) 模块下 ServerApplication 应用类。
+
+启动示例项目,[hippo4j-spring-boot-starter-example](https://github.com/opengoofy/hippo4j/tree/develop/hippo4j-example/hippo4j-spring-boot-starter-example) 模块下 Hippo4JServerExampleApplication 应用类。
+
+访问 Server 控制台,路径 `http://localhost:6691/index.html`,默认用户名密码:admin / 123456
+
+## 配置变更
+
+访问控制台动态线程池菜单下线程池实例,修改动态线程池相关参数。
+
+
+
+观察 Hippo4j-Example 控制台日志输出,日志输出包括不限于此信息即为成功。
+
+```tex
+2022-09-10 00:23:29.783 INFO 50322 --- [change.config_0] c.h.s.s.c.ServerThreadPoolDynamicRefresh : [message-consume] Dynamic thread pool change parameter.
+ corePoolSize: 2 => 4
+ maximumPoolSize: 6 => 12
+ capacity: 1024 => 2048
+ keepAliveTime: 9999 => 9999
+ executeTimeOut: 800 => 3000
+ rejectedType: SyncPutQueuePolicy => RunsOldestTaskPolicy
+ allowCoreThreadTimeOut: true => true
+```
+
+另外,当 Client 集群部署时,可以修改某一个实例,或选择 `全部修改` 按钮,修改所有实例线程池信息。
diff --git a/docs/i18n/zh/docusaurus-plugin-content-pages/markdown-page.md b/docs/i18n/zh/docusaurus-plugin-content-pages/markdown-page.md
new file mode 100644
index 00000000..9756c5b6
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-plugin-content-pages/markdown-page.md
@@ -0,0 +1,7 @@
+---
+title: Markdown page example
+---
+
+# Markdown page example
+
+You don't need React to write simple standalone pages.
diff --git a/docs/i18n/zh/docusaurus-theme-classic/footer.json b/docs/i18n/zh/docusaurus-theme-classic/footer.json
new file mode 100644
index 00000000..781b05cb
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-theme-classic/footer.json
@@ -0,0 +1,42 @@
+{
+ "link.title.Docs": {
+ "message": "Docs",
+ "description": "The title of the footer links column with title=Docs in the footer"
+ },
+ "link.title.Community": {
+ "message": "Community",
+ "description": "The title of the footer links column with title=Community in the footer"
+ },
+ "link.title.More": {
+ "message": "More",
+ "description": "The title of the footer links column with title=More in the footer"
+ },
+ "link.item.label.简介": {
+ "message": "简介",
+ "description": "The label of footer link with label=简介 linking to /docs/user_docs/intro"
+ },
+ "link.item.label.加群沟通": {
+ "message": "加群沟通",
+ "description": "The label of footer link with label=加群沟通 linking to https://hippo4j.cn/docs/user_docs/other/group"
+ },
+ "link.item.label.微信公众号": {
+ "message": "微信公众号",
+ "description": "The label of footer link with label=微信公众号 linking to https://mp.weixin.qq.com/s/diVHYvwiuYH9aWpZDPc27g"
+ },
+ "link.item.label.Gitee": {
+ "message": "Gitee",
+ "description": "The label of footer link with label=Gitee linking to https://gitee.com/itmachen/hippo4j"
+ },
+ "link.item.label.GitHub": {
+ "message": "GitHub",
+ "description": "The label of footer link with label=GitHub linking to https://github.com/opengoofy/hippo4j"
+ },
+ "link.item.label.公司登记": {
+ "message": "公司登记",
+ "description": "The label of footer link with label=公司登记 linking to https://github.com/opengoofy/hippo4j/issues/13"
+ },
+ "copyright": {
+ "message": "Copyright © 2021-2022 小马哥版权所有 京ICP备2021038095号-2\n",
+ "description": "The footer copyright"
+ }
+}
diff --git a/docs/i18n/zh/docusaurus-theme-classic/navbar.json b/docs/i18n/zh/docusaurus-theme-classic/navbar.json
new file mode 100644
index 00000000..3e38678a
--- /dev/null
+++ b/docs/i18n/zh/docusaurus-theme-classic/navbar.json
@@ -0,0 +1,22 @@
+{
+ "title": {
+ "message": "",
+ "description": "The title in the navbar"
+ },
+ "item.label.文档": {
+ "message": "文档",
+ "description": "Navbar item with label 文档"
+ },
+ "item.label.社区": {
+ "message": "社区",
+ "description": "Navbar item with label 社区"
+ },
+ "item.label.控制台样例": {
+ "message": "控制台样例",
+ "description": "Navbar item with label 控制台样例"
+ },
+ "item.label.🥇代码实战课": {
+ "message": "🥇代码实战课",
+ "description": "Navbar item with label 🥇代码实战课"
+ }
+}
diff --git a/docs/src/components/HomepageFeatures/index.js b/docs/src/components/HomepageFeatures/index.js
index 59e97a95..10b5d288 100644
--- a/docs/src/components/HomepageFeatures/index.js
+++ b/docs/src/components/HomepageFeatures/index.js
@@ -8,7 +8,7 @@ const FeatureList = [
Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default,
description: (
<>
- 应用运行时动态变更线程池参数,包括不限于核心、最大线程、阻塞队列大小和拒绝策略等;支持应用集群线程池配置差异化
+ 应用运行时动态变更线程池参数,包括不限于核心、最大线程、阻塞队列大小和拒绝策略等,支持应用集群下不同节点线程池配置差异化
>
),
},
@@ -26,7 +26,7 @@ const FeatureList = [
Svg: require('@site/static/img/undraw_docusaurus_react.svg').default,
description: (
<>
- 支持自定义时长的线程池运行数据采集存储,并提供可视化大屏监控运行指标;同时也支持 Prometheus 采集监控,帮助排查以及确定线程池问题
+ 支持自定义时长线程池运行数据采集存储,同时也支持 Prometheus、InfluxDB 等采集监控,通过 Grafana 或内置监控页面提供可视化大屏监控运行指标
>
),
},
diff --git a/docs/src/pages/index.js b/docs/src/pages/index.js
index 557e5928..a1bdfacc 100644
--- a/docs/src/pages/index.js
+++ b/docs/src/pages/index.js
@@ -1,6 +1,7 @@
import React from 'react';
import clsx from 'clsx';
import Link from '@docusaurus/Link';
+import Translate from '@docusaurus/Translate';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import Layout from '@theme/Layout';
import HomepageFeatures from '@site/src/components/HomepageFeatures';
diff --git a/docs/static/img/hippo4j.png b/docs/static/img/hippo4j.png
new file mode 100644
index 00000000..66ab4b25
Binary files /dev/null and b/docs/static/img/hippo4j.png differ
diff --git a/docs/static/img/web.png b/docs/static/img/web.png
deleted file mode 100644
index 6c9d3b00..00000000
Binary files a/docs/static/img/web.png and /dev/null differ
diff --git a/docs/versioned_docs/version-1.4.2/community/_category_.json b/docs/versioned_docs/version-1.4.2/community/_category_.json
new file mode 100644
index 00000000..bcd256c9
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/community/_category_.json
@@ -0,0 +1,7 @@
+{
+ "label": "社区",
+ "position": 1,
+ "link": {
+ "type": "generated-index"
+ }
+}
diff --git a/docs/versioned_docs/version-1.4.2/community/contributor.md b/docs/versioned_docs/version-1.4.2/community/contributor.md
new file mode 100644
index 00000000..f0185ad3
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/community/contributor.md
@@ -0,0 +1,24 @@
+---
+sidebar_position: 1
+---
+
+# 贡献指南
+
+Git Commit Log 尽量使用英文。
+
+Pull Request 尽量保持单一,不同语义的代码贡献应拆分多个 Pull Request。
+
+为了让您的 GitHub ID 显示在 Contributor 列表中,别忘了以下设置:
+
+```shell
+git config --global user.name "username"
+git config --global user.email "GitHub 账号邮箱"
+```
+
+## 贡献者列表
+
+您可以在 [Hippo4J](https://github.com/opengoofy/hippo4j/graphs/contributors) 和 [Hippo4J Console](https://github.com/opengoofy/hippo4j-console) 的贡献列表中找到全部的贡献者名单。
+
+
+
+
diff --git a/docs/versioned_docs/version-1.4.2/community/dev_convention/_category_.json b/docs/versioned_docs/version-1.4.2/community/dev_convention/_category_.json
new file mode 100644
index 00000000..cb875453
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/community/dev_convention/_category_.json
@@ -0,0 +1,7 @@
+{
+ "label": "贡献规约",
+ "position": 2,
+ "link": {
+ "type": "generated-index"
+ }
+}
diff --git a/docs/versioned_docs/version-1.4.2/community/dev_convention/code.md b/docs/versioned_docs/version-1.4.2/community/dev_convention/code.md
new file mode 100644
index 00000000..f91acdbe
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/community/dev_convention/code.md
@@ -0,0 +1,8 @@
+---
+sidebar_position: 2
+---
+
+# 代码规约
+
+1. 代码提交前,执行 `mvn spotless:apply` 保证代码格式符合规范。
+2. 代码中不要出现无意义的空行。
diff --git a/docs/versioned_docs/version-1.4.2/community/dev_convention/document.md b/docs/versioned_docs/version-1.4.2/community/dev_convention/document.md
new file mode 100644
index 00000000..923ad81d
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/community/dev_convention/document.md
@@ -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 Gbps,SSD 一共有 20 TB。
+
+錯誤:
+
+> 我家的光纖入屋寬頻有 10Gbps,SSD 一共有 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 元。
+
+錯誤:
+
+> 這件蛋糕只賣 1000 元。
+
+例外:在設計稿、宣傳海報中如出現極少量數字的情形時,為方便文字對齊,是可以使用全形數字的。
+
+### 遇到完整的英文整句、特殊名詞,其內容使用半形標點
+
+正確:
+
+> 賈伯斯那句話是怎麼說的?「Stay hungry, stay foolish.」
+
+> 推薦你閱讀《Hackers & Painters: Big Ideas from the Computer Age》,非常的有趣。
+
+錯誤:
+
+> 賈伯斯那句話是怎麼說的?「Stay hungry,stay foolish。」
+
+> 推薦你閱讀《Hackers&Painters:Big 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](#) 並分配给相關同事。
+
+> 訪問我們網站的最新動態,請[點擊這裡](#)進行訂閱!
+
+### 簡體中文使用直角引號
+
+用法:
+
+> 「老师,『有条不紊』的『紊』是什么意思?」
+
+對比用法:
+
+> “老师,‘有条不紊’的‘紊’是什么意思?”
diff --git a/docs/versioned_docs/version-1.4.2/community/developer.md b/docs/versioned_docs/version-1.4.2/community/developer.md
new file mode 100644
index 00000000..03cdd4e3
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/community/developer.md
@@ -0,0 +1,82 @@
+---
+sidebar_position: 2
+---
+
+# 核心开发者
+
+
+
+## 成为核心开发者
+
+持续对 Hippo-4J 进行贡献, 粗略评估,完成 10 次 PR 贡献即可成为核心开发者。 其中包括完成 2 个 [good pro issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+pro+issue%22) 或以上,以及 若干个 [good first issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)。
+
+:::note
+会根据 PR 质量提供个性化评估,有可能一个或两个质量较高 PR 即可成为核心开发者。参考:[重构 DynamicThreadPoolExecutor 功能扩展逻辑](https://github.com/opengoofy/hippo4j/pull/854)
+:::
+
+成为核心开发者后,会为该 GitHub 账号获取 Jetbrains 全家桶 Licenses,有效期为 1 年。不用再为破解而烦恼,感受随时升级的快乐。
+
+:::note
+距离到期两周前,会再次申请 Jetbrains Licenses。有点类似于无限续约的感觉,在此感谢 Jetbrains 公司对开源的支持。
+:::
+
+截至 `2022-10-30` 当天,已为登记的 7 位核心开发者成功申请 Licenses。
+
+
diff --git a/docs/versioned_docs/version-1.4.2/community/powered-by.md b/docs/versioned_docs/version-1.4.2/community/powered-by.md
new file mode 100644
index 00000000..635d9011
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/community/powered-by.md
@@ -0,0 +1,37 @@
+---
+sidebar_position: 3
+---
+
+# 采用公司
+
+## 登记
+
+欢迎采用了 Hippo4J 的公司在此登记,非常感谢大家对 Hippo4J 的关注和支持,这是我们前进最大的动力。
+
+请按公司名 + 首页的格式在 [此处](https://github.com/opengoofy/hippo4j/issues/13) 登记。
+
+## 谁在使用 Hippo4J
+
+共计 21+ 家公司生产接入 Hippo4J。按照公司登记时间排序。
+
+- [身边云](https://serviceshare.com)
+- [Medbanks](https://www.medbanks.cn)
+- [北京智合联创科技有限公司](http://www.zhlc.com.cn)
+- [神州数码](http://www.digitalchina.com)
+- [payermax](https://www.payermax.com/)
+- [轻松到家](http://www.uyess.com/index.html)
+- [某商业银行股份有限公司](https://github.com/opengoofy/hippo4j/issues/13)
+- [某国际物流信息股份有限公司](https://github.com/opengoofy/hippo4j/issues/13)
+- [萨科(深圳)科技有限公司](https://www.lbdj.com/)
+- [广东天枢新能源科技有限公司](https://gd-tianshu.com/)
+- [FitTime](http://fittime.com/)
+- [百强国际物流](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/)
+- [远眺网络科技有限公司](https://www.yuantiaokj.com/)
+- [浙江吉利控股集团有限公司](https://www.geely.com/)
+- [三立人(深圳)科技有限公司-焦内](https://www.bananain.com/)
diff --git a/docs/versioned_docs/version-1.4.2/community/sponsor.md b/docs/versioned_docs/version-1.4.2/community/sponsor.md
new file mode 100644
index 00000000..c73fc64a
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/community/sponsor.md
@@ -0,0 +1,23 @@
+---
+sidebar_position: 4
+---
+
+# 支持开源
+
+如果您正在使用这个项目并感觉良好,或者是想支持我继续开发,通过以下二维码一次性捐款。
+
+在这里承诺将,将收到的所有赞助支持资金完全公开化,且后续资金用途仅 Hippo-4J 项目的运转。
+
+
+
+感谢给予支持的朋友,您的支持是 Hippo-4J 社区前进的动力 🎉
+
+| | ID | 赞赏金额 | 时间 | 备注 |
+|-----|--|-------|------------|--------------------|
+| 1 | 六月飞雪 | 30.00 | 2021-12-30 | 代码设计很优雅的一款框架,继续加油! |
+| 2 | 孙大圣 | 26.6 | 2022-03-23 | 学习一下😁😁 |
+| 3 | Easy 点 | 66.00 | 2022-04-09 | 好货好技术当加赏 |
+| 4 | 捷克 | 30.00 | 2022-05-21 | 非常不错的框架,点赞 |
+| 5 | 吃猫的饼干 | 88.00 | 2022-08-21 | 👍 |
+| 6 | 不忘初心· | 66.00 | 2022-10-28 | Nice! |
+| 7 | 时刻· | 6.00 | 2022-10-30 | -! |
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/dev_manual/_category_.json b/docs/versioned_docs/version-1.4.2/user_docs/dev_manual/_category_.json
new file mode 100644
index 00000000..11f12432
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/dev_manual/_category_.json
@@ -0,0 +1,8 @@
+{
+ "label": "开发者手册",
+ "position": 5,
+ "link": {
+ "type": "generated-index",
+ "description": "Hippo4J 留给使用者能够扩展的知识点。"
+ }
+}
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/dev_manual/rejected-policy-custom.md b/docs/versioned_docs/version-1.4.2/user_docs/dev_manual/rejected-policy-custom.md
new file mode 100644
index 00000000..1f2cf694
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/dev_manual/rejected-policy-custom.md
@@ -0,0 +1,57 @@
+---
+sidebar_position: 1
+---
+
+# 拒绝策略自定义
+
+Hippo4J 通过 SPI 的方式对拒绝策略进行扩展,可以让用户在 Hippo4J 中完成自定义拒绝策略实现。
+
+## Hippo4J Server 拒绝策略扩展
+
+自定义拒绝策略,实现 `CustomRejectedExecutionHandler` 接口,示例如下:
+
+```java
+public class ErrorLogRejectedExecutionHandler implements CustomRejectedExecutionHandler {
+
+ @Override
+ public Integer getType() {
+ return 12;
+ }
+
+ @Override
+ public RejectedExecutionHandler generateRejected() {
+ return new CustomErrorLogRejectedExecutionHandler();
+ }
+
+ public static class CustomErrorLogRejectedExecutionHandler implements RejectedExecutionHandler {
+
+ @Override
+ public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
+ Logger logger = LoggerFactory.getLogger(this.getClass());
+ logger.error("线程池抛出拒绝策略");
+ }
+ }
+}
+```
+
+创建 `src/main/resources/META-INF/services` 目录,创建 SPI 自定义拒绝策略文件 `cn.hippo4j.common.executor.support.CustomRejectedExecutionHandler`。
+
+`cn.hippo4j.common.executor.support.CustomRejectedExecutionHandler` 文件内仅放一行自定义拒绝策略全限定名即可,示例:
+
+```text
+cn.hippo4j.example.core.handler.ErrorLogRejectedExecutionHandler
+```
+
+创建、修改线程池页面选择 `CustomRejectedPolicy(自定义 SPI 策略)`。
+
+
+
+拒绝策略触发时,完成上述代码效果,仅打印异常日志提示。
+
+```text
+2022-08-01 21:27:49.515 ERROR 48928 --- [ateHandler.test] r$CustomErrorLogRejectedExecutionHandler : 线程池抛出拒绝策略
+```
+
+:::note
+具体参考 `hippo4j-example/hippo4j-spring-boot-starter-example` 模块。
+:::
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/dev_manual/rejected-policy-info.md b/docs/versioned_docs/version-1.4.2/user_docs/dev_manual/rejected-policy-info.md
new file mode 100644
index 00000000..d5c68138
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/dev_manual/rejected-policy-info.md
@@ -0,0 +1,50 @@
+---
+sidebar_position: 0
+---
+
+# 内置拒绝策略
+
+内置两种拒绝策略说明:
+
+**RunsOldestTaskPolicy**:添加新任务并由主线程运行最早的任务。
+
+```java
+public class RunsOldestTaskPolicy implements RejectedExecutionHandler {
+
+ @Override
+ public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
+ if (executor.isShutdown()) {
+ return;
+ }
+ BlockingQueue workQueue = executor.getQueue();
+ Runnable firstWork = workQueue.poll();
+ boolean newTaskAdd = workQueue.offer(r);
+ if (firstWork != null) {
+ firstWork.run();
+ }
+ if (!newTaskAdd) {
+ executor.execute(r);
+ }
+ }
+}
+```
+
+**SyncPutQueuePolicy**:主线程把拒绝任务以阻塞的方式添加到队列。
+
+```java
+@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);
+ }
+ }
+}
+```
\ No newline at end of file
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/getting_started/_category_.json b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/_category_.json
new file mode 100644
index 00000000..72b1e151
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/_category_.json
@@ -0,0 +1,7 @@
+{
+ "label": "快速开始",
+ "position": 3,
+ "link": {
+ "type": "generated-index"
+ }
+}
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/getting_started/config/_category_.json b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/config/_category_.json
new file mode 100644
index 00000000..78b3d9c4
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/config/_category_.json
@@ -0,0 +1,5 @@
+{
+ "label": "依赖配置中心",
+ "position": 2,
+ "collapsed": true
+}
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-default.md b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-default.md
new file mode 100644
index 00000000..9c9e0fc9
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-default.md
@@ -0,0 +1,45 @@
+---
+sidebar_position: 4
+---
+
+# 参数默认配置
+
+曾有多名小伙伴反馈说,项目中线程池一多,配置文件中配置就显得很臃肿。为此 hippo4j-config 开发出了动态线程池默认配置。
+
+```yaml
+spring:
+ dynamic:
+ thread-pool:
+ default-executor:
+ core-pool-size: 4
+ maximum-pool-size: 6
+ blocking-queue: ResizableCapacityLinkedBlockingQueue
+ queue-capacity: 1024
+ execute-time-out: 1000
+ keep-alive-time: 9999
+ rejected-handler: AbortPolicy
+ active-alarm: 90
+ capacity-alarm: 85
+ alarm: true
+ allow-core-thread-time-out: true
+ notify:
+ interval: 5
+ receives: chen.ma
+ executors:
+ - thread-pool-id: message-produce
+ - thread-pool-id: message-consume
+ core-pool-size: 80
+ maximum-pool-size: 100
+ execute-time-out: 1000
+ notify:
+ interval: 6
+ receives: chen.ma
+```
+
+`spring.dynamic.thread-pool.executors` 层级下,仅需要配置 `thread-pool-id`,其余配置从 `spring.dynamic.thread-pool.default-executor` 读取。
+
+如果 `spring.dynamic.thread-pool.executors` 下配置和 `spring.dynamic.thread-pool.default-executor` 冲突,以前者为主。
+
+通过该自定义配置方式,可减少大量重复线程池参数配置项,提高核心配置简洁度。
+
+提示:`spring.dynamic.thread-pool.default-executor` 层级下参数,不提供动态刷新功能。
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-monitor.md b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-monitor.md
new file mode 100644
index 00000000..72528638
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-monitor.md
@@ -0,0 +1,117 @@
+---
+sidebar_position: 3
+---
+
+# 线程池监控
+
+## 线程池监控配置
+
+监控前置条件:需要先完成 hippo4j-config 的 [接入工作](/docs/user_docs/getting_started/config/hippo4j-config-start)。
+
+接下来引入 SpringBoot Actuator。Spring 2.x 一般都有版本指定,所以这里不用写版本号。
+
+```xml
+
+ io.micrometer
+ micrometer-registry-prometheus
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+```
+
+添加动态线程池监控相关配置:
+
+```yaml
+management:
+ metrics:
+ export:
+ prometheus:
+ enabled: true
+ server:
+ port: 29999 # 可选配置,如果不配置该 port,直接使用 ${server.port}
+ endpoints:
+ web:
+ exposure:
+ include: '*' # 测试使用,开启了所有端点,生产环境不建议 *
+spring:
+ dynamic:
+ thread-pool:
+ collect-type: micrometer
+```
+
+项目启动,访问 `http://localhost:29999/actuator/prometheus` 出现 `dynamic_thread_pool_` 前缀的指标,即为成功。
+
+
+
+## 配置 Prometheus
+
+通过 Docker 启动 Prometheus 服务。
+
+```shell
+docker run -d -p 9090:9090 --name prometheus prom/prometheus
+```
+
+添加 Prometheus 抽取数据任务。
+
+```shell
+# 进入 prometheus 容器内部
+docker exec -it prometheus /bin/sh
+# 编辑 prometheus 配置文件
+vi /etc/prometheus/prometheus.yml
+```
+
+scrape_configs 节点下新添加一个 job,如果 Prometheus 是 Docker 方式部署,`{scrape_configs.static_configs.targets}` 需要写本机的 IP。
+
+```yaml
+scrape_configs:
+ - job_name: 'dynamic-thread-pool-job'
+ scrape_interval: 5s
+ metrics_path: '/actuator/prometheus'
+ static_configs:
+ - targets: [ '127.0.0.1:29999' ]
+```
+
+配置成功后 `exit` 退出容器,并进行 Prometheus 容器重启 `docker restart prometheus`。
+
+访问 Prometheus 控制台 `http://localhost:9090/graph` 路径,能够展示相关指标即为配置成功。
+
+
+
+## 配置 Grafana
+
+```shell
+docker run -d -p 3000:3000 --name=grafana grafana/grafana
+```
+
+访问 Grafana 地址,[http://localhost:3000](http://localhost:3000) 用户名密码:`admin`
+
+Grafana 访问 `http://localhost:3000/datasources` 导入 Prometheus 数据源。
+
+
+
+> 如果 Prometheus 为 Docker 方式部署,HTTP URL 需要为本地 IP,比如:http://192.168.1.5:9090
+
+关注公众号 `龙台的技术笔记`,回复:`监控`,获取 Hippo4J Grafana DashBoard JSON 配置。
+
+| 公众号 | 回复关键词 |
+|:------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------------------------------:|
+|  |  |
+
+获取到 JSON 文件后,通过 `http://localhost:3000/dashboard/import` 将 JSON 文件导入至 Grafana DashBoard。
+
+
+
+下拉框内动态选择创建好的 Prometheus 数据源,并点击 `Import`。
+
+
+
+即可使用炫酷的 Hippo-4J 动态线程池监控 DashBoard。大家伙儿也可以根据个人喜好进行定制 DashBoard,如果觉得有优化点,欢迎和我联系贡献。
+
+
+
+如果项目客户端启动多个示例,动态线程池监控效果图如下:
+
+
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-more.md b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-more.md
new file mode 100644
index 00000000..2511b4f3
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-more.md
@@ -0,0 +1,80 @@
+---
+sidebar_position: 3
+---
+
+# 个性化配置
+
+以下所述特性自 hippo4j-config v1.4.2 及以上版本提供,由 hippo4j 核心开发者 [@pizihao](https://github.com/pizihao) 完成相应功能开发。
+
+## 需求背景
+
+**1)容器及三方框架线程池自定义启用**
+
+最初设计容器线程池和三方框架线程池的动态变更是和启动无关的。也就是说,启动时不会根据配置文件中相关参数去修改两者对应的线程池配置。
+
+这么设计的初衷是因为,不想让 hippo4j 过多的去介入框架原有的功能。因为容器和三方框架都支持线程池参数的自定义。
+
+也就造成,可能你在配置中心配置了对应的容器和三方框架线程池参数,启动时是无效的。但当修改配置文件任一配置,容器和三方框架线程池配置将生效。
+
+为了更好的用户体验,决定加入启用标识来控制:是否在项目初始化启动时,对容器和三方框架线程池参数进行修改。
+
+**2)客户端集群个性化配置**
+
+大家都知道,hippo4j-config 是依赖配置中心做线程池配置动态变更。这种模式有一种缺点:改动配置文件后,所有客户端都会变更。
+
+有些小伙伴希望 hippo4j-config 能够像 hippo4j-server 一样,能够针对单独的客户端进行配置变更。
+
+## 容器及三方框架线程池自定义启用
+
+容器及三方框架线程池添加启用配置,为了保持统一,动态线程池配置中也有该参数配置。配置项默认开启。
+
+```yaml
+spring:
+ dynamic:
+ thread-pool:
+ tomcat:
+ enable: true
+ executors:
+ - thread-pool-id: message-consume
+ enable: false
+ adapter-executors:
+ - threadPoolKey: 'input'
+ enable: true
+```
+
+## 客户端集群个性化配置
+
+分别在动态线程池、容器线程池以及三方框架线程池配置下增加 `nodes` 配置节点,通过该配置可匹配需要变更的节点。
+
+```yaml
+spring:
+ dynamic:
+ thread-pool:
+ tomcat:
+ nodes: 192.168.1.5:*,192.168.1.6:8080
+ executors:
+ - thread-pool-id: message-consume
+ nodes: 192.168.1.5:*
+ adapter-executors:
+ - threadPoolKey: 'input'
+ nodes: 192.168.1.5:*
+```
+
+来一段代码方法中的注释,大家就基本明白如何使用了。
+
+```java
+/**
+ * Matching nodes
+ * nodes is ip + port.Get 'nodes' in the new Properties,Compare this with the ip + port of Application.
+ * support prefix pattern matching. e.g:
+ *
+ * - 192.168.1.5:* -- Matches all ports of 192.168.1.5
+ * - 192.168.1.*:2009 -- Matches 2009 port of 192.168.1.*
+ * - * -- all
+ * - empty -- all
+ *
+ * The format of ip + port is ip : port.
+ */
+```
+
+`nodes` 可与 `enable` 同时使用。如此,基于配置中心的动态线程池实现方式,将能够更方便的支持个性化需求。
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-springboot1x-adapter.md b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-springboot1x-adapter.md
new file mode 100644
index 00000000..693dd341
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-springboot1x-adapter.md
@@ -0,0 +1,121 @@
+---
+sidebar_position: 5
+---
+
+# 适配SpringBoot1x
+
+目前已支持 Nacos、Apollo 配置中心适配 SpringBoot 1.5.x 版本。
+
+```xml
+
+ cn.hippo4j
+ hippo4j-config-spring-boot-1x-starter
+ 1.4.2
+
+```
+
+Nacos SpringBoot 配置如下:
+
+```yaml
+spring:
+ cloud:
+ nacos:
+ config:
+ ext-config:
+ - data-id: hippo4j-nacos.yaml
+ group: DEFAULT_GROUP
+ refresh: true
+ server-addr: 127.0.0.1:8848
+ dynamic:
+ thread-pool:
+ config-file-type: yml
+ nacos:
+ data-id: hippo4j-nacos.yaml
+ group: DEFAULT_GROUP
+```
+
+Apollo SpringBoot 配置如下:
+
+```yaml
+apollo:
+ autoUpdateInjectedSpringProperties: true
+ bootstrap:
+ eagerLoad:
+ enabled: true
+ enabled: true
+ namespaces: application
+ meta: http://127.0.0.1:8080
+app:
+ id: dynamic-threadpool-example
+spring:
+ dynamic:
+ thread-pool:
+ apollo:
+ namespace: application
+```
+
+动态线程池通用配置如下:
+
+```yaml
+management:
+ context-path: /actuator
+ security:
+ enabled: false
+server:
+ port: 8091
+ servlet:
+ context-path: /example
+spring:
+ application:
+ name: dynamic-threadpool-example
+ dynamic:
+ thread-pool:
+ banner: true
+ check-state-interval: 5
+ collect-type: micrometer
+ config-file-type: properties
+ enable: true
+ executors:
+ - active-alarm: 80
+ alarm: true
+ allow-core-thread-time-out: true
+ blocking-queue: LinkedBlockingQueue
+ capacity-alarm: 80
+ core-pool-size: 1
+ execute-time-out: 1000
+ keep-alive-time: 6691
+ maximum-pool-size: 1
+ notify:
+ interval: 8
+ receives: chen.ma
+ queue-capacity: 1
+ rejected-handler: AbortPolicy
+ thread-name-prefix: message-consume
+ thread-pool-id: message-consume
+ - active-alarm: 80
+ alarm: true
+ allow-core-thread-time-out: true
+ blocking-queue: LinkedBlockingQueue
+ capacity-alarm: 80
+ core-pool-size: 1
+ execute-time-out: 1000
+ keep-alive-time: 6691
+ maximum-pool-size: 1
+ notify:
+ interval: 8
+ receives: chen.ma
+ queue-capacity: 1
+ rejected-handler: AbortPolicy
+ thread-name-prefix: message-produce
+ thread-pool-id: message-produce
+ notify-platforms:
+ - platform: WECHAT
+ token: ac0426a5-c712-474c-9bff-72b8b8f5caff
+ profiles:
+ active: dev
+```
+
+具体 Demo 运行请参考以下示例模块,已验证对应线程池动态变更、报警以及运行时监控功能。
+
+- `/hippo4j-config-nacos-spring-boot-1x-starter-example`
+- `hippo4j-example/hippo4j-config-apollo-spring-boot-1x-starter-example`
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-start.md b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-start.md
new file mode 100644
index 00000000..33f658c2
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/config/hippo4j-config-start.md
@@ -0,0 +1,193 @@
+---
+sidebar_position: 1
+---
+
+# 接入流程
+
+Nacos、Apollo、Zookeeper、ETCD、Polaris 配置中心任选其一。
+
+## hippo4j 配置
+
+```xml
+
+ cn.hippo4j
+ hippo4j-config-spring-boot-starter
+ 1.4.2
+
+```
+
+启动类上添加注解 `@EnableDynamicThreadPool`。
+
+```java
+@SpringBootApplication
+@EnableDynamicThreadPool
+public class ExampleApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(ExampleApplication.class, args);
+ }
+}
+```
+
+SpringBoot 应用配置文件添加:
+
+```yaml
+server:
+ port: 8090
+ servlet:
+ context-path: /example
+
+spring:
+ profiles:
+ active: dev
+
+ dynamic:
+ thread-pool:
+ # 是否开启动态线程池
+ enable: true
+ # 是否打印 banner
+ banner: true
+ # 是否开启线程池数据采集,对接 Micrometer、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、ETCD、Polaris 任选其一
+ nacos:
+ data-id: xxx
+ group: xxx
+ apollo:
+ namespace: xxxx
+ # 配置中心文件格式
+ config-file-type: yml
+ # tomcat、undertow、jetty 三种容器线程池,任选其一
+ undertow:
+ core-pool-size: 100
+ maximum-pool-size: 200
+ keep-alive-time: 1000
+ # 全局通知配置-是否报警
+ 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
+ # 阻塞队列名称,参考 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
+ queue-capacity: 1
+ execute-time-out: 1000
+ blocking-queue: 'LinkedBlockingQueue'
+ rejected-handler: 'AbortPolicy'
+ keep-alive-time: 1024
+ allow-core-thread-time-out: true
+ thread-name-prefix: 'message-consume'
+ alarm: true
+ active-alarm: 80
+ capacity-alarm: 80
+ notify:
+ interval: 8
+ receives: xxx
+```
+
+## ThreadPoolExecutor 适配
+
+添加线程池配置类,通过 `@DynamicThreadPool` 注解修饰。`threadPoolId` 为服务端创建的线程池 ID。
+
+```java
+package cn.hippo4j.example;
+
+import cn.hippo4j.core.executor.DynamicThreadPool;
+import cn.hippo4j.core.executor.support.ThreadPoolBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import java.util.concurrent.ThreadPoolExecutor;
+
+@Configuration
+public class ThreadPoolConfig {
+
+ @Bean
+ @DynamicThreadPool
+ public ThreadPoolExecutor messageConsumeDynamicExecutor() {
+ String threadPoolId = "message-consume";
+ ThreadPoolExecutor messageConsumeDynamicExecutor = ThreadPoolBuilder.builder()
+ .threadFactory(threadPoolId)
+ .threadPoolId(threadPoolId)
+ .dynamicPool()
+ .build();
+ return messageConsumeDynamicExecutor;
+ }
+
+ @Bean
+ @DynamicThreadPool
+ public ThreadPoolExecutor messageProduceDynamicExecutor() {
+ String threadPoolId = "message-produce";
+ ThreadPoolExecutor messageProduceDynamicExecutor = ThreadPoolBuilder.builder()
+ .threadFactory(threadPoolId)
+ .threadPoolId(threadPoolId)
+ .dynamicPool()
+ .build();
+ return messageProduceDynamicExecutor;
+ }
+
+}
+```
+
+通过 ThreadPoolBuilder 构建动态线程池,只有 threadFactory、threadPoolId 为必填项,其它参数会从配置中心拉取。
+
+项目中使用上述定义的动态线程池,如下所示:
+
+```java
+@Resource
+private ThreadPoolExecutor messageConsumeDynamicExecutor;
+
+messageConsumeDynamicExecutor.execute(() -> xxx);
+
+@Resource
+private ThreadPoolExecutor messageProduceDynamicExecutor;
+
+messageProduceDynamicExecutor.execute(() -> xxx);
+```
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/getting_started/difference.md b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/difference.md
new file mode 100644
index 00000000..4e07d71b
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/difference.md
@@ -0,0 +1,37 @@
+---
+sidebar_position: 0
+---
+
+# 运行模式介绍
+
+1.1.0 版本发布后,Hippo-4J 分为两种使用模式:轻量级依赖配置中心以及无中间件依赖版本。
+
+
+
+### hippo4j-config
+
+**轻量级动态线程池管理**,依赖 Nacos、Apollo、Zookeeper、ETCD、Polaris 等三方配置中心(任选其一)完成线程池参数动态变更,支持运行时报警、监控等功能。
+
+> 监控功能配置详见:[线程池监控](/docs/user_docs/getting_started/config/hippo4j-config-monitor)
+
+
+
+### hippo4j-server
+
+**部署 hippo4j-server 服务**,通过可视化 Web 界面完成线程池的创建、变更以及查看,不依赖三方中间件。
+
+相比较 hippo4j-config,功能会更强大,但同时也引入了一定的复杂性。需要部署一个 Java 服务,以及依赖 MySQL 数据库。
+
+
+
+### 使用总结
+
+| | hippo4j-config | hippo4j-server |
+| ---- | ---------------------------------------------------- | ------------------------------------------------------------ |
+| 依赖 | Nacos、Apollo、Zookeeper、ETCD、Polaris 配置中心(任选其一) | 部署 Hippo-4J Server(内部无依赖中间件) |
+| 使用 | 配置中心补充线程池相关参数 | Hippo-4J Server Web 控制台添加线程池记录 |
+| 功能 | 包含基础功能:参数动态化、运行时监控、报警等 | 基础功能之外扩展控制台界面、线程池堆栈查看、线程池运行信息实时查看、历史运行信息查看、线程池配置集群个性化等 |
+
+使用建议:根据公司情况选择,如果基本功能可以满足使用,选择 hippo4j-config 使用即可;如果希望更多的功能,可以选择 hippo4j-server。
+
+**两者在进行替换的时候,无需修改业务代码**。
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/getting_started/hippo4j-adapter.md b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/hippo4j-adapter.md
new file mode 100644
index 00000000..030367e1
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/hippo4j-adapter.md
@@ -0,0 +1,72 @@
+---
+sidebar_position: 6
+---
+
+# 三方框架线程池适配
+
+Hippo4J 目前已支持的三方框架线程池列表:
+
+- Dubbo
+- Hystrix
+- RabbitMQ
+- RocketMQ
+- AlibabaDubbo
+- RocketMQSpringCloudStream
+- RabbitMQSpringCloudStream
+
+引入 Hippo4J Server 或 Core 的 Maven Jar 坐标后,还需要引入对应的框架适配 Jar:
+
+```xml
+
+ cn.hippo4j
+
+ hippo4j-spring-boot-starter-adapter-dubbo
+
+ hippo4j-spring-boot-starter-adapter-alibaba-dubbo
+
+ hippo4j-spring-boot-starter-adapter-hystrix
+
+ hippo4j-spring-boot-starter-adapter-rabbitmq
+
+ hippo4j-spring-boot-starter-adapter-rocketmq
+
+ hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rocketmq
+
+ hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rabbitmq
+ 1.4.2
+
+```
+
+如果想省事,仅需引入一个全量包,框架底层会根据条件判断加载具体线程池适配器。
+
+```xml
+
+ cn.hippo4j
+ hippo4j-spring-boot-starter-adapter-all
+ 1.4.2
+
+```
+
+## Hippo4J Server
+
+Hippo4J Server 仅需要引入上述 Jar 包,即可在 Hippo4J Server 的控制台进行查看及修改三方框架线程池。
+
+
+
+## Hippo4J Config
+
+Hippo4J Config 除了依赖上述适配 Jar 包外,还需要在配置中心添加以下配置项。
+
+```yaml
+spring:
+ dynamic:
+ thread-pool:
+ # 省略其它配置
+ adapter-executors:
+ # threadPoolKey 代表线程池标识
+ - threadPoolKey: 'input'
+ # mark 为三方线程池框架类型,参见文初已支持框架集合
+ mark: 'RocketMQSpringCloudStream'
+ corePoolSize: 10
+ maximumPoolSize: 10
+```
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/getting_started/img/docsVersionDropdown.png b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/img/docsVersionDropdown.png
new file mode 100644
index 00000000..97e41646
Binary files /dev/null and b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/img/docsVersionDropdown.png differ
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/getting_started/img/grafana-monitor.jpg b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/img/grafana-monitor.jpg
new file mode 100644
index 00000000..336bd980
Binary files /dev/null and b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/img/grafana-monitor.jpg differ
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/getting_started/img/localeDropdown.png b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/img/localeDropdown.png
new file mode 100644
index 00000000..e257edc1
Binary files /dev/null and b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/img/localeDropdown.png differ
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/getting_started/server/_category_.json b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/server/_category_.json
new file mode 100644
index 00000000..4063c17f
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/server/_category_.json
@@ -0,0 +1,5 @@
+{
+ "label": "无中间件依赖",
+ "position": 3,
+ "collapsed": true
+}
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/getting_started/server/hippo4j-server-config.md b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/server/hippo4j-server-config.md
new file mode 100644
index 00000000..24bf9a13
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/server/hippo4j-server-config.md
@@ -0,0 +1,19 @@
+---
+sidebar_position: 4
+---
+
+# 服务端配置
+
+`hippo4j.core.clean-history-data-enable`
+
+是否开启线程池历史数据清洗,默认开启。
+
+`hippo4j.core.clean-history-data-period`
+
+线程池历史数据保留时间,默认值:30,单位分钟。
+
+服务端会保留这个配置时间的数据,超过这个时间则会被清理。比如按照默认值 30 分钟来说,12:00 收集到的数据,12:30 就会被清理删除。
+
+`hippo4j.core.monitor.report-type`
+
+客户端监控上报服务端类型,可选值:http、netty,默认 http。服务端开启 netty 配置后,需要在客户端对应开启才可生效。用来应对大量动态线程池监控场景。
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/getting_started/server/hippo4j-server-start.md b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/server/hippo4j-server-start.md
new file mode 100644
index 00000000..64b94ee3
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/getting_started/server/hippo4j-server-start.md
@@ -0,0 +1,127 @@
+---
+sidebar_position: 3
+---
+
+# 接入流程
+
+部署服务端,参考 [部署手册](/docs/user_docs/ops/hippo4j-server-deploy)。
+
+服务端创建 [租户、项目](/docs/user_docs/other/issue#租户和项目在-hippo4j-中是什么意思) 和线程池记录。
+
+需要注意,项目 ID 需要与配置文件 `{application.name}` 保持一致。
+
+:::note
+租户、项目、线程池 ID 如果由多个词组成,建议以 - 进行分割。比如:message-center。
+:::
+
+## Hippo4J 配置
+
+SpringBoot Pom 引入 Hippo4j Starter Jar。
+
+```xml
+
+ cn.hippo4j
+ hippo4j-spring-boot-starter
+ 1.4.2
+
+```
+
+启动类上添加注解 `@EnableDynamicThreadPool`。
+
+```java
+@SpringBootApplication
+@EnableDynamicThreadPool
+public class ExampleApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(ExampleApplication.class, args);
+ }
+}
+```
+
+SpringBoot 应用配置文件添加:
+
+```yaml
+spring:
+ profiles:
+ active: dev
+ application:
+ # 服务端创建的项目 id 需要与 application.name 保持一致
+ name: dynamic-threadpool-example
+ dynamic:
+ thread-pool:
+ # 服务端地址
+ server-addr: http://localhost:6691
+ # 用户名
+ username: admin
+ # 密码
+ password: 123456
+ # 租户 id, 对应 tenant 表
+ namespace: prescription
+ # 项目 id, 对应 item 表
+ item-id: ${spring.application.name}
+```
+
+## ThreadPoolExecutor 适配
+
+添加线程池配置类,通过 `@DynamicThreadPool` 注解修饰。`threadPoolId` 为服务端创建的线程池 ID。
+
+```java
+package cn.hippo4j.example;
+
+import cn.hippo4j.core.executor.DynamicThreadPool;
+import cn.hippo4j.core.executor.support.ThreadPoolBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+@Configuration
+public class ThreadPoolConfig {
+
+ @Bean
+ @DynamicThreadPool
+ public ThreadPoolExecutor messageConsumeDynamicExecutor() {
+ String threadPoolId = "message-consume";
+ ThreadPoolExecutor messageConsumeDynamicExecutor = ThreadPoolBuilder.builder()
+ .threadFactory(threadPoolId)
+ .threadPoolId(threadPoolId)
+ .dynamicPool()
+ .build();
+ return messageConsumeDynamicExecutor;
+ }
+
+ @Bean
+ @DynamicThreadPool
+ public ThreadPoolExecutor messageProduceDynamicExecutor() {
+ String threadPoolId = "message-produce";
+ ThreadPoolExecutor messageProduceDynamicExecutor = ThreadPoolBuilder.builder()
+ .threadFactory(threadPoolId)
+ .threadPoolId(threadPoolId)
+ .dynamicPool()
+ .build();
+ return messageProduceDynamicExecutor;
+ }
+
+}
+```
+
+通过 ThreadPoolBuilder 构建动态线程池,只有 threadFactory、threadPoolId 为必填项,其它参数会从 hippo4j-server 服务拉取。
+
+:::note
+创建线程池时建议填充实际的参数。如果在连接 Hippo4J Server 端失败时,会使用填充配置创建线程池。
+:::
+
+项目中使用上述定义的动态线程池,如下所示:
+
+```java
+@Resource
+private ThreadPoolExecutor messageConsumeDynamicExecutor;
+
+messageConsumeDynamicExecutor.execute(() -> xxx);
+
+@Resource
+private ThreadPoolExecutor messageProduceDynamicExecutor;
+
+messageProduceDynamicExecutor.execute(() -> xxx);
+```
+
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/intro.md b/docs/versioned_docs/version-1.4.2/user_docs/intro.md
new file mode 100644
index 00000000..84930faa
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/intro.md
@@ -0,0 +1,618 @@
+---
+sidebar_position: 1
+---
+
+# 简介
+
+## 线程池痛点
+
+线程池是一种基于池化思想管理线程的工具,使用线程池可以减少创建销毁线程的开销,避免线程过多导致系统资源耗尽。
+
+在高并发以及大批量的任务处理场景,线程池的使用是必不可少的。
+
+如果有在项目中实际使用线程池,相信你可能会遇到以下痛点:
+
+- 线程池随便定义,线程资源过多,造成服务器高负载。
+
+- 线程池参数不易评估,随着业务的并发提升,业务面临出现故障的风险。
+- 线程池任务执行时间超过平均执行周期,开发人员无法感知。
+- 线程池任务堆积,触发拒绝策略,影响既有业务正常运行。
+- 当业务出现超时、熔断等问题时,因为没有监控,无法确定是不是线程池引起。
+- 原生线程池不支持运行时变量的传递,比如 MDC 上下文遇到线程池就 GG。
+- 无法执行优雅关闭,当项目关闭时,大量正在运行的线程池任务被丢弃。
+- 线程池运行中,任务执行停止,怀疑发生死锁或执行耗时操作,但是无从下手。
+
+## 什么是 Hippo-4J
+
+Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池等功能,为业务系统提高线上运行保障能力。
+
+提供以下功能支持:
+
+- 全局管控 - 管理应用线程池实例。
+
+- 动态变更 - 应用运行时动态变更线程池参数,包括不限于:核心、最大线程数、阻塞队列容量、拒绝策略等。
+- 通知报警 - 内置四种报警通知策略,线程池活跃度、容量水位、拒绝策略以及任务执行时间超长。
+- 运行监控 - 实时查看线程池运行时数据,最近半小时线程池运行数据图表展示。
+- 功能扩展 - 支持线程池任务传递上下文;项目关闭时,支持等待线程池在指定时间内完成任务。
+- 多种模式 - 内置两种使用模式:[依赖配置中心](https://hippo4j.cn/docs/user_docs/getting_started/config/hippo4j-config-start) 和 [无中间件依赖](https://hippo4j.cn/docs/user_docs/getting_started/server/hippo4j-server-start)。
+- 容器管理 - Tomcat、Jetty、Undertow 容器线程池运行时查看和线程数变更。
+- 框架适配 - Dubbo、Hystrix、RabbitMQ、RocketMQ 等消费线程池运行时数据查看和线程数变更。
+
+## 快速开始
+
+对于本地演示目的,请参阅 [Quick start](https://hippo4j.cn/docs/user_docs/user_guide/quick-start)
+
+演示环境: [http://console.hippo4j.cn/index.html](http://console.hippo4j.cn/index.html)
+
+## 接入登记
+
+更多接入的公司,欢迎在 [登记地址](https://github.com/opengoofy/hippo4j/issues/13) 登记,登记仅仅为了产品推广。
+
+## 联系我
+
+
+
+扫码添加微信,备注:hippo4j,邀您加入群聊。若图片加载不出来,访问 [官网站点](https://hippo4j.cn/docs/user_docs/other/group)。
+
+## 友情链接
+
+- [[ 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 学习指南。
+
+## 贡献者
+
+感谢所有为项目作出贡献的开发者。如果有意贡献,参考 [good first issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)。
+
+
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/ops/_category_.json b/docs/versioned_docs/version-1.4.2/user_docs/ops/_category_.json
new file mode 100644
index 00000000..d5b7d1e8
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/ops/_category_.json
@@ -0,0 +1,7 @@
+{
+ "label": "运维指南",
+ "position": 4,
+ "link": {
+ "type": "generated-index"
+ }
+}
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/ops/hippo4j-server-deploy.md b/docs/versioned_docs/version-1.4.2/user_docs/ops/hippo4j-server-deploy.md
new file mode 100644
index 00000000..f78457ba
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/ops/hippo4j-server-deploy.md
@@ -0,0 +1,45 @@
+---
+sidebar_position: 1
+---
+
+# 源码包部署
+
+[RELEASE](https://github.com/opengoofy/hippo4j/releases) 页面下载对应版本并进行解压。
+
+## 初始化
+
+修改数据库相关信息。
+
+```txt
+/conf/application.properties
+```
+
+如果是新运行 Hippo-4J,数据库执行下述 SQL 脚本即可。
+
+```txt
+/conf/hippo4j_manager.sql
+```
+
+如果是对已运行 Hippo-4J 升级,请查看 `/conf/sql-upgrade` 目录下,是否有目标版本对应的升级脚本。
+
+## 直接运行
+
+Mac Linux 启动执行。
+
+```txt
+sh ./bin/startup.sh
+```
+
+Windows 启动执行。
+
+```txt
+bin/startup.cmd
+```
+
+## 访问控制台
+
+启动成功后,访问链接。用户名密码:admin 123456
+
+```txt
+localhost:6691/index.html
+```
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/ops/server-docker.md b/docs/versioned_docs/version-1.4.2/user_docs/ops/server-docker.md
new file mode 100644
index 00000000..141c597a
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/ops/server-docker.md
@@ -0,0 +1,50 @@
+---
+sidebar_position: 2
+---
+
+# Docker部署
+
+## 镜像启动
+
+Docker 镜像默认使用内置 H2 数据库,数据持久化到 Docker 容器存储卷中。
+
+```shell
+docker run -d -p 6691:6691 --name hippo4j-server hippo4j/hippo4j-server
+```
+
+或者,底层存储数据库切换为 MySQL。`DATASOURCE_HOST` 需要切换为本地 IP,不能使用 `127.0.0.1` 或 `localhost`。
+
+```shell
+docker run -d -p 6691:6691 --name hippo4j-server \
+-e DATASOURCE_MODE=mysql \
+-e DATASOURCE_HOST=xxx.xxx.xxx.xxx \
+-e DATASOURCE_PORT=3306 \
+-e DATASOURCE_DB=hippo4j_manager \
+-e DATASOURCE_USERNAME=root \
+-e DATASOURCE_PASSWORD=root \
+hippo4j/hippo4j-server
+```
+
+访问 Server 控制台,路径 `http://localhost:6691/index.html` ,默认用户名密码:admin / 123456
+
+## 镜像构建
+
+如果想要自定义镜像,可以通过以下命令快速构建 Hippo4J Server:
+
+方式一:
+
+```shell
+# 进入到 hippo4j-server/hippo4j-bootstrap 工程路径下
+mvn clean package -Dskip.spotless.apply=true
+# 默认打包是打包的 tag 是 latest
+docker build -t hippo4j/hippo4j-server ../hippo4j-bootstrap
+```
+
+方式二:
+
+通过 `maven docker plugin`
+
+```shell
+# 进入到 hippo4j-server 工程路径下
+mvn clean package -DskipTests -Dskip.spotless.apply=true docker:build
+```
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/other/_category_.json b/docs/versioned_docs/version-1.4.2/user_docs/other/_category_.json
new file mode 100644
index 00000000..a74d7432
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/other/_category_.json
@@ -0,0 +1,7 @@
+{
+ "label": "其它",
+ "position": 6,
+ "link": {
+ "type": "generated-index"
+ }
+}
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/other/group.md b/docs/versioned_docs/version-1.4.2/user_docs/other/group.md
new file mode 100644
index 00000000..e75e96be
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/other/group.md
@@ -0,0 +1,9 @@
+---
+sidebar_position: 1
+---
+
+# 加群沟通
+
+扫码添加微信,备注:`hippo4j`,邀您加入群聊。
+
+
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/other/issue.md b/docs/versioned_docs/version-1.4.2/user_docs/other/issue.md
new file mode 100644
index 00000000..11f48a12
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/other/issue.md
@@ -0,0 +1,90 @@
+---
+sidebar_position: 2
+---
+
+# 常见问题
+
+- 租户和项目在 Hippo4J 中是什么意思
+- 控制台线程池管理和线程池实例的区别
+- 示例项目为什么会有跨域请求
+- 更新代码后运行时服务端SQL报错
+- 生产环境如何不启用动态线程池
+- Server 端宕机会影响 Client 运行么
+- Hippo4J 的发布方式是怎样的?如何选择正确的版本
+- 群机器人接受不到通知报警
+- 设置线程池参数优先级问题
+- 线程池实例中修改队列容量参数问题
+- 控制台 SocketTimeoutException: connect timed out
+
+## 租户和项目在 Hippo4J 中是什么意思
+
+Hippo4J 按照租户、项目、线程池的维度划分。
+
+举个例子,小编在一家公司的公共组件团队,团队中负责消息、短链接网关等项目。公共组件是租户,消息或短链接就是项目。
+
+## 控制台线程池管理和线程池实例的区别
+
+在线程池管理中修改线程池参数,客户端并不能实时感知到并变更参数,需要重启客户端。而线程池实例中去对具体的实例修改参数时,客户端无需重启,可以实时感知到参数变化。如果二者针对同一线程
+池的参数配置不同,则在重启客户端时,客户端会去拉去线程池管理中的参数配置。
+
+二者对应的定位:线程池管理中的配置是常态化配置。而线程池实例里的配置变更像是一种临时修改,比如突发的流量激增等场景,并不具备普适性。
+
+## 示例项目为什么会有跨域请求
+
+~~正常大家在部署时,服务端项目和客户端都在同一网络下,进行内网通信,是没有问题的。~~
+
+~~因为示例项目中,服务端部署在外网,而客户端注册到服务端 IP 是内网的,所以不通。~~
+
+~~涉及功能:线程池实例-查看、编辑,容器线程池。~~
+
+1.2.0 版本后,服务端访问客户端已变成,浏览器访问服务端,服务端转发客户端的形式完成调用,跨域问题已解决。
+
+## 更新代码后运行时服务端SQL报错
+
+如果更新代码运行功能出错,大概率是因为项目新增或修改了表结构。如版本升级迭代涉及数据库表变更,会额外提供 SQL 变更文件。
+
+如若第一次使用,初始化 SQL 脚本地址:[hippo4j_manager.sql](https://github.com/longtai-cn/hippo4j/blob/develop/hippo4j-server/conf/hippo4j_manager.sql)。
+
+> 友情提示:每次执行数据库表或数据变更时,一定要保持提前备份的好习惯。
+
+## 生产环境如何不启用动态线程池
+
+测试环境已经引入 Hippo4J,暂时不打算上线生产环境。
+
+生产环境指定配置 `spring.dynamic.thread-pool.enable=false`,测试环境和生产环境配置就会隔离。
+
+## Server 端宕机会影响 Client 运行么
+
+不会。Client 端包含对 Server 端的健康检查机制,Server 端不可用时会停止交互,检查到可用时重新建立连接交互。
+
+## Hippo4J 的发布方式是怎样的?如何选择正确的版本
+
+Hippo4J 发布时可能会涉及到两端发布,分别是 Server 和 Starter。如无特殊说明,**每一次的版本升级将兼容上一版本代码**。
+
+- 如涉及 Server 发布,会在 [发布列表页面](https://github.com/longtai-cn/hippo4j/releases) 创建最新的发行版本;
+- 如涉及 Starter 发布,将直接推送 Starter Jar 至中央仓库,Server 包版本不变。
+
+## 群机器人接受不到通知报警
+
+如果是钉钉机器人,需在机器人配置自定义关键字,才可发送成功。如下所示:
+
+
+
+如果使用 hippo4j-server,请检查在 hippo4j-server 添加的报警通知记录,是否在客户端项目启动前,因为客户端只有在启动时会去 hippo4j-server 拉取报警通知记录。
+
+重启客户端项目,会重新拉取最新报警推送配置,问题解决。
+
+## 设置线程池参数优先级问题
+
+- 当使用 `@DynamicThreadPool` 进行修饰的方法中和在管理界面设置中同时存在的话,则管理界面设置的优先级最高;
+- 如果连接 server 端失败的话,使用 `@DynamicThreadPool` 进行修饰设置的优先级最高。
+
+## 线程池实例中修改队列容量参数问题
+
+在线程池管理中添加时,只有当选择队列类型为 `ResizableCapacityLinkedBlockingQueue` 时,后续再进行修改容量大小时才会实时的刷新修改成功。
+
+## 控制台 SocketTimeoutException: connect timed out
+
+控制台中触发的某些操作涉及到 hippo4j-server 调用客户端项目。如果 hippo4j-server 部署在测试环境,而客户端项目为本地启动,则会触发该问题。
+
+为什么编辑线程池参数不报错?因为线程池的动态变更是客户端主动发起连接,和服务端保持了一个长轮询,所以不存在服务端主动调用客户端行为。
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/other/official-ccounts.md b/docs/versioned_docs/version-1.4.2/user_docs/other/official-ccounts.md
new file mode 100644
index 00000000..61a1a5c6
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/other/official-ccounts.md
@@ -0,0 +1,23 @@
+---
+sidebar_position: 5
+---
+
+# 推荐公众号
+
+## JavaGuide
+
+专注Java后端学习和大厂面试的公众号!
+
+
+
+## HelloGitHub
+
+HelloGitHub,专注于开源社区技术和知识内容分享。
+
+
+
+## macrozheng
+
+专注Java技术分享,解析优质开源项目。涵盖SpringBoot、SpringCloud、Docker、K8S等实用技术,作者Github开源项目mall(50K+Star)。
+
+
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/other/operation.md b/docs/versioned_docs/version-1.4.2/user_docs/other/operation.md
new file mode 100644
index 00000000..ba9ed7f0
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/other/operation.md
@@ -0,0 +1,23 @@
+---
+sidebar_position: 6
+---
+
+# 公众号合作
+
+## 推荐须知
+
+hippo4j 作为一款新兴动态线程池框架,开源出来的时间比较晚,目前迫切需要不同的途径进行推广。
+
+如果您是公众号运营者或者开源爱好者,欢迎将 hippo4j 推荐给您的粉丝。
+
+1. 您无需为 hippo4j 专门撰写文案,只需要直接导入 [推荐文章](https://mp.weixin.qq.com/s/JTTwcBEiK_MnFcPTZl3zGA) 即可。
+2. 在文章底部或内容中留下项目官网或者 GitHub 仓库链接。
+3. 文章需至少 1000+ 的阅读量。
+
+作为推荐回报,hippo4j 可以为您:
+
+1. 在框架官方文档 [推荐公众号](/docs/user_docs/other/official-ccounts) 页面处留下您的公众号二维码。
+2. 在框架官方交流群里@全体成员推广您的公众号一次,附带介绍语。
+3. 您的公众号所有新推文章都可以将链接发送到 hippo4j 交流群中,增加阅读量。
+
+如果您还有除公众号以外的其它途径可以与 hippo4j 相互推荐,欢迎 [加群沟通](/docs/user_docs/other/group)。
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/other/question.md b/docs/versioned_docs/version-1.4.2/user_docs/other/question.md
new file mode 100644
index 00000000..49fd4d77
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/other/question.md
@@ -0,0 +1,246 @@
+---
+sidebar_position: 3
+---
+
+# 问题提问
+
+文档引用自:[提问的智慧](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way)
+
+## 在提问之前
+
+在你准备要通过电子邮件、新闻群组或者聊天室提出技术问题前,请先做到以下事情:
+
+1. 尝试在你准备提问的论坛的旧文章中搜索答案。
+2. 尝试上网搜索以找到答案。
+3. 尝试阅读手册以找到答案。
+4. 尝试阅读常见问题文件(FAQ)以找到答案。
+5. 尝试自己检查或试验以找到答案。
+6. 向你身边的强者朋友打听以找到答案。
+7. 如果你是程序开发者,请尝试阅读源代码以找到答案。
+
+当你提出问题的时候,请先表明你已经做了上述的努力;这将有助于树立你并不是一个不劳而获且浪费别人的时间的提问者。如果你能一并表达在做了上述努力的过程中所**学到**的东西会更好,因为我们更乐于回答那些表现出能从答案中学习的人的问题。
+
+## 当你提问时
+
+### 慎选提问的论坛
+小心选择你要提问的场合。如果你做了下述的事情,你很可能被忽略掉或者被看作失败者:
+
+* 在与主题不合的论坛上贴出你的问题。
+* 在探讨进阶技术问题的论坛张贴非常初级的问题;反之亦然。
+* 在太多的不同新闻群组上重复转贴同样的问题(cross-post)。
+* 向既非熟人也没有义务解决你问题的人发送私人电邮。
+
+因此,第一步是找到对的论坛。再说一次,Google 和其它搜索引擎还是你的朋友,用它们来找到与你遭遇到困难的软硬件问题最相关的网站。通常那儿都有常见问题(FAQ)、邮件列表及相关说明文件的链接。如果你的努力(包括**阅读** FAQ)都没有结果,网站上也许还有报告 Bug(Bug-reporting)的流程或链接,如果是这样,链过去看看。
+
+### 使用有意义且描述明确的标题
+
+在邮件列表、新闻群组或论坛中,大约 50 字以内的标题是抓住资深专家注意力的好机会。别用喋喋不休的帮帮忙、跪求、急(更别说救命啊!!!!这样让人反感的话,用这种标题会被条件反射式地忽略)来浪费这个机会。不要妄想用你的痛苦程度来打动我们,而应该是在这点空间中使用极简单扼要的描述方式来提出问题。
+
+一个好标题范例是`目标 —— 差异`式的描述,许多技术支持组织就是这样做的。在`目标`部分指出是哪一个或哪一组东西有问题,在`差异`部分则描述与期望的行为不一致的地方。
+
+> 蠢问题:救命啊!我的笔记本电脑不能正常显示了!
+
+> 聪明问题:X.org 6.8.1 的鼠标指针会变形,某牌显卡 MV1005 芯片组。
+
+> 更聪明问题:X.org 6.8.1 的鼠标指针,在某牌显卡 MV1005 芯片组环境下 - 会变形。
+
+### 使用清晰、正确、精准且合乎语法的语句
+
+我们从经验中发现,粗心的提问者通常也会粗心地写程序与思考(我敢打包票)。回答粗心大意者的问题很不值得,我们宁愿把时间耗在别处。
+
+正确的拼写、标点符号和大小写是很重要的。一般来说,如果你觉得这样做很麻烦,不想在乎这些,那我们也觉得麻烦,不想在乎你的提问。花点额外的精力斟酌一下字句,用不着太僵硬与正式 —— 事实上,黑客文化很看重能准确地使用非正式、俚语和幽默的语句。但它**必须很**准确,而且有迹象表明你是在思考和关注问题。
+
+### 精确地描述问题并言之有物
+
+* 仔细、清楚地描述你的问题或 Bug 的症状。
+* 描述问题发生的环境(机器配置、操作系统、应用程序、以及相关的信息),提供经销商的发行版和版本号(如:`Fedora Core 4`、`Slackware 9.1`等)。
+* 描述在提问前你是怎样去研究和理解这个问题的。
+* 描述在提问前为确定问题而采取的诊断步骤。
+* 描述最近做过什么可能相关的硬件或软件变更。
+* 尽可能地提供一个可以`重现这个问题的可控环境`的方法。
+
+尽量去揣测一个黑客会怎样反问你,在你提问之前预先将黑客们可能提出的问题回答一遍。
+
+以上几点中,当你报告的是你认为可能在代码中的问题时,给黑客一个可以重现你的问题的环境尤其重要。当你这么做时,你得到有效的回答的机会和速度都会大大的提升。
+
+[Simon Tatham](http://www.chiark.greenend.org.uk/~sgtatham/) 写过一篇名为《[如何有效的报告 Bug](http://www.chiark.greenend.org.uk/~sgtatham/bugs-cn.html)》的出色文章。强力推荐你也读一读。
+
+### 话不在多而在精
+
+你需要提供精确有内容的信息。这并不是要求你简单的把成堆的出错代码或者资料完全转录到你的提问中。如果你有庞大而复杂的测试样例能重现程序挂掉的情境,尽量将它剪裁得越小越好。
+
+这样做的用处至少有三点。
+第一,表现出你为简化问题付出了努力,这可以使你得到回答的机会增加;
+第二,简化问题使你更有可能得到**有用**的答案;
+第三,在精炼你的 bug 报告的过程中,你很可能就自己找到了解决方法或权宜之计。
+
+### 别动辄声称找到 Bug
+
+当你在使用软件中遇到问题,除非你非常、**非常**的有根据,不要动辄声称找到了 Bug。提示:除非你能提供解决问题的源代码补丁,或者提供回归测试来表明前一版本中行为不正确,否则你都多半不够完全确信。这同样适用在网页和文件,如果你(声称)发现了文件的`Bug`,你应该能提供相应位置的修正或替代文件。
+
+请记得,还有其他许多用户没遇到你发现的问题,否则你在阅读文件或搜索网页时就应该发现了(你在抱怨前[已经做了这些,是吧](#在提问之前)?)。这也意味着很有可能是你弄错了而不是软件本身有问题。
+
+编写软件的人总是非常辛苦地使它尽可能完美。如果你声称找到了 Bug,也就是在质疑他们的能力,即使你是对的,也有可能会冒犯到其中某部分人。当你在标题中嚷嚷着有`Bug`时,这尤其严重。
+
+提问时,即使你私下非常确信已经发现一个真正的 Bug,最好写得像是**你**做错了什么。如果真的有 Bug,你会在回复中看到这点。这样做的话,如果真有 Bug,维护者就会向你道歉,这总比你惹恼别人然后欠别人一个道歉要好一点。
+
+### 低声下气不能代替你的功课
+
+有些人明白他们不该粗鲁或傲慢的提问并要求得到答复,但他们选择另一个极端 —— 低声下气:`我知道我只是个可悲的新手,一个撸瑟,但...`。这既使人困扰,也没有用,尤其是伴随着与实际问题含糊不清的描述时更令人反感。
+
+别用原始灵长类动物的把戏来浪费你我的时间。取而代之的是,尽可能清楚地描述背景条件和你的问题情况。这比低声下气更好地定位了你的位置。
+
+有时网页论坛会设有专为新手提问的版面,如果你真的认为遇到了初学者的问题,到那去就是了,但一样别那么低声下气。
+
+### 描述问题症状而非你的猜测
+
+告诉黑客们你认为问题是怎样造成的并没什么帮助。(如果你的推断如此有效,还用向别人求助吗?),因此要确信你原原本本告诉了他们问题的症状,而不是你的解释和理论;让黑客们来推测和诊断。如果你认为陈述自己的猜测很重要,清楚地说明这只是你的猜测,并描述为什么它们不起作用。
+
+**蠢问题**
+
+> 我在编译内核时接连遇到 SIG11 错误,
+> 我怀疑某条飞线搭在主板的走线上了,这种情况应该怎样检查最好?
+
+**聪明问题**
+
+> 我的组装电脑是 FIC-PA2007 主机板搭载 AMD K6/233 CPU(威盛 Apollo VP2 芯片组),
+> 256MB Corsair PC133 SDRAM 内存,在编译内核时,从开机 20 分钟以后就频频产生 SIG11 错误,
+> 但是在头 20 分钟内从没发生过相同的问题。重新启动也没有用,但是关机一晚上就又能工作 20 分钟。
+> 所有内存都换过了,没有效果。相关部分的标准编译记录如下…
+
+由于以上这点似乎让许多人觉得难以配合,这里有句话可以提醒你:`所有的诊断专家都来自密苏里州。` 美国国务院的官方座右铭则是:`让我看看`(出自国会议员 Willard D. Vandiver 在 1899 年时的讲话:`我来自一个出产玉米,棉花,牛蒡和民主党人的国家,滔滔雄辩既不能说服我,也不会让我满意。我来自密苏里州,你必须让我看看。`) 针对诊断者而言,这并不是一种怀疑,而只是一种真实而有用的需求,以便让他们看到的是与你看到的原始证据尽可能一致的东西,而不是你的猜测与归纳的结论。所以,大方的展示给我们看吧!
+
+### 按发生时间先后列出问题症状
+
+问题发生前的一系列操作,往往就是对找出问题最有帮助的线索。因此,你的说明里应该包含你的操作步骤,以及机器和软件的反应,直到问题发生。在命令行处理的情况下,提供一段操作记录(例如运行脚本工具所生成的),并引用相关的若干行(如 20 行)记录会非常有帮助。
+
+如果挂掉的程序有诊断选项(如 -v 的详述开关),试着选择这些能在记录中增加调试信息的选项。记住,`多`不等于`好`。试着选取适当的调试级别以便提供有用的信息而不是让读者淹没在垃圾中。
+
+如果你的说明很长(如超过四个段落),在开头简述问题,接下来再按时间顺序详述会有所帮助。这样黑客们在读你的记录时就知道该注意哪些内容了。
+
+### 描述目标而不是过程
+
+如果你想弄清楚如何做某事(而不是报告一个 Bug),在开头就描述你的目标,然后才陈述重现你所卡住的特定步骤。
+
+经常寻求技术帮助的人在心中有个更高层次的目标,而他们在自以为能达到目标的特定道路上被卡住了,然后跑来问该怎么走,但没有意识到这条路本身就有问题。结果要费很大的劲才能搞定。
+
+**蠢问题**
+
+> 我怎样才能从某绘图程序的颜色选择器中取得十六进制的 RGB 值?
+
+**聪明问题**
+
+> 我正试着用替换一幅图片的色码(color table)成自己选定的色码,我现在知道的唯一方法是编辑每个色码区块(table slot),
+> 但却无法从某绘图程序的颜色选择器取得十六进制的 RGB 值。
+
+第二种提问法比较聪明,你可能得到像是```建议采用另一个更合适的工具```的回复。
+
+### 清楚明确的表达你的问题以及需求
+
+漫无边际的提问是近乎无休无止的时间黑洞。最有可能给你有用答案的人通常也正是最忙的人(他们忙是因为要亲自完成大部分工作)。这样的人对无节制的时间黑洞相当厌恶,所以他们也倾向于厌恶那些漫无边际的提问。
+
+如果你明确表述需要回答者做什么(如提供指点、发送一段代码、检查你的补丁、或是其他等等),就最有可能得到有用的答案。因为这会定出一个时间和精力的上限,便于回答者能集中精力来帮你。这么做很棒。
+
+要理解专家们所处的世界,请把专业技能想像为充裕的资源,而回复的时间则是稀缺的资源。你要求他们奉献的时间越少,你越有可能从真正专业而且很忙的专家那里得到解答。
+
+所以,界定一下你的问题,使专家花在辨识你的问题和回答所需要付出的时间减到最少,这技巧对你有用答案相当有帮助 —— 但这技巧通常和简化问题有所区别。因此,问`我想更好地理解 X,可否指点一下哪有好一点说明?`通常比问`你能解释一下 X 吗?`更好。如果你的代码不能运作,通常请别人看看哪里有问题,比要求别人替你改正要明智得多。
+
+### 礼多人不怪,而且有时还很有帮助
+
+彬彬有礼,多用`请`和`谢谢您的关注`,或`谢谢你的关照`。让大家都知道你对他们花时间免费提供帮助心存感激。
+
+坦白说,这一点并没有比使用清晰、正确、精准且合乎语法和避免使用专用格式重要(也不能取而代之)。黑客们一般宁可读有点唐突但技术上鲜明的 Bug 报告,而不是那种有礼但含糊的报告。(如果这点让你不解,记住我们是按问题能教给我们什么来评价问题的价值的)
+
+然而,如果你有一串的问题待解决,客气一点肯定会增加你得到有用回应的机会。
+
+(我们注意到,自从本指南发布后,从资深黑客那里得到的唯一严重缺陷反馈,就是对预先道谢这一条。一些黑客觉得`先谢了`意味着事后就不用再感谢任何人的暗示。我们的建议是要么先说`先谢了`,**然后**事后再对回复者表示感谢,或者换种方式表达感激,譬如用`谢谢你的关注`或`谢谢你的关照`。)
+
+## 不该问的问题
+
+以下是几个经典蠢问题,以及黑客没回答时心中所想的:
+
+问题:[我能在哪找到 X 程序或 X 资源?](#q1)
+
+问题:[我怎样用 X 做 Y?](#q2)
+
+问题:[我的程序/设定/SQL 语句没有用](#q3)
+
+问题:[我的 Windows 电脑有问题,你能帮我吗?](#q4)
+
+问题:[我的程序不会动了,我认为系统工具 X 有问题](#q5)
+
+问题:[我在安装 Linux(或者 X )时有问题,你能帮我吗?](#q6)
+
+问题:[我怎么才能破解 root 帐号/窃取 OP 特权/读别人的邮件呢?](#q7)
+
+---
+
+> 问题:我能在哪找到 X 程序或 X 资源?
+
+回答:就在我找到它的地方啊,白痴 —— 搜索引擎的那一头。天哪!难道还有人不会用 [Google](https://www.google.com) 吗?
+
+> 问题:我怎样用 X 做 Y?
+
+回答:如果你想解决的是 Y ,提问时别给出可能并不恰当的方法。这种问题说明提问者不但对 X 完全无知,也对 Y 要解决的问题糊涂,还被特定形势禁锢了思维。最好忽略这种人,等他们把问题搞清楚了再说。
+
+> 问题:我的{程序/设定/SQL 语句}没有用
+
+回答:这不算是问题吧,我对要我问你二十个问题才找得出你真正问题的问题没兴趣 —— 我有更有意思的事要做呢。在看到这类问题的时候,我的反应通常不外如下三种
+
+* 你还有什么要补充的吗?
+* 真糟糕,希望你能搞定。
+* 这关我屁事?
+
+> 问题:我的 Windows 电脑有问题,你能帮我吗?
+
+回答:能啊,扔掉微软的垃圾,换个像 Linux 或 BSD 的开源操作系统吧。
+
+注意:如果程序有官方版 Windows 或者与 Windows 有互动(如 Samba),你**可以**问与 Windows 相关的问题,只是别对问题是由 Windows 操作系统而不是程序本身造成的回复感到惊讶, 因为 Windows 一般来说实在太烂,这种说法通常都是对的。
+
+> 问题:我的程序不会动了,我认为系统工具 X 有问题
+
+回答:你完全有可能是第一个注意到被成千上万用户反复使用的系统调用与函数库文件有明显缺陷的人,更有可能的是你完全没有根据。不同凡响的说法需要不同凡响的证据,当你这样声称时,你必须有清楚而详尽的缺陷说明文件作后盾。
+
+> 问题:我在安装 Linux(或者 X )时有问题,你能帮我吗?
+
+回答:不能,我只有亲自在你的电脑上动手才能找到毛病。还是去找你当地的 Linux 使用群组者寻求实际的指导吧(你能在[这儿](http://www.linux.org/groups/index.html)找到用户群组的清单)。
+
+注意:如果安装问题与某 Linux 的发行版有关,在它的邮件列表、论坛或本地用户群组中提问也许是恰当的。此时,应描述问题的准确细节。在此之前,先用 `Linux` 和**所有**被怀疑的硬件作关键词仔细搜索。
+
+> 问题:我怎么才能破解 root 帐号/窃取 OP 特权/读别人的邮件呢?
+
+回答:想要这样做,说明了你是个卑鄙小人;想找个黑客帮你,说明你是个白痴!
+
+## 好问题与蠢问题
+
+最后,我将透过举一些例子,来说明怎样聪明的提问;同一个问题的两种问法被放在一起,一种是愚蠢的,另一种才是明智的。
+
+**蠢问题**:
+
+> 我从 foo 项目找来的源码没法编译。它怎么这么烂?
+
+他觉得都是别人的错,这个傲慢自大的提问者。
+
+**聪明问题**:
+
+> foo 项目代码在 Nulix 6.2 版下无法编译通过。我读过了 FAQ,但里面没有提到跟 Nulix 有关的问题。这是我编译过程的记录,我有什么做的不对的地方吗?
+
+提问者已经指明了环境,也读过了 FAQ,还列出了错误,并且他没有把问题的责任推到别人头上,他的问题值得被关注。
+
+**蠢问题**:
+
+> 我的主机板有问题了,谁来帮我?
+
+某黑客对这类问题的回答通常是:`好的,还要帮你拍拍背和换尿布吗?`,然后按下删除键。
+
+**聪明问题**:
+
+> 我在 S2464 主机板上试过了 X 、 Y 和 Z ,但没什么作用,我又试了 A 、 B 和 C 。请注意当我尝试 C 时的奇怪现象。显然 florbish 正在 grommicking,但结果出人意料。通常在 Athlon MP 主机板上引起 grommicking 的原因是什么?有谁知道接下来我该做些什么测试才能找出问题?
+
+## 如果得不到回答
+
+如果仍得不到回答,请不要以为我们觉得无法帮助你。有时只是看到你问题的人不知道答案罢了。没有回应不代表你被忽视,虽然不可否认这种差别很难区分。
+
+总的来说,简单的重复张贴问题是个很糟的点子。这将被视为无意义的喧闹。有点耐心,知道你问题答案的人可能生活在不同的时区,可能正在睡觉,也有可能你的问题一开始就没有组织好。
+
+你可以通过其他渠道获得帮助,这些渠道通常更适合初学者的需要。
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/other/update-log.md b/docs/versioned_docs/version-1.4.2/user_docs/other/update-log.md
new file mode 100644
index 00000000..fc7b2fda
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/other/update-log.md
@@ -0,0 +1,299 @@
+---
+sidebar_position: 4
+---
+
+# 更新日志
+
+## 1.4.2 (Oct 18, 2022)
+
+这是一个功能增强版本,修复了少量 BUG。建议按照当前版本升级。具体信息可查看 Release 标签地址:[1.4.2](https://github.com/opengoofy/hippo4j/milestone/12?closed=1)
+
+**Feature**
+
+- 强制指定客户端注册的 ip + port
+- 支持 spring-cloud-tencent Polaris 线程池动态更新 @weihubeats
+- 服务启动时加载 MySQL、H2 数据库初始化语句
+- Adapter 初始化覆盖核心参数 @pizihao
+- Server 端新增是否开启认证模式 @baymax55
+
+**Refactor**
+
+- 替换底层网络工具类 OkHttp @yanrongzhen
+- 全局移除 commons-lang3 工具包依赖 @yanrongzhen
+- 去除三方工具类依赖 @pizihao
+- 全局移除 Guava 工具包依赖 @road2master
+- DockerFile 基于 H2 数据库重新构建 @BigXin0109
+
+**Bug**
+
+- Dubbo 2.7.15 无法获取线程池引用 @iwangjie
+- 动态线程池报警参数颠倒 @jinlingmei
+
+**Optimize**
+
+- 线程池实例运行数据采集,如果线程池id不存在,且长度超长,会报异常 @Gdk666
+- 项目中动态线程池数量为空时,存在 CPU 空转情况
+- 客户端注册服务端失败,输出服务端返回信息 @wulangcode
+- 调整数据库项目 id 和线程池 id 字段长度
+- 增加代码检查工具 maven-checkstyle-plugin
+- 调整控制台监控图表颜色展示
+
+## 1.4.1 (Sep 12, 2022)
+
+这是一个功能增强版本,修复了若干 BUG。建议按照当前版本升级。具体信息可查看 Release 标签地址:[1.4.1](https://github.com/opengoofy/hippo4j/milestone/11?closed=1)
+
+**Feature**
+
+- 支持 H2 数据库 @weihubeats
+- 动态线程池配置变更时,支持单个、多个或全部节点变 @pizihao
+- 增加线程池活跃度和容量报警可选择关闭
+- @DynamicThreadPool 线程池不存在则创建 @shanjianq
+- 支持 ETCD 配置中心动态调整参数 @weihubeats
+- 创建动态线程池支持 spring 线程池 @BigXin0109
+- 线程池实例变更增加执行超时时间
+- 线程池相关查询页面增加阻塞队列属性
+- 定义动态线程池时,抽象默认配置
+- 提供 ExecutorContext 封装上下文细节 @road2master
+- Docker 制作服务端镜像,帮助开发者快速启动 @BigXin0109
+- RabbitMQ 适配器增加多个 MQ 数据源 @weihubeats
+
+**Bug**
+
+- 动态线程池设置关闭时启动报错 @dousp
+- ExecutorTtlWrapper 类型的 Executor 不生效 @BigXin0109
+- Undertow 获取 WebServer 类型参数异常 @shining-stars-lk
+- 修复线程池核心、最大线程数校验限制
+- ByteConvertUtil#getPrintSize 单位转换错误 @onesimplecoder
+- 创建线程池单选框选择错误
+- ReflectUtil#getFieldsDirectly missing fields @BigXin0109
+- 本地代码中设置的 capacity 无效 @BigXin0109
+- 服务端线程池超时时间存在拆箱空指针异常 @oreoft
+- 未读取服务端返回执行超时时间属性
+- ResizableCapacityLinkedBlockingQueue#put 当前元素数量大于 capacity 未阻塞
+
+**Optimize**
+
+- 长轮询任务判断逻辑优化 @shining-stars-lk
+- 线程池存在实例不允许删除线程池 @shanjianq
+- 优化租户、项目列表展示排版
+- 通知报警模块项目和线程池下拉查询排序修改
+- 动态线程池拒绝策略触发,以异步的方式报警
+- 优化框架中线程池工厂产生的线程名称 @road2master
+
+## 1.4.0 (Aug 16, 2022)
+
+`hippo4j server` 兼容历史低版本,`hippo4j config` 中部分属性名进行了调整,请参考 [hippo4j config 快速开始](https://hippo4j.cn/docs/user_docs/getting-started/hippo4j-core-start)。
+
+注意事项:
+1. 如果是对已运行 hippo4j server 升级,执行 `/conf/sql-upgrade` 目录下对应的升级脚本。
+2. 需客户端在 1.4.0 及以上版本才可在 hippo4j server 设置线程执行超时时间属性。
+
+**Feature**
+
+- 添加 Alibaba Dubbo 线程池监控及动态变更
+- hippo4j server 支持任务执行超时时间动态修改
+- 阿里 TTL 框架线程池适配
+- 添加动态线程池自动注册功能
+- 订阅回调线程池参数变更
+- 动态线程池监控增加 SPI 自定义功能
+- hippo4j server 支持多种线程池监控方式,例如 Prometheus
+- 通知相关参数添加动态变更功能
+
+**Bug**
+
+- 线程池变更:executeTimeOut 变更极端情况下会出现异常
+- 用户登录时候,如果输入了不存在的用户名,后台报空指针异常
+- 修复了对 spring-boot 服务中 tomcat 线程池的兼容问题
+- 排除 Tomcat Jar 使用 Undertow 启动报错
+
+**Optimize**
+
+- hippo4j-core-spring-boot-starter 模块修改名称为 hippo4j-config-spring-boot-starter
+- 拆分容器线程池子页面:Tomcat、Undertow、Jetty
+- 服务端访问客户端时对 URL 转码
+- MyBatisPlus 修改全局填充方法优化
+- 控制台线程池列表下拉框默认正序
+- 控制台线程池实例菜单,对于非可修改容量队列外,不允许修改队列容量
+- 动态线程池控制台功能变更
+- 租户和项目列表分页查询按照创建时间倒序展示
+- 线程池监控页面图表 UI 优化
+- 设置 maven-gpg-plugin 插件默认不执行
+- 前端控制台相关搜索条件添加必填提示
+- hippo4j 消息通知 & 报警抽象优化
+- 配置中心未配置线程池启动报错
+- 控制台线程池报警 UI 以及功能优化
+- Web、框架线程池编辑弹框 UI 优化
+- 线程池添加、编辑页面 UI 优化
+- 线程池运行详情页前端 UI 优化
+
+**Refactor**
+
+- 删除自定义日志组件
+- 线程池监控功能重构
+- hippo4j core 配置中心生效判断重构
+- 配置变更通知 & 报警通知重构
+- Web 容器线程池适配迁移 hippo4j-adapter
+
+## 1.3.1 (July 17, 2022)
+
+注:这是一个兼容历史版本的小范围升级。
+
+**Feature**
+
+- 控制台新增线程池功能设置为 Admin 权限
+- 添加 Hystrix 线程池监控及动态变更
+- 添加 Netty 上传动态线程池监控数据方式
+- 添加 GitHub Actions CI 流程
+- 添加 Spring Kafka 示例项目
+- Tomcat 版本号 >= 9.0.55 线程池适配
+
+**Refactor**
+
+- 更多线程池拆分子目录页面
+
+**Optimize**
+
+- hippo4j core 添加 banner 打印
+- 优化可变更容量阻塞队列名称
+
+**BUG**
+
+- Apollo 配置修改延迟了一个版本
+- Spring Boot 环境下使用 hippo4j-core 接入,配置中心使用 nacos;启动时提示 ConfigService not found
+
+查看 1.3.1 版本发布:https://github.com/mabaiwan/hippo4j/milestone/9
+
+## 1.3.0 (June 06, 2022)
+
+1.3.0 发布 **适配三方框架的基础框架**。
+
+目前已完成 **Dubbo、RabbitMQ、RocketMQ、RocketMQSpringCloudStream** 的线程池适配,后续还会接入 **Kafka、Hystrix** 等框架或中间件的线程池适配。
+
+注:这是一个兼容历史版本的重大升级。
+
+**Feature**
+
+- 添加 RabbitMQ 线程池监控及动态变更
+- 添加 RocketMQ 线程池监控及动态变更
+- 添加 Dubbo 线程池监控及动态变更
+- 添加 SpringCloud Stream RocketMQ 消费线程池监控及动态变更
+
+**Refactor**
+
+- 重构容器线程池查询及修改功能
+- 优化配置中心触发监听后,所执行的数据变更逻辑
+
+**Optimize**
+
+- 前端控制台删除无用组件
+- 服务端页面字段未显示中文
+- 控制台 UI 优化
+- 修改线程池实例后实时刷新列表参数
+- 容器线程池编辑仅限 Admin 权限
+- SpringBoot Starter 变更包路径
+
+**BUG**
+
+- 修复 SpringBoot Nacos 动态刷新不生效
+- 报警配置 alarm=false 不配置通知报警平台和接收人报错
+
+## 1.2.1 (May 07, 2022)
+
+**BugFix**
+
+- apollo 动态配置不生效
+- 修复 hippo4j-core 后置处理器创建线程池问题
+- 重构 hippo4j-core spring 后置处理器逻辑
+- 优化ThreadPoolNotifyAlarmHandler下的空指针异常
+- 修复线程池核心、最大线程数变更问题
+- startup.cmd 未正常读取 conf 配置文件
+
+**Optimize**
+
+- 配置文件中字段歧义
+- 修改代码中历史网址
+- InstanceInfo 的 groupKey 参数重复设置
+- ConfigFileTypeEnum 枚举字段添加注释
+- 线程资源通过线程池创建,不允许自行显示创建线程
+- Guava 版本升级至 30.0-jre 及以上版本
+- SystemClock 替换 System.currentTimeMillis()
+- 添加代码格式化插件 Spotless
+- 修改线程池文案
+
+## 1.2.0 (Mar 13, 2022)
+
+**Feature**
+
+- hippo4j-core线程池资源对接 Prometheus 监控
+- hippo4j-core 支持 Zookeeper
+- hippo4j-core 支持 Apollo
+
+**Optimize**
+
+- 适配非 Web SpringBoot 项目使用 Hippo4J
+- 优化报警通知
+- 修复在 JDK 小版本中的兼容性问题
+
+**BugFix**
+
+- server 端查看容器线程池,参数为 null
+- 重构线程池查看及容器线程池查看等交互
+- 修复引入 hippo4j-spring-boot-starter 后,运行单元测试报错
+- 修复可能出现的空指针异常
+
+## 1.1.0 (Mar 13, 2022)
+
+Hippo4J 线程池框架 1.1.0 RELEASE 版本,添加了 Hippo4J-Core(依赖配置中心的动态线程池).
+
+**Feature**
+
+- 删除 DynamicThreadPoolExecutor 内代码实现,仅通过线程池扩展点进行扩展
+- 通过动态代理实现线程池拒绝策略执行次数统计
+- 抽象通知报警消息模块
+- 抽象 hippo4j 核心组件,不依赖 server 端即可完成动态调参、监控、报警等功能
+- 前端删除线程池按钮添加 Admin 权限
+- 添加线程池任务运行超长报警
+- 容器线程池支持 Undertow
+- 容器线程池支持 Jetty
+- 重构服务端异常体系
+
+**Optimize**
+
+- 前端项目 Token 失效跳转登录页
+- 优化 Server 启动脚本日志输出
+- 优化前端按钮权限控制粒度
+- 优化线程池报警推送文案
+- 前端弹框样式优化
+- 适配低版本 SpringBoot Bind
+- 优化消息通知模块
+
+**BugFix**
+
+- Duplicate entry 'xxx' for key 'uk_configinfo_datagrouptenant'
+
+## 1.0.0 (Feb 01, 2022)
+
+**Feature**
+
+- 线程池运行堆栈查看
+- 扩展 Web 容器线程池动态调参、监控
+
+**Optimize**
+
+- 删除高版本 SpringBoot Api
+- ListableBeanFactory#findAnnotationOnBean SpringBoot 低版本适配
+- 优化客户端关闭时调用服务端钩子函数
+- 线程池实例参数弹框添加实例 ID 和线程池状态
+- 补充线程池替换 Hippo4J 文档
+- 1.5.x springboot 引入hippo4j-spring-boot-starter配置项,bean初始化失败
+- 优化线程池参数编辑合理性校验
+- BaseInstanceRegistry 读写锁重构
+
+**BugFix**
+
+- 本地项目线程池实例缓存无法精确清理
+- 线程池实例页面多实例不同 Active 展示错误
+- 创建动态线程池逻辑判断修复
+- 创建动态线程池增强参数未设置
+- 控制消息推送报警频率的方法有并发安全的问题
+- tomcat线程池上下文获取失败
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/user_guide/_category_.json b/docs/versioned_docs/version-1.4.2/user_docs/user_guide/_category_.json
new file mode 100644
index 00000000..6dc10c33
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/user_guide/_category_.json
@@ -0,0 +1,8 @@
+{
+ "label": "用户指南",
+ "position": 2,
+ "link": {
+ "type": "generated-index",
+ "description": "帮助想要了解 Hippo4J 的用户快速掌握核心开发理念。"
+ }
+}
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/user_guide/frame.md b/docs/versioned_docs/version-1.4.2/user_docs/user_guide/frame.md
new file mode 100644
index 00000000..47f568fa
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/user_guide/frame.md
@@ -0,0 +1,60 @@
+---
+sidebar_position: 1
+---
+
+# 为什么写
+
+[美团线程池文章](https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html "美团线程池文章") 介绍中,因为业务对线程池参数没有合理配置,触发过几起生产事故,进而引发了一系列思考。最终决定封装线程池动态参数调整,扩展线程池监控以及消息报警等功能。
+
+在开源平台找了挺多动态线程池项目,从功能性以及健壮性而言,个人感觉不满足企业级应用。
+
+因为对动态线程池比较感兴趣,加上想写一个有意义的项目,所以决定自己来造一个轻量级的轮子。
+
+想给项目起一个简单易记的名字,类似于 Eureka、Nacos、Redis;后和朋友商量,决定命名:**Hippo4J**。
+
+
+
+## 它解决了什么问题
+
+线程池在业务系统应该都有使用到,帮助业务流程提升效率以及管理线程,多数场景应用于大量的异步任务处理。
+
+虽然线程池提供了我们许多便利,但也并非尽善尽美,比如下面这些问题就无法很好解决。
+
+- 线程池随便定义,线程资源过多,造成服务器高负载。
+
+- 线程池参数不易评估,随着业务的并发提升,业务面临出现故障的风险。
+
+- 线程池任务执行时间超过平均执行周期,开发人员无法感知。
+
+- 线程池任务堆积,触发拒绝策略,影响既有业务正常运行。
+
+- 当业务出现超时、熔断等问题时,因为没有监控,无法确定是不是线程池引起。
+
+- 原生线程池不支持运行时变量的传递,比如 MDC 上下文遇到线程池就 GG。
+
+- 无法执行优雅关闭,当项目关闭时,大量正在运行的线程池任务被丢弃。
+
+- 线程池运行中,任务执行停止,怀疑发生死锁或执行耗时操作,但是无从下手。
+
+Hippo4J 很好解决了这些问题,它将业务中所有线程池统一管理,增强原生线程池系列功能。
+
+## 它有什么特性
+
+应用系统中线程池并不容易管理。参考美团的设计,Hippo4J 按照租户、项目、线程池的维度划分。再加上系统权限,让不同的开发、管理人员负责自己系统的线程池操作。
+
+举个例子,小编在一家公司的公共组件团队,团队中负责消息、短链接网关等项目。公共组件是租户,消息或短链接就是项目。
+
+Hippo4J 除去动态修改线程池,还包含实时查看线程池运行时指标、负载报警、配置日志管理等。
+
+- `hippo4j-adapter`:适配对第三方框架中的线程池进行监控,如 Dubbo、RocketMQ、Hystrix 等;
+- `hippo4j-auth`:用户、角色、权限等;
+- `hippo4j-common`:多个模块公用代码实现;
+- `hippo4j-config`:提供线程池准实时参数更新功能;
+- `hippo4j-console`:对接前端控制台;
+- `hippo4j-core`:核心的依赖,包括配置、核心包装类等;
+- `hippo4j-discovery`:提供线程池项目实例注册、续约、下线等功能;
+- `hippo4j-example` :示例工程;
+- `hippo4j-message` :配置变更以及报警通知发送;
+- `hippo4j-monitor` :线程池运行时监控;
+- `hippo4j-server` :Server 端发布需要的模块聚合;
+- `hippo4j-spring-boot`:SpringBoot Starter。
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/user_guide/framework.md b/docs/versioned_docs/version-1.4.2/user_docs/user_guide/framework.md
new file mode 100644
index 00000000..226ddf61
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/user_guide/framework.md
@@ -0,0 +1,51 @@
+---
+sidebar_position: 2
+---
+
+# 架构设计
+
+简单来说,Hippo4J 从部署的角度上分为两种角色:Server 端和 Client 端。
+
+Server 端是 Hippo4J 项目打包出的 Java 进程,功能包括用户权限、线程池监控以及执行持久化的动作。
+
+Client 端指的是我们 SpringBoot 应用,通过引入 Hippo4J Starter Jar 包负责与 Server 端进行交互。
+
+比如拉取 Server 端线程池数据、动态更新线程池配置以及采集上报线程池运行时数据等。
+
+## 基础组件
+
+### 配置中心(Config)
+
+配置中心位于 Server 端,它的主要作用是监控 Server 端线程池配置变更,实时通知到 Client 实例执行线程池变更流程。
+
+代码设计基于 Nacos 1.x 版本的 **长轮询以及异步 Servlet 机制** 实现。
+
+### 注册中心(Discovery)
+
+负责管理 Client 端(单机或集群)注册到 Server 端的实例,包括不限于**实例注册、续约、过期剔除** 等操作,代码基于 Eureka 源码实现。
+
+上面的配置中心很容易理解,动态线程池参数变更的根本。但是注册中心是用来做什么的?
+
+注册中心管理 Client 端注册的实例,通过这些实例可以 **实时获取线程池的运行时参数信息**。
+
+目前的设计是如此,不排除后续基于 Discovery 做更多的扩展。
+
+### 控制台(Console)
+
+对接前端项目,包括不限于以下模块管理:
+
+
+
+## 消息通知(Notify)
+
+Hippo4J 内置了很多需要通知的事件,比如:线程池参数变更通知、线程池活跃度报警、拒绝策略执行报警以及阻塞队列容量报警等。
+
+目前 Notify 已经接入了钉钉、企业微信和飞书,后续持续集成邮件、短信等通知渠道;并且,Notify 模块提供了消息事件的 SPI 方案,可以接受三方自定义的推送。
+
+## Hippo4j-Spring-Boot-Starter
+
+熟悉 SpringBoot 的小伙伴对 Starter 应该不会陌生。Hippo4J 提供以 Starter Jar 包的形式嵌套在应用内,负责与 Server 端完成交互。
+
+## 功能架构
+
+
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/user_guide/notify.md b/docs/versioned_docs/version-1.4.2/user_docs/user_guide/notify.md
new file mode 100644
index 00000000..216840e9
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/user_guide/notify.md
@@ -0,0 +1,71 @@
+---
+sidebar_position: 4
+---
+
+# 通知报警
+
+现阶段已集成钉钉、企业微信、飞书的消息推送,后续会持续接入邮箱、短信和自定义通知渠道。
+
+
+
+**通知平台**
+
+- DING:钉钉平台;
+
+- LARK:飞书平台;
+
+- WECHAT:企业微信。
+
+**通知类型**
+
+- CONFIG:线程池配置变更推送;
+
+- ALARM:线程池运行报警推送。
+
+**Token**
+
+获取 DING、LARK、WECHAT 机器人 Token。
+
+**报警间隔**
+
+- CONFIG 类型通知没有报警间隔;
+
+- ALARM 类型设置报警间隔后,某一节点下的同一线程池指定间隔只会发送一次报警通知。
+
+**接收者**
+
+```tex
+多个接收者使用英文逗号 , 分割 (注意不要有空格)
+DING:填写手机号
+WECHART:填写user_id会以@的消息发给用户,填写姓名则是普通的@,如:龙台
+LARK:填写ou_开头用户唯一标识会以@的消息发给用户,填写手机号则是普通的@
+```
+
+
+## 钉钉平台
+
+[钉钉创建群机器人](https://www.dingtalk.com/qidian/help-detail-20781541.html)
+
+| 配置变更 | 报警通知 |
+| :---: | :---: |
+|  |  |
+
+添加钉钉机器人后,需在机器人配置自定义关键字,才可发送成功。如下所示:
+
+
+
+## 企业微信
+
+[企业微信创建群机器人](https://open.work.weixin.qq.com/help2/pc/14931?person_id=1&from=homesearch)
+
+| 配置变更 | 报警通知 |
+| :---: | :---: |
+|  |  |
+
+## 飞书平台
+
+[飞书创建群机器人](https://www.feishu.cn/hc/zh-CN/articles/360024984973)
+
+
+
+
diff --git a/docs/versioned_docs/version-1.4.2/user_docs/user_guide/quick-start.md b/docs/versioned_docs/version-1.4.2/user_docs/user_guide/quick-start.md
new file mode 100644
index 00000000..cce9e577
--- /dev/null
+++ b/docs/versioned_docs/version-1.4.2/user_docs/user_guide/quick-start.md
@@ -0,0 +1,40 @@
+---
+sidebar_position: 3
+---
+
+# 快速开始
+
+## 服务启动
+
+使用 Docker 运行服务端,默认使用内置 H2 数据库,数据持久化到 Docker 容器存储卷中。
+
+```shell
+docker run -d -p 6691:6691 --name hippo4j-server hippo4j/hippo4j-server
+```
+
+> 如果没有 Docker,可以使用源码编译的方式,启动 [Hippo4J-Server/Hippo4J-Bootstrap](https://github.com/longtai-cn/hippo4j/tree/develop/hippo4j-server/hippo4j-bootstrap) 模块下 ServerApplication 应用类。
+
+启动示例项目,[hippo4j-spring-boot-starter-example](https://github.com/opengoofy/hippo4j/tree/develop/hippo4j-example/hippo4j-spring-boot-starter-example) 模块下 Hippo4JServerExampleApplication 应用类。
+
+访问 Server 控制台,路径 `http://localhost:6691/index.html`,默认用户名密码:admin / 123456
+
+## 配置变更
+
+访问控制台动态线程池菜单下线程池实例,修改动态线程池相关参数。
+
+
+
+观察 Hippo4j-Example 控制台日志输出,日志输出包括不限于此信息即为成功。
+
+```tex
+2022-09-10 00:23:29.783 INFO 50322 --- [change.config_0] c.h.s.s.c.ServerThreadPoolDynamicRefresh : [message-consume] Dynamic thread pool change parameter.
+ corePoolSize: 2 => 4
+ maximumPoolSize: 6 => 12
+ capacity: 1024 => 2048
+ keepAliveTime: 9999 => 9999
+ executeTimeOut: 800 => 3000
+ rejectedType: SyncPutQueuePolicy => RunsOldestTaskPolicy
+ allowCoreThreadTimeOut: true => true
+```
+
+另外,当 Client 集群部署时,可以修改某一个实例,或选择 `全部修改` 按钮,修改所有实例线程池信息。
diff --git a/docs/versioned_sidebars/version-1.4.2-sidebars.json b/docs/versioned_sidebars/version-1.4.2-sidebars.json
new file mode 100644
index 00000000..98d1c255
--- /dev/null
+++ b/docs/versioned_sidebars/version-1.4.2-sidebars.json
@@ -0,0 +1,26 @@
+{
+ "tutorialSidebar": [
+ {
+ "type": "autogenerated",
+ "dirName": "."
+ }
+ ],
+ "user_docs": [
+ {
+ "type": "autogenerated",
+ "dirName": "user_docs"
+ }
+ ],
+ "community": [
+ {
+ "type": "autogenerated",
+ "dirName": "community"
+ }
+ ],
+ "sponsor": [
+ {
+ "type": "autogenerated",
+ "dirName": "sponsor"
+ }
+ ]
+}
diff --git a/docs/versions.json b/docs/versions.json
new file mode 100644
index 00000000..4c34c760
--- /dev/null
+++ b/docs/versions.json
@@ -0,0 +1,3 @@
+[
+ "1.4.2"
+]
diff --git a/hippo4j-common/pom.xml b/hippo4j-common/pom.xml
index 36d6d3b1..5f036d55 100644
--- a/hippo4j-common/pom.xml
+++ b/hippo4j-common/pom.xml
@@ -62,5 +62,9 @@
com.github.dozermapper
dozer-core
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+
diff --git a/hippo4j-core/pom.xml b/hippo4j-core/pom.xml
index bd891a49..e9e05f10 100644
--- a/hippo4j-core/pom.xml
+++ b/hippo4j-core/pom.xml
@@ -10,6 +10,11 @@
hippo4j-core
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
org.projectlombok
lombok
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/executor/DynamicThreadPoolExecutor.java b/hippo4j-core/src/main/java/cn/hippo4j/core/executor/DynamicThreadPoolExecutor.java
index 2249fabc..71cc5bed 100644
--- a/hippo4j-core/src/main/java/cn/hippo4j/core/executor/DynamicThreadPoolExecutor.java
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/executor/DynamicThreadPoolExecutor.java
@@ -17,107 +17,226 @@
package cn.hippo4j.core.executor;
-import cn.hippo4j.common.config.ApplicationContextHolder;
-import cn.hippo4j.core.executor.support.AbstractDynamicExecutorSupport;
-import cn.hippo4j.core.proxy.RejectedProxyUtil;
-import cn.hippo4j.core.toolkit.SystemClock;
+import cn.hippo4j.common.toolkit.CollectionUtil;
+import cn.hippo4j.core.plugin.impl.TaskDecoratorPlugin;
+import cn.hippo4j.core.plugin.impl.TaskRejectCountRecordPlugin;
+import cn.hippo4j.core.plugin.impl.TaskTimeoutNotifyAlarmPlugin;
+import cn.hippo4j.core.plugin.impl.ThreadPoolExecutorShutdownPlugin;
+import cn.hippo4j.core.plugin.manager.DefaultThreadPoolPluginManager;
+import cn.hippo4j.core.plugin.manager.DefaultThreadPoolPluginRegistrar;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.DisposableBean;
import org.springframework.core.task.TaskDecorator;
-import java.util.concurrent.*;
+import java.util.Objects;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
/**
* Enhanced dynamic and monitored thread pool.
*/
-public class DynamicThreadPoolExecutor extends AbstractDynamicExecutorSupport {
+@Slf4j
+public class DynamicThreadPoolExecutor extends ExtensibleThreadPoolExecutor implements DisposableBean {
+ /**
+ * wait for tasks to complete on shutdown
+ */
@Getter
@Setter
- private Long executeTimeOut;
-
- @Getter
- @Setter
- private TaskDecorator taskDecorator;
-
- @Getter
- @Setter
- private RejectedExecutionHandler redundancyHandler;
-
- @Getter
- private final String threadPoolId;
-
- @Getter
- private final AtomicLong rejectCount = new AtomicLong();
-
- private final ThreadLocal startTimeThreadLocal = new ThreadLocal<>();
-
- public DynamicThreadPoolExecutor(int corePoolSize,
- int maximumPoolSize,
- long keepAliveTime,
- TimeUnit unit,
- long executeTimeOut,
- boolean waitForTasksToCompleteOnShutdown,
- long awaitTerminationMillis,
+ public boolean waitForTasksToCompleteOnShutdown;
+
+ /**
+ * Creates a new {@code DynamicThreadPoolExecutor} with the given initial parameters.
+ *
+ * @param threadPoolId thread-pool id
+ * @param executeTimeOut execute time out
+ * @param waitForTasksToCompleteOnShutdown wait for tasks to complete on shutdown
+ * @param awaitTerminationMillis await termination millis
+ * @param corePoolSize the number of threads to keep in the pool, even
+ * if they are idle, unless {@code allowCoreThreadTimeOut} is set
+ * @param maximumPoolSize the maximum number of threads to allow in the
+ * pool
+ * @param keepAliveTime when the number of threads is greater than
+ * the core, this is the maximum time that excess idle threads
+ * will wait for new tasks before terminating.
+ * @param unit the time unit for the {@code keepAliveTime} argument
+ * @param blockingQueue the queue to use for holding tasks before they are
+ * executed. This queue will hold only the {@code Runnable}
+ * tasks submitted by the {@code execute} method.
+ * @param threadFactory the factory to use when the executor creates a new thread
+ * @param rejectedExecutionHandler the handler to use when execution is blocked because the thread bounds and queue capacities are reached
+ * @throws IllegalArgumentException if one of the following holds:
+ * {@code corePoolSize < 0}
+ * {@code keepAliveTime < 0}
+ * {@code maximumPoolSize <= 0}
+ * {@code maximumPoolSize < corePoolSize}
+ * @throws NullPointerException if {@code workQueue}
+ * or {@code threadFactory} or {@code handler} is null
+ */
+ public DynamicThreadPoolExecutor(
+ int corePoolSize, int maximumPoolSize,
+ long keepAliveTime, TimeUnit unit,
+ long executeTimeOut, boolean waitForTasksToCompleteOnShutdown, long awaitTerminationMillis,
@NonNull BlockingQueue blockingQueue,
@NonNull String threadPoolId,
@NonNull ThreadFactory threadFactory,
@NonNull RejectedExecutionHandler rejectedExecutionHandler) {
- super(corePoolSize, maximumPoolSize, keepAliveTime, unit, waitForTasksToCompleteOnShutdown, awaitTerminationMillis, blockingQueue, threadPoolId, threadFactory, rejectedExecutionHandler);
- this.threadPoolId = threadPoolId;
- this.executeTimeOut = executeTimeOut;
- // Number of dynamic proxy denial policies.
- RejectedExecutionHandler rejectedProxy = RejectedProxyUtil.createProxy(rejectedExecutionHandler, threadPoolId, rejectCount);
- setRejectedExecutionHandler(rejectedProxy);
- // Redundant fields to avoid reflecting the acquired fields when sending change information.
- redundancyHandler = rejectedExecutionHandler;
+ super(
+ threadPoolId, new DefaultThreadPoolPluginManager(),
+ corePoolSize, maximumPoolSize, keepAliveTime, unit,
+ blockingQueue, threadFactory, rejectedExecutionHandler);
+ log.info("Initializing ExecutorService {}", threadPoolId);
+ this.waitForTasksToCompleteOnShutdown = waitForTasksToCompleteOnShutdown;
+ // init default plugins
+ new DefaultThreadPoolPluginRegistrar(executeTimeOut, awaitTerminationMillis)
+ .doRegister(this);
}
+ /**
+ * Invoked by the containing {@code BeanFactory} on destruction of a bean.
+ *
+ */
@Override
- public void execute(@NonNull Runnable command) {
- if (taskDecorator != null) {
- command = taskDecorator.decorate(command);
+ public void destroy() {
+ if (isWaitForTasksToCompleteOnShutdown()) {
+ super.shutdown();
+ } else {
+ super.shutdownNow();
}
- super.execute(command);
+ getThreadPoolPluginManager().clear();
}
- @Override
- protected void beforeExecute(Thread t, Runnable r) {
- if (executeTimeOut == null || executeTimeOut <= 0) {
- return;
- }
- startTimeThreadLocal.set(SystemClock.now());
+ /**
+ * Get await termination millis.
+ *
+ * @return await termination millis.
+ * @deprecated use {@link ThreadPoolExecutorShutdownPlugin}
+ */
+ @Deprecated
+ public long getAwaitTerminationMillis() {
+ return getPluginOfType(ThreadPoolExecutorShutdownPlugin.PLUGIN_NAME, ThreadPoolExecutorShutdownPlugin.class)
+ .map(ThreadPoolExecutorShutdownPlugin::getAwaitTerminationMillis)
+ .orElse(-1L);
}
- @Override
- protected void afterExecute(Runnable r, Throwable t) {
- Long startTime;
- if ((startTime = startTimeThreadLocal.get()) == null) {
- return;
- }
- try {
- long endTime = SystemClock.now();
- long executeTime;
- boolean executeTimeAlarm = (executeTime = (endTime - startTime)) > executeTimeOut;
- if (executeTimeAlarm && ApplicationContextHolder.getInstance() != null) {
- ThreadPoolNotifyAlarmHandler notifyAlarmHandler = ApplicationContextHolder.getBean(ThreadPoolNotifyAlarmHandler.class);
- if (notifyAlarmHandler != null) {
- notifyAlarmHandler.asyncSendExecuteTimeOutAlarm(threadPoolId, executeTime, executeTimeOut, this);
- }
- }
- } finally {
- startTimeThreadLocal.remove();
- }
+ /**
+ * Set support param.
+ *
+ * @param awaitTerminationMillis await termination millis
+ * @param waitForTasksToCompleteOnShutdown wait for tasks to complete on shutdown
+ * @deprecated use {@link ThreadPoolExecutorShutdownPlugin}
+ */
+ @Deprecated
+ public void setSupportParam(long awaitTerminationMillis, boolean waitForTasksToCompleteOnShutdown) {
+ setWaitForTasksToCompleteOnShutdown(waitForTasksToCompleteOnShutdown);
+ getPluginOfType(ThreadPoolExecutorShutdownPlugin.PLUGIN_NAME, ThreadPoolExecutorShutdownPlugin.class)
+ .ifPresent(processor -> processor.setAwaitTerminationMillis(awaitTerminationMillis));
}
- @Override
- protected ExecutorService initializeExecutor() {
- return this;
+ /**
+ * Get reject count num.
+ *
+ * @return reject count num
+ * @deprecated use {@link TaskRejectCountRecordPlugin}
+ */
+ @Deprecated
+ public Long getRejectCountNum() {
+ return getPluginOfType(TaskRejectCountRecordPlugin.PLUGIN_NAME, TaskRejectCountRecordPlugin.class)
+ .map(TaskRejectCountRecordPlugin::getRejectCountNum)
+ .orElse(-1L);
}
- public Long getRejectCountNum() {
- return rejectCount.get();
+ /**
+ * Get reject count.
+ *
+ * @return reject count num
+ * @deprecated use {@link TaskRejectCountRecordPlugin}
+ */
+ @Deprecated
+ public AtomicLong getRejectCount() {
+ return getPluginOfType(TaskRejectCountRecordPlugin.PLUGIN_NAME, TaskRejectCountRecordPlugin.class)
+ .map(TaskRejectCountRecordPlugin::getRejectCount)
+ .orElse(new AtomicLong(0));
+ }
+
+ /**
+ * Get execute time out.
+ *
+ * @deprecated use {@link TaskTimeoutNotifyAlarmPlugin}
+ */
+ @Deprecated
+ public Long getExecuteTimeOut() {
+ return getPluginOfType(TaskTimeoutNotifyAlarmPlugin.PLUGIN_NAME, TaskTimeoutNotifyAlarmPlugin.class)
+ .map(TaskTimeoutNotifyAlarmPlugin::getExecuteTimeOut)
+ .orElse(-1L);
+ }
+
+ /**
+ * Set execute time out.
+ *
+ * @param executeTimeOut execute time out
+ * @deprecated use {@link TaskTimeoutNotifyAlarmPlugin}
+ */
+ @Deprecated
+ public void setExecuteTimeOut(Long executeTimeOut) {
+ getPluginOfType(TaskTimeoutNotifyAlarmPlugin.PLUGIN_NAME, TaskTimeoutNotifyAlarmPlugin.class)
+ .ifPresent(processor -> processor.setExecuteTimeOut(executeTimeOut));
+ }
+
+ /**
+ * Get {@link TaskDecorator}.
+ *
+ * @deprecated use {@link TaskDecoratorPlugin}
+ */
+ @Deprecated
+ public TaskDecorator getTaskDecorator() {
+ return getPluginOfType(TaskDecoratorPlugin.PLUGIN_NAME, TaskDecoratorPlugin.class)
+ .map(processor -> CollectionUtil.getFirst(processor.getDecorators()))
+ .orElse(null);
+ }
+
+ /**
+ * Set {@link TaskDecorator}.
+ *
+ * @param taskDecorator task decorator
+ * @deprecated use {@link TaskDecoratorPlugin}
+ */
+ @Deprecated
+ public void setTaskDecorator(TaskDecorator taskDecorator) {
+ getPluginOfType(TaskDecoratorPlugin.PLUGIN_NAME, TaskDecoratorPlugin.class)
+ .ifPresent(processor -> {
+ if (Objects.nonNull(taskDecorator)) {
+ processor.clearDecorators();
+ processor.addDecorator(taskDecorator);
+ }
+ });
+ }
+
+ /**
+ * Get rejected execution handler.
+ *
+ * @deprecated use {@link DynamicThreadPoolExecutor#getRejectedExecutionHandler}
+ */
+ @Deprecated
+ public RejectedExecutionHandler getRedundancyHandler() {
+ return getRejectedExecutionHandler();
+ }
+
+ /**
+ * Set rejected execution handler.
+ *
+ * @param handler handler
+ * @deprecated use {@link DynamicThreadPoolExecutor#setRejectedExecutionHandler}
+ */
+ @Deprecated
+ public void setRedundancyHandler(RejectedExecutionHandler handler) {
+ setRejectedExecutionHandler(handler);
}
+
}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/executor/DynamicThreadPoolWrapper.java b/hippo4j-core/src/main/java/cn/hippo4j/core/executor/DynamicThreadPoolWrapper.java
index a99b0b37..8f4d2941 100644
--- a/hippo4j-core/src/main/java/cn/hippo4j/core/executor/DynamicThreadPoolWrapper.java
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/executor/DynamicThreadPoolWrapper.java
@@ -17,7 +17,6 @@
package cn.hippo4j.core.executor;
-import cn.hippo4j.core.executor.support.AbstractDynamicExecutorSupport;
import cn.hippo4j.core.executor.support.CommonDynamicThreadPool;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -26,7 +25,9 @@ import lombok.NoArgsConstructor;
import org.springframework.beans.factory.DisposableBean;
import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
import java.util.concurrent.Future;
+import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
/**
@@ -38,10 +39,27 @@ import java.util.concurrent.ThreadPoolExecutor;
@AllArgsConstructor
public class DynamicThreadPoolWrapper implements DisposableBean {
+ /**
+ * Determine the unique identifier of the thread pool in the project.
+ *
+ * @param tenantId tenant id
+ * @param itemId project id in the team
+ * @param threadPoolId Thread pool identifier under the project
+ */
private String tenantId, itemId, threadPoolId;
+ /**
+ * Whether the thread pool has completed initialization,
+ * and whether to subscribe to server-side configuration change events.
+ *
+ * @param subscribeFlag subscription server configuration id
+ * @param initFlag initial configuration complete flag
+ */
private boolean subscribeFlag, initFlag;
+ /**
+ * Thread pool executor.
+ */
private ThreadPoolExecutor executor;
public DynamicThreadPoolWrapper(String threadPoolId) {
@@ -54,22 +72,70 @@ public class DynamicThreadPoolWrapper implements DisposableBean {
this.subscribeFlag = true;
}
+ /**
+ * Executes the given task sometime in the future. The task
+ * may execute in a new thread or in an existing pooled thread.
+ *
+ * If the task cannot be submitted for execution, either because this
+ * executor has been shutdown or because its capacity has been reached,
+ * the task is handled by the current {@code RejectedExecutionHandler}.
+ *
+ * @param command the task to execute
+ * @throws RejectedExecutionException at discretion of
+ * {@code RejectedExecutionHandler}, if the task
+ * cannot be accepted for execution
+ * @throws NullPointerException if {@code command} is null
+ */
public void execute(Runnable command) {
executor.execute(command);
}
+ /**
+ * Submits a Runnable task for execution and returns a Future
+ * representing that task. The Future's {@code get} method will
+ * return {@code null} upon successful completion.
+ *
+ * @param task the task to submit
+ * @return a Future representing pending completion of the task
+ * @throws RejectedExecutionException if the task cannot be
+ * scheduled for execution
+ * @throws NullPointerException if the task is null
+ */
public Future> submit(Runnable task) {
return executor.submit(task);
}
+ /**
+ * Submits a value-returning task for execution and returns a
+ * Future representing the pending results of the task. The
+ * Future's {@code get} method will return the task's result upon
+ * successful completion.
+ *
+ *
+ * If you would like to immediately block waiting
+ * for a task, you can use constructions of the form
+ * {@code result = exec.submit(aCallable).get();}
+ *
+ *
Note: The {@link Executors} class includes a set of methods
+ * that can convert some other common closure-like objects,
+ * for example, {@link java.security.PrivilegedAction} to
+ * {@link Callable} form so they can be submitted.
+ *
+ * @param task the task to submit
+ * @param the type of the task's result
+ * @return a Future representing pending completion of the task
+ * @throws RejectedExecutionException if the task cannot be
+ * scheduled for execution
+ * @throws NullPointerException if the task is null
+ */
public Future submit(Callable task) {
return executor.submit(task);
}
@Override
public void destroy() throws Exception {
- if (executor instanceof AbstractDynamicExecutorSupport) {
- ((AbstractDynamicExecutorSupport) executor).destroy();
+ if (executor instanceof DynamicThreadPoolExecutor) {
+ ((DynamicThreadPoolExecutor) executor).destroy();
}
}
}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/executor/ExtensibleThreadPoolExecutor.java b/hippo4j-core/src/main/java/cn/hippo4j/core/executor/ExtensibleThreadPoolExecutor.java
new file mode 100644
index 00000000..4bd96b16
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/executor/ExtensibleThreadPoolExecutor.java
@@ -0,0 +1,320 @@
+/*
+ * 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.core.executor;
+
+import cn.hippo4j.core.plugin.*;
+import cn.hippo4j.core.plugin.manager.ThreadPoolPluginManager;
+import cn.hippo4j.core.plugin.manager.ThreadPoolPluginSupport;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.Setter;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.*;
+
+/**
+ * Extensible thread-pool executor.
+ * Support the callback extension points provided on the basis of {@link ThreadPoolExecutor}.
+ * Each extension point corresponds to a different {@link ThreadPoolPlugin} interface,
+ * users can customize plug-ins and implement one or more {@link ThreadPoolPlugin} interface
+ * to enable plugins to sense thread pool behavior and provide extended functions.
+ *
+ * @see ThreadPoolPluginManager
+ * @see ThreadPoolPlugin
+ */
+public class ExtensibleThreadPoolExecutor extends ThreadPoolExecutor implements ThreadPoolPluginSupport {
+
+ /**
+ * thread pool id
+ */
+ @Getter
+ @NonNull
+ private final String threadPoolId;
+
+ /**
+ * action aware registry
+ */
+ @Getter
+ private final ThreadPoolPluginManager threadPoolPluginManager;
+
+ /**
+ * handler wrapper, any changes to the current instance {@link RejectedExecutionHandler} should be made through this wrapper
+ */
+ private final RejectedAwareHandlerWrapper handlerWrapper;
+
+ /**
+ * Creates a new {@code ExtensibleThreadPoolExecutor} with the given initial parameters.
+ *
+ * @param threadPoolId thread-pool id
+ * @param threadPoolPluginManager action aware registry
+ * @param corePoolSize the number of threads to keep in the pool, even
+ * if they are idle, unless {@code allowCoreThreadTimeOut} is set
+ * @param maximumPoolSize the maximum number of threads to allow in the
+ * pool
+ * @param keepAliveTime when the number of threads is greater than
+ * the core, this is the maximum time that excess idle threads
+ * will wait for new tasks before terminating.
+ * @param unit the time unit for the {@code keepAliveTime} argument
+ * @param workQueue the queue to use for holding tasks before they are
+ * executed. This queue will hold only the {@code Runnable}
+ * tasks submitted by the {@code execute} method.
+ * @param threadFactory the factory to use when the executor
+ * creates a new thread
+ * @param handler the handler to use when execution is blocked
+ * because the thread bounds and queue capacities are reached
+ * @throws IllegalArgumentException if one of the following holds:
+ * {@code corePoolSize < 0}
+ * {@code keepAliveTime < 0}
+ * {@code maximumPoolSize <= 0}
+ * {@code maximumPoolSize < corePoolSize}
+ * @throws NullPointerException if {@code workQueue}
+ * or {@code threadFactory} or {@code handler} is null
+ */
+ public ExtensibleThreadPoolExecutor(
+ @NonNull String threadPoolId,
+ @NonNull ThreadPoolPluginManager threadPoolPluginManager,
+ int corePoolSize, int maximumPoolSize,
+ long keepAliveTime, TimeUnit unit,
+ @NonNull BlockingQueue workQueue,
+ @NonNull ThreadFactory threadFactory,
+ @NonNull RejectedExecutionHandler handler) {
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
+
+ // pool extended info
+ this.threadPoolId = threadPoolId;
+ this.threadPoolPluginManager = threadPoolPluginManager;
+
+ // proxy handler to support Aware callback
+ while (handler instanceof RejectedAwareHandlerWrapper) {
+ handler = ((RejectedAwareHandlerWrapper) handler).getHandler();
+ }
+ this.handlerWrapper = new RejectedAwareHandlerWrapper(threadPoolPluginManager, handler);
+ super.setRejectedExecutionHandler(handlerWrapper);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Before calling the parent class method, {@link ExecuteAwarePlugin#beforeExecute} will be called first.
+ *
+ * @param thread the thread that will run task {@code r}
+ * @param runnable the task that will be executed
+ */
+ @Override
+ protected void beforeExecute(Thread thread, Runnable runnable) {
+ Collection executeAwarePluginList = threadPoolPluginManager.getExecuteAwarePluginList();
+ executeAwarePluginList.forEach(aware -> aware.beforeExecute(thread, runnable));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Before calling the superclass method, {@link TaskAwarePlugin#beforeTaskExecute} will be called first.
+ *
+ * @param runnable the task to execute
+ */
+ @Override
+ public void execute(@NonNull Runnable runnable) {
+ Collection taskAwarePluginList = threadPoolPluginManager.getTaskAwarePluginList();
+ for (TaskAwarePlugin taskAwarePlugin : taskAwarePluginList) {
+ runnable = taskAwarePlugin.beforeTaskExecute(runnable);
+ }
+ super.execute(runnable);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * After calling the superclass method, {@link ExecuteAwarePlugin#afterExecute} will be called last.
+ *
+ * @param runnable the runnable that has completed
+ * @param throwable the exception that caused termination, or null if
+ * execution completed normally
+ */
+ @Override
+ protected void afterExecute(Runnable runnable, Throwable throwable) {
+ Collection executeAwarePluginList = threadPoolPluginManager.getExecuteAwarePluginList();
+ executeAwarePluginList.forEach(aware -> aware.afterExecute(runnable, throwable));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Before calling the superclass method,
+ * {@link ShutdownAwarePlugin#beforeShutdown} will be called first.
+ * and then will be call {@link ShutdownAwarePlugin#afterShutdown}
+ *
+ * @throws SecurityException {@inheritDoc}
+ */
+ @Override
+ public void shutdown() {
+ Collection shutdownAwarePluginList = threadPoolPluginManager.getShutdownAwarePluginList();
+ shutdownAwarePluginList.forEach(aware -> aware.beforeShutdown(this));
+ super.shutdown();
+ shutdownAwarePluginList.forEach(aware -> aware.afterShutdown(this, Collections.emptyList()));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Before calling the superclass method,
+ * {@link ShutdownAwarePlugin#beforeShutdown} will be called first.
+ * and then will be call {@link ShutdownAwarePlugin#afterShutdown}
+ *
+ * @throws SecurityException
+ */
+ @Override
+ public List shutdownNow() {
+ Collection shutdownAwarePluginList = threadPoolPluginManager.getShutdownAwarePluginList();
+ shutdownAwarePluginList.forEach(aware -> aware.beforeShutdown(this));
+ List tasks = super.shutdownNow();
+ shutdownAwarePluginList.forEach(aware -> aware.afterShutdown(this, tasks));
+ return tasks;
+ }
+
+ /**
+ * {@inheritDoc}.
+ *
+ * Before calling the superclass method, {@link ShutdownAwarePlugin#afterTerminated} will be called first.
+ */
+ @Override
+ protected void terminated() {
+ super.terminated();
+ Collection shutdownAwarePluginList = threadPoolPluginManager.getShutdownAwarePluginList();
+ shutdownAwarePluginList.forEach(aware -> aware.afterTerminated(this));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Before calling the superclass method, {@link TaskAwarePlugin#beforeTaskCreate} will be called first.
+ *
+ * @param runnable the runnable task being wrapped
+ * @param value the default value for the returned future
+ * @return a {@code RunnableFuture} which, when run, will run the
+ * underlying runnable and which, as a {@code Future}, will yield
+ * the given value as its result and provide for cancellation of
+ * the underlying task
+ * @since 1.6
+ */
+ @Override
+ protected RunnableFuture newTaskFor(Runnable runnable, T value) {
+ Collection taskAwarePluginList = threadPoolPluginManager.getTaskAwarePluginList();
+ for (TaskAwarePlugin taskAwarePlugin : taskAwarePluginList) {
+ runnable = taskAwarePlugin.beforeTaskCreate(this, runnable, value);
+ }
+ return super.newTaskFor(runnable, value);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Before calling the superclass method, {@link TaskAwarePlugin#beforeTaskCreate} will be called first.
+ *
+ * @param callable the callable task being wrapped
+ * @return a {@code RunnableFuture} which, when run, will call the
+ * underlying callable and which, as a {@code Future}, will yield
+ * the callable's result as its result and provide for
+ * cancellation of the underlying task
+ * @since 1.6
+ */
+ @Override
+ protected RunnableFuture newTaskFor(Callable callable) {
+ Collection taskAwarePluginList = threadPoolPluginManager.getTaskAwarePluginList();
+ for (TaskAwarePlugin taskAwarePlugin : taskAwarePluginList) {
+ callable = taskAwarePlugin.beforeTaskCreate(this, callable);
+ }
+ return super.newTaskFor(callable);
+ }
+
+ /**
+ * Sets a new handler for unexecutable tasks.
+ *
+ * @param handler the new handler
+ * @throws NullPointerException if handler is null
+ * @see #getRejectedExecutionHandler
+ */
+ @Override
+ public void setRejectedExecutionHandler(@NonNull RejectedExecutionHandler handler) {
+ while (handler instanceof RejectedAwareHandlerWrapper) {
+ handler = ((RejectedAwareHandlerWrapper) handler).getHandler();
+ }
+ handlerWrapper.setHandler(handler);
+ }
+
+ /**
+ * Returns the current handler for unexecutable tasks.
+ *
+ * @return the current handler
+ * @see #setRejectedExecutionHandler(RejectedExecutionHandler)
+ */
+ @Override
+ public RejectedExecutionHandler getRejectedExecutionHandler() {
+ return handlerWrapper.getHandler();
+ }
+
+ /**
+ * Get thread-pool executor.
+ *
+ * @return thread-pool executor
+ */
+ @Override
+ public ThreadPoolExecutor getThreadPoolExecutor() {
+ return this;
+ }
+
+ /**
+ * Wrapper of original {@link RejectedExecutionHandler} of {@link ThreadPoolExecutor},
+ * It's used to support the {@link RejectedAwarePlugin} on the basis of the {@link RejectedExecutionHandler}.
+ *
+ * @see RejectedAwarePlugin
+ */
+ @AllArgsConstructor
+ private static class RejectedAwareHandlerWrapper implements RejectedExecutionHandler {
+
+ /**
+ * thread-pool action aware registry
+ */
+ private final ThreadPoolPluginManager registry;
+
+ /**
+ * original target
+ */
+ @NonNull
+ @Setter
+ @Getter
+ private RejectedExecutionHandler handler;
+
+ /**
+ * Call {@link RejectedAwarePlugin#beforeRejectedExecution}, then reject the task
+ *
+ * @param r the runnable task requested to be executed
+ * @param executor the executor attempting to execute this task
+ */
+ @Override
+ public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
+ Collection rejectedAwarePluginList = registry.getRejectedAwarePluginList();
+ rejectedAwarePluginList.forEach(aware -> aware.beforeRejectedExecution(r, executor));
+ handler.rejectedExecution(r, executor);
+ }
+
+ }
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/executor/ThreadPoolNotifyAlarmHandler.java b/hippo4j-core/src/main/java/cn/hippo4j/core/executor/ThreadPoolNotifyAlarmHandler.java
index 77237dd4..7b832473 100644
--- a/hippo4j-core/src/main/java/cn/hippo4j/core/executor/ThreadPoolNotifyAlarmHandler.java
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/executor/ThreadPoolNotifyAlarmHandler.java
@@ -22,13 +22,13 @@ import cn.hippo4j.common.toolkit.StringUtil;
import cn.hippo4j.core.executor.manage.GlobalNotifyAlarmManage;
import cn.hippo4j.core.executor.manage.GlobalThreadPoolManage;
import cn.hippo4j.core.executor.support.ThreadPoolBuilder;
-import cn.hippo4j.core.toolkit.IdentifyUtil;
import cn.hippo4j.core.toolkit.ExecutorTraceContextUtil;
-import cn.hippo4j.message.service.Hippo4jSendMessageService;
+import cn.hippo4j.core.toolkit.IdentifyUtil;
import cn.hippo4j.message.enums.NotifyTypeEnum;
-import cn.hippo4j.message.service.ThreadPoolNotifyAlarm;
import cn.hippo4j.message.request.AlarmNotifyRequest;
import cn.hippo4j.message.request.ChangeParameterNotifyRequest;
+import cn.hippo4j.message.service.Hippo4jSendMessageService;
+import cn.hippo4j.message.service.ThreadPoolNotifyAlarm;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -211,9 +211,7 @@ public class ThreadPoolNotifyAlarmHandler implements Runnable, CommandLineRunner
*/
public AlarmNotifyRequest buildAlarmNotifyRequest(ThreadPoolExecutor threadPoolExecutor) {
BlockingQueue blockingQueue = threadPoolExecutor.getQueue();
- RejectedExecutionHandler rejectedExecutionHandler = threadPoolExecutor instanceof DynamicThreadPoolExecutor
- ? ((DynamicThreadPoolExecutor) threadPoolExecutor).getRedundancyHandler()
- : threadPoolExecutor.getRejectedExecutionHandler();
+ RejectedExecutionHandler rejectedExecutionHandler = threadPoolExecutor.getRejectedExecutionHandler();
long rejectCount = threadPoolExecutor instanceof DynamicThreadPoolExecutor
? ((DynamicThreadPoolExecutor) threadPoolExecutor).getRejectCountNum()
: -1L;
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/executor/state/ThreadPoolRunStateHandler.java b/hippo4j-core/src/main/java/cn/hippo4j/core/executor/state/ThreadPoolRunStateHandler.java
index ca9d7eaf..a0405a6e 100644
--- a/hippo4j-core/src/main/java/cn/hippo4j/core/executor/state/ThreadPoolRunStateHandler.java
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/executor/state/ThreadPoolRunStateHandler.java
@@ -23,10 +23,8 @@ import cn.hippo4j.common.toolkit.BeanUtil;
import cn.hippo4j.common.toolkit.ByteConvertUtil;
import cn.hippo4j.common.toolkit.MemoryUtil;
import cn.hippo4j.common.toolkit.StringUtil;
-import cn.hippo4j.core.executor.DynamicThreadPoolExecutor;
import cn.hippo4j.core.executor.DynamicThreadPoolWrapper;
import cn.hippo4j.core.executor.manage.GlobalThreadPoolManage;
-import cn.hippo4j.core.executor.support.AbstractDynamicExecutorSupport;
import cn.hippo4j.core.toolkit.inet.InetUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -66,11 +64,7 @@ public class ThreadPoolRunStateHandler extends AbstractThreadPoolRuntime {
DynamicThreadPoolWrapper executorService = GlobalThreadPoolManage.getExecutorService(threadPoolId);
ThreadPoolExecutor pool = executorService.getExecutor();
String rejectedName;
- if (pool instanceof AbstractDynamicExecutorSupport) {
- rejectedName = ((DynamicThreadPoolExecutor) pool).getRedundancyHandler().getClass().getSimpleName();
- } else {
- rejectedName = pool.getRejectedExecutionHandler().getClass().getSimpleName();
- }
+ rejectedName = pool.getRejectedExecutionHandler().getClass().getSimpleName();
poolRunStateInfo.setRejectedName(rejectedName);
ManyThreadPoolRunStateInfo manyThreadPoolRunStateInfo = BeanUtil.convert(poolRunStateInfo, ManyThreadPoolRunStateInfo.class);
manyThreadPoolRunStateInfo.setIdentify(CLIENT_IDENTIFICATION_VALUE);
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/executor/support/AbstractDynamicExecutorSupport.java b/hippo4j-core/src/main/java/cn/hippo4j/core/executor/support/AbstractDynamicExecutorSupport.java
index cff8087c..8dcf65fa 100644
--- a/hippo4j-core/src/main/java/cn/hippo4j/core/executor/support/AbstractDynamicExecutorSupport.java
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/executor/support/AbstractDynamicExecutorSupport.java
@@ -17,6 +17,7 @@
package cn.hippo4j.core.executor.support;
+import cn.hippo4j.core.plugin.impl.ThreadPoolExecutorShutdownPlugin;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
@@ -25,7 +26,10 @@ import java.util.concurrent.*;
/**
* Dynamic executor configuration support.
+ *
+ * @deprecated use {@link ThreadPoolExecutorShutdownPlugin} to get thread-pool shutdown support
*/
+@Deprecated
@Slf4j
public abstract class AbstractDynamicExecutorSupport extends ThreadPoolExecutor implements InitializingBean, DisposableBean {
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/ExecuteAwarePlugin.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/ExecuteAwarePlugin.java
new file mode 100644
index 00000000..d6c8638a
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/ExecuteAwarePlugin.java
@@ -0,0 +1,48 @@
+/*
+ * 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.core.plugin;
+
+import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor;
+
+/**
+ * Callback during task execution.
+ */
+public interface ExecuteAwarePlugin extends ThreadPoolPlugin {
+
+ /**
+ * Callback before task execution.
+ *
+ * @param thread thread of executing task
+ * @param runnable task
+ * @see ExtensibleThreadPoolExecutor#beforeExecute
+ */
+ default void beforeExecute(Thread thread, Runnable runnable) {
+ }
+
+ /**
+ * Callback after task execution.
+ *
+ * @param runnable runnable
+ * @param throwable exception thrown during execution
+ * @see ExtensibleThreadPoolExecutor#afterExecute
+ */
+ default void afterExecute(Runnable runnable, Throwable throwable) {
+ // do nothing
+ }
+
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/PluginRuntime.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/PluginRuntime.java
new file mode 100644
index 00000000..a4177eb4
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/PluginRuntime.java
@@ -0,0 +1,63 @@
+/*
+ * 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.core.plugin;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Plug in runtime information.
+ */
+@RequiredArgsConstructor
+@Getter
+public class PluginRuntime {
+
+ /**
+ * plugin id
+ */
+ private final String pluginId;
+
+ /**
+ * runtime info
+ */
+ private final List infoList = new ArrayList<>();
+
+ /**
+ * Add a runtime info item.
+ *
+ * @param name name
+ * @param value value
+ * @return runtime info item
+ */
+ public PluginRuntime addInfo(String name, Object value) {
+ infoList.add(new Info(name, value));
+ return this;
+ }
+
+ @Getter
+ @RequiredArgsConstructor
+ public static class Info {
+
+ private final String name;
+ private final Object value;
+ }
+
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/RejectedAwarePlugin.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/RejectedAwarePlugin.java
new file mode 100644
index 00000000..3df9629b
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/RejectedAwarePlugin.java
@@ -0,0 +1,37 @@
+/*
+ * 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.core.plugin;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * Callback when task is rejected.
+ */
+public interface RejectedAwarePlugin extends ThreadPoolPlugin {
+
+ /**
+ * Callback before task is rejected.
+ *
+ * @param runnable task
+ * @param executor executor
+ */
+ default void beforeRejectedExecution(Runnable runnable, ThreadPoolExecutor executor) {
+ // do nothing
+ }
+
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/ShutdownAwarePlugin.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/ShutdownAwarePlugin.java
new file mode 100644
index 00000000..52396077
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/ShutdownAwarePlugin.java
@@ -0,0 +1,63 @@
+/*
+ * 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.core.plugin;
+
+import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor;
+
+import java.util.List;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * Callback before thread-pool shutdown.
+ */
+public interface ShutdownAwarePlugin extends ThreadPoolPlugin {
+
+ /**
+ * Callback before pool shutdown.
+ *
+ * @param executor executor
+ * @see ThreadPoolExecutor#shutdown()
+ * @see ThreadPoolExecutor#shutdownNow()
+ */
+ default void beforeShutdown(ThreadPoolExecutor executor) {
+ // do nothing
+ }
+
+ /**
+ * Callback after pool shutdown.
+ *
+ * @param executor executor
+ * @param remainingTasks remainingTasks, or empty if no tasks left or {@link ThreadPoolExecutor#shutdown()} called
+ * @see ThreadPoolExecutor#shutdown()
+ * @see ThreadPoolExecutor#shutdownNow()
+ */
+ default void afterShutdown(ThreadPoolExecutor executor, List remainingTasks) {
+ // do nothing
+ }
+
+ /**
+ * Callback after pool terminated.
+ *
+ * @param executor executor
+ * @see ThreadPoolExecutor#terminated()
+ */
+ default void afterTerminated(ExtensibleThreadPoolExecutor executor) {
+ // do nothing
+ }
+
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/TaskAwarePlugin.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/TaskAwarePlugin.java
new file mode 100644
index 00000000..33c56599
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/TaskAwarePlugin.java
@@ -0,0 +1,65 @@
+/*
+ * 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.core.plugin;
+
+import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * Callback during task submit in thread-pool.
+ */
+public interface TaskAwarePlugin extends ThreadPoolPlugin {
+
+ /**
+ * Callback during the {@link java.util.concurrent.RunnableFuture} task create in thread-pool.
+ *
+ * @param executor executor
+ * @param runnable original task
+ * @return Tasks that really need to be performed
+ * @see ThreadPoolExecutor#newTaskFor(Runnable, Object)
+ */
+ default Runnable beforeTaskCreate(ThreadPoolExecutor executor, Runnable runnable, V value) {
+ return runnable;
+ }
+
+ /**
+ * Callback during the {@link java.util.concurrent.RunnableFuture} task create in thread-pool.
+ *
+ * @param executor executor
+ * @param future original task
+ * @return Tasks that really need to be performed
+ * @see ThreadPoolExecutor#newTaskFor(Callable)
+ */
+ default Callable beforeTaskCreate(ThreadPoolExecutor executor, Callable future) {
+ return future;
+ }
+
+ /**
+ * Callback when task is execute.
+ *
+ * @param runnable runnable
+ * @return tasks to be execute
+ * @see ExtensibleThreadPoolExecutor#execute
+ */
+ default Runnable beforeTaskExecute(Runnable runnable) {
+ return runnable;
+ }
+
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/ThreadPoolPlugin.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/ThreadPoolPlugin.java
new file mode 100644
index 00000000..76238432
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/ThreadPoolPlugin.java
@@ -0,0 +1,82 @@
+/*
+ * 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.core.plugin;
+
+import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor;
+import cn.hippo4j.core.plugin.manager.ThreadPoolPluginManager;
+import cn.hippo4j.core.plugin.manager.ThreadPoolPluginSupport;
+
+/**
+ * A marker superinterface indicating that
+ * an instance class is eligible to be sense and intercept
+ * some operations of the specific thread-pool instance.
+ *
+ *
Generally, any thread-pool that implements the {@link ThreadPoolPluginSupport}
+ * can be register multiple plugins by {@link ThreadPoolPluginSupport#register},
+ * and the plugin will provide some extension function of original
+ * {@link java.util.concurrent.ThreadPoolExecutor} does not support.
+ *
+ *
During runtime, plugins can dynamically modify some configurable parameters
+ * and provide some runtime information by {@link #getPluginRuntime()}.
+ * When the thread-pool is destroyed, the plugin will also be destroyed.
+ *
+ * @see ExtensibleThreadPoolExecutor
+ * @see ThreadPoolPluginManager
+ * @see TaskAwarePlugin
+ * @see ExecuteAwarePlugin
+ * @see ShutdownAwarePlugin
+ * @see RejectedAwarePlugin
+ */
+public interface ThreadPoolPlugin {
+
+ /**
+ * Get id.
+ *
+ * @return id
+ */
+ String getId();
+
+ /**
+ * Callback when plugin register into manager
+ *
+ * @see ThreadPoolPluginManager#register
+ */
+ default void start() {
+ // do nothing
+ }
+
+ /**
+ * Callback when plugin unregister from manager
+ *
+ * @see ThreadPoolPluginManager#unregister
+ * @see ThreadPoolPluginManager#clear
+ */
+ default void stop() {
+ // do nothing
+ }
+
+ /**
+ * Get plugin runtime info.
+ *
+ * @return plugin runtime info
+ */
+ default PluginRuntime getPluginRuntime() {
+ return new PluginRuntime(getId());
+ }
+
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/AbstractTaskTimerPlugin.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/AbstractTaskTimerPlugin.java
new file mode 100644
index 00000000..4a42fef3
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/AbstractTaskTimerPlugin.java
@@ -0,0 +1,88 @@
+/*
+ * 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.core.plugin.impl;
+
+import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor;
+import cn.hippo4j.core.plugin.ExecuteAwarePlugin;
+import cn.hippo4j.core.toolkit.SystemClock;
+
+import java.util.Optional;
+
+/**
+ *
An abstract task execution time recording plugin
+ * for thread-safe statistics the execution time of tasks.
+ *
+ *
Must override {@link #processTaskTime} to define the processing logic for task execution time.
+ * Default time precision is milliseconds, may override {@link #currentTime} to redefine the time precision.
+ *
+ * @see TaskTimeRecordPlugin
+ * @see TaskTimeoutNotifyAlarmPlugin
+ */
+public abstract class AbstractTaskTimerPlugin implements ExecuteAwarePlugin {
+
+ /**
+ * start times of executed tasks
+ */
+ private final ThreadLocal startTimes = new ThreadLocal<>();
+
+ /**
+ * Record the time when the worker thread starts executing the task.
+ *
+ * @param thread thread of executing task
+ * @param runnable task
+ * @see ExtensibleThreadPoolExecutor#beforeExecute
+ */
+ @Override
+ public final void beforeExecute(Thread thread, Runnable runnable) {
+ startTimes.set(currentTime());
+ }
+
+ /**
+ * Record the total time for the worker thread to complete the task, and update the time record.
+ *
+ * @param runnable runnable
+ * @param throwable exception thrown during execution
+ */
+ @Override
+ public final void afterExecute(Runnable runnable, Throwable throwable) {
+ try {
+ Optional.ofNullable(startTimes.get())
+ .map(startTime -> currentTime() - startTime)
+ .ifPresent(this::processTaskTime);
+ } finally {
+ startTimes.remove();
+ }
+ }
+
+ /**
+ * Get the current time.
+ *
+ * @return current time
+ */
+ protected long currentTime() {
+ return SystemClock.now();
+ }
+
+ /**
+ * Processing the execution time of the task.
+ *
+ * @param taskExecuteTime execute time of task
+ */
+ protected abstract void processTaskTime(long taskExecuteTime);
+
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/TaskDecoratorPlugin.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/TaskDecoratorPlugin.java
new file mode 100644
index 00000000..99212e18
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/TaskDecoratorPlugin.java
@@ -0,0 +1,105 @@
+/*
+ * 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.core.plugin.impl;
+
+import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor;
+import cn.hippo4j.core.plugin.PluginRuntime;
+import cn.hippo4j.core.plugin.TaskAwarePlugin;
+import lombok.Getter;
+import lombok.NonNull;
+import org.springframework.core.task.TaskDecorator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Decorate tasks when they are submitted to thread-pool.
+ */
+public class TaskDecoratorPlugin implements TaskAwarePlugin {
+
+ public static final String PLUGIN_NAME = "task-decorator-plugin";
+
+ /**
+ * Get id.
+ *
+ * @return id
+ */
+ @Override
+ public String getId() {
+ return PLUGIN_NAME;
+ }
+
+ /**
+ * decorators
+ */
+ @Getter
+ private final List decorators = new ArrayList<>();
+
+ /**
+ * Callback when task is executed.
+ *
+ * @param runnable runnable
+ * @return tasks to be execute
+ * @see ExtensibleThreadPoolExecutor#execute
+ */
+ @Override
+ public Runnable beforeTaskExecute(Runnable runnable) {
+ for (TaskDecorator decorator : decorators) {
+ runnable = decorator.decorate(runnable);
+ }
+ return runnable;
+ }
+
+ /**
+ * Get plugin runtime info.
+ *
+ * @return plugin runtime info
+ */
+ @Override
+ public PluginRuntime getPluginRuntime() {
+ return new PluginRuntime(getId())
+ .addInfo("decorators", decorators);
+ }
+
+ /**
+ * Add a decorator
+ *
+ * @param decorator decorator
+ */
+ public void addDecorator(@NonNull TaskDecorator decorator) {
+ decorators.remove(decorator);
+ decorators.add(decorator);
+ }
+
+ /**
+ * Clear all decorators
+ *
+ */
+ public void clearDecorators() {
+ decorators.clear();
+ }
+
+ /**
+ * Remove decorators
+ *
+ */
+ public void removeDecorator(TaskDecorator decorator) {
+ decorators.remove(decorator);
+ }
+
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/TaskRejectCountRecordPlugin.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/TaskRejectCountRecordPlugin.java
new file mode 100644
index 00000000..0f478911
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/TaskRejectCountRecordPlugin.java
@@ -0,0 +1,83 @@
+/*
+ * 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.core.plugin.impl;
+
+import cn.hippo4j.core.plugin.PluginRuntime;
+import cn.hippo4j.core.plugin.RejectedAwarePlugin;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Record the number of tasks rejected by the thread pool.
+ */
+public class TaskRejectCountRecordPlugin implements RejectedAwarePlugin {
+
+ public static final String PLUGIN_NAME = "task-reject-count-record-plugin";
+
+ /**
+ * Get id.
+ *
+ * @return id
+ */
+ @Override
+ public String getId() {
+ return PLUGIN_NAME;
+ }
+
+ /**
+ * rejection count
+ */
+ @Setter
+ @Getter
+ private AtomicLong rejectCount = new AtomicLong(0);
+
+ /**
+ * Get plugin runtime info.
+ *
+ * @return plugin runtime info
+ */
+ @Override
+ public PluginRuntime getPluginRuntime() {
+ return new PluginRuntime(getId())
+ .addInfo("rejectCount", getRejectCountNum());
+ }
+
+ /**
+ * Record rejection count.
+ *
+ * @param r task
+ * @param executor executor
+ */
+ @Override
+ public void beforeRejectedExecution(Runnable r, ThreadPoolExecutor executor) {
+ rejectCount.incrementAndGet();
+ }
+
+ /**
+ * Get reject count num
+ *
+ * @return reject count num
+ */
+ public Long getRejectCountNum() {
+ return rejectCount.get();
+ }
+
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/TaskRejectNotifyAlarmPlugin.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/TaskRejectNotifyAlarmPlugin.java
new file mode 100644
index 00000000..6b865642
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/TaskRejectNotifyAlarmPlugin.java
@@ -0,0 +1,61 @@
+/*
+ * 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.core.plugin.impl;
+
+import cn.hippo4j.common.config.ApplicationContextHolder;
+import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor;
+import cn.hippo4j.core.executor.ThreadPoolNotifyAlarmHandler;
+import cn.hippo4j.core.plugin.RejectedAwarePlugin;
+
+import java.util.Optional;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * Send alert notification when a task is rejected.
+ */
+public class TaskRejectNotifyAlarmPlugin implements RejectedAwarePlugin {
+
+ public static final String PLUGIN_NAME = "task-reject-notify-alarm-plugin";
+
+ /**
+ * Get id.
+ *
+ * @return id
+ */
+ @Override
+ public String getId() {
+ return PLUGIN_NAME;
+ }
+
+ /**
+ * Callback before task is rejected.
+ *
+ * @param runnable task
+ * @param executor executor
+ */
+ @Override
+ public void beforeRejectedExecution(Runnable runnable, ThreadPoolExecutor executor) {
+ if (!(executor instanceof ExtensibleThreadPoolExecutor)) {
+ return;
+ }
+ String threadPoolId = ((ExtensibleThreadPoolExecutor) executor).getThreadPoolId();
+ Optional.ofNullable(ApplicationContextHolder.getInstance())
+ .map(context -> context.getBean(ThreadPoolNotifyAlarmHandler.class))
+ .ifPresent(handler -> handler.asyncSendRejectedAlarm(threadPoolId));
+ }
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/TaskTimeRecordPlugin.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/TaskTimeRecordPlugin.java
new file mode 100644
index 00000000..0bb029c2
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/TaskTimeRecordPlugin.java
@@ -0,0 +1,171 @@
+/*
+ * 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.core.plugin.impl;
+
+import cn.hippo4j.core.plugin.PluginRuntime;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * Record task execution time indicator.
+ */
+@RequiredArgsConstructor
+public class TaskTimeRecordPlugin extends AbstractTaskTimerPlugin {
+
+ public static final String PLUGIN_NAME = "task-time-record-plugin";
+
+ /**
+ * Lock instance.
+ */
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+
+ /**
+ * Total execution milli time of all tasks.
+ */
+ private long totalTaskTimeMillis = 0L;
+
+ /**
+ * Maximum task milli execution time, default -1.
+ */
+ private long maxTaskTimeMillis = -1L;
+
+ /**
+ * Minimal task milli execution time, default -1.
+ */
+ private long minTaskTimeMillis = -1L;
+
+ /**
+ * Count of completed task.
+ */
+ private long taskCount = 0L;
+
+ /**
+ * Get id.
+ *
+ * @return id
+ */
+ @Override
+ public String getId() {
+ return PLUGIN_NAME;
+ }
+
+ /**
+ * Get plugin runtime info.
+ *
+ * @return plugin runtime info
+ */
+ @Override
+ public PluginRuntime getPluginRuntime() {
+ Summary summary = summarize();
+ return new PluginRuntime(getId())
+ .addInfo("taskCount", summary.getTaskCount())
+ .addInfo("minTaskTime", summary.getMinTaskTimeMillis() + "ms")
+ .addInfo("maxTaskTime", summary.getMaxTaskTimeMillis() + "ms")
+ .addInfo("totalTaskTime", summary.getTotalTaskTimeMillis() + "ms")
+ .addInfo("avgTaskTime", summary.getAvgTaskTimeMillis() + "ms");
+ }
+
+ /**
+ * Refresh time indicators of the current instance.
+ *
+ * @param taskExecuteTime execute time of task
+ */
+ @Override
+ protected void processTaskTime(long taskExecuteTime) {
+ Lock writeLock = lock.writeLock();
+ writeLock.lock();
+ try {
+ if (taskCount == 0) {
+ maxTaskTimeMillis = taskExecuteTime;
+ minTaskTimeMillis = taskExecuteTime;
+ } else {
+ maxTaskTimeMillis = Math.max(taskExecuteTime, maxTaskTimeMillis);
+ minTaskTimeMillis = Math.min(taskExecuteTime, minTaskTimeMillis);
+ }
+ taskCount = taskCount + 1;
+ totalTaskTimeMillis += taskExecuteTime;
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ /**
+ * Get the summary statistics of the instance at the current time.
+ *
+ * @return data snapshot
+ */
+ public Summary summarize() {
+ Lock readLock = lock.readLock();
+ Summary statistics;
+ readLock.lock();
+ try {
+ statistics = new Summary(
+ this.totalTaskTimeMillis,
+ this.maxTaskTimeMillis,
+ this.minTaskTimeMillis,
+ this.taskCount);
+ } finally {
+ readLock.unlock();
+ }
+ return statistics;
+ }
+
+ /**
+ * Summary statistics of SyncTimeRecorder instance at a certain time.
+ */
+ @Getter
+ @RequiredArgsConstructor
+ public static class Summary {
+
+ /**
+ * Total execution nano time of all tasks.
+ */
+ private final long totalTaskTimeMillis;
+
+ /**
+ * Maximum task nano execution time.
+ */
+ private final long maxTaskTimeMillis;
+
+ /**
+ * Minimal task nano execution time.
+ */
+ private final long minTaskTimeMillis;
+
+ /**
+ * Count of completed task.
+ */
+ private final long taskCount;
+
+ /**
+ * Get the avg task time in milliseconds.
+ *
+ * @return avg task time
+ */
+ public long getAvgTaskTimeMillis() {
+ long totalTaskCount = getTaskCount();
+ return totalTaskCount > 0L ? getTotalTaskTimeMillis() / totalTaskCount : -1;
+ }
+
+ }
+
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/TaskTimeoutNotifyAlarmPlugin.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/TaskTimeoutNotifyAlarmPlugin.java
new file mode 100644
index 00000000..4a566f17
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/TaskTimeoutNotifyAlarmPlugin.java
@@ -0,0 +1,78 @@
+/*
+ * 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.core.plugin.impl;
+
+import cn.hippo4j.common.config.ApplicationContextHolder;
+import cn.hippo4j.core.executor.ThreadPoolNotifyAlarmHandler;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Optional;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * Send alarm notification when the execution time exceeds the threshold.
+ */
+@AllArgsConstructor
+public class TaskTimeoutNotifyAlarmPlugin extends AbstractTaskTimerPlugin {
+
+ public static final String PLUGIN_NAME = "task-timeout-notify-alarm-plugin";
+
+ /**
+ * threadPoolId
+ */
+ private final String threadPoolId;
+
+ @Getter
+ @Setter
+ private Long executeTimeOut;
+
+ /**
+ * thread-pool
+ */
+ private final ThreadPoolExecutor threadPoolExecutor;
+
+ /**
+ * Get id.
+ *
+ * @return id
+ */
+ @Override
+ public String getId() {
+ return PLUGIN_NAME;
+ }
+
+ /**
+ * Check whether the task execution time exceeds {@link #executeTimeOut},
+ * if it exceeds this time, send an alarm notification.
+ *
+ * @param taskExecuteTime execute time of task
+ */
+ @Override
+ protected void processTaskTime(long taskExecuteTime) {
+ if (taskExecuteTime <= executeTimeOut) {
+ return;
+ }
+ Optional.ofNullable(ApplicationContextHolder.getInstance())
+ .map(context -> context.getBean(ThreadPoolNotifyAlarmHandler.class))
+ .ifPresent(handler -> handler.asyncSendExecuteTimeOutAlarm(
+ threadPoolId, taskExecuteTime, executeTimeOut, threadPoolExecutor));
+ }
+
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/ThreadPoolExecutorShutdownPlugin.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/ThreadPoolExecutorShutdownPlugin.java
new file mode 100644
index 00000000..114f2971
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/impl/ThreadPoolExecutorShutdownPlugin.java
@@ -0,0 +1,145 @@
+/*
+ * 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.core.plugin.impl;
+
+import cn.hippo4j.common.toolkit.CollectionUtil;
+import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor;
+import cn.hippo4j.core.plugin.PluginRuntime;
+import cn.hippo4j.core.plugin.ShutdownAwarePlugin;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.List;
+import java.util.concurrent.*;
+
+/**
+ * After the thread pool calls {@link ThreadPoolExecutor#shutdown()} or {@link ThreadPoolExecutor#shutdownNow()}.
+ * Cancel the remaining tasks in the pool, then wait for the thread pool to terminate until
+ * the blocked main thread has timed out or the thread pool has completely terminated.
+ */
+@Accessors(chain = true)
+@Getter
+@Slf4j
+@AllArgsConstructor
+public class ThreadPoolExecutorShutdownPlugin implements ShutdownAwarePlugin {
+
+ public static final String PLUGIN_NAME = "thread-pool-executor-shutdown-plugin";
+
+ /**
+ * Get id.
+ *
+ * @return id
+ */
+ @Override
+ public String getId() {
+ return PLUGIN_NAME;
+ }
+
+ /**
+ * await termination millis
+ */
+ @Setter
+ public long awaitTerminationMillis;
+
+ /**
+ * Callback before pool shutdown.
+ *
+ * @param executor executor
+ */
+ @Override
+ public void beforeShutdown(ThreadPoolExecutor executor) {
+ if (executor instanceof ExtensibleThreadPoolExecutor) {
+ ExtensibleThreadPoolExecutor dynamicThreadPoolExecutor = (ExtensibleThreadPoolExecutor) executor;
+ String threadPoolId = dynamicThreadPoolExecutor.getThreadPoolId();
+ if (log.isInfoEnabled()) {
+ log.info("Before shutting down ExecutorService {}", threadPoolId);
+ }
+ }
+ }
+
+ /**
+ * Callback after pool shutdown.
+ * cancel the remaining tasks,
+ * then wait for pool to terminate according {@link #awaitTerminationMillis} if necessary.
+ *
+ * @param executor executor
+ * @param remainingTasks remainingTasks
+ */
+ @Override
+ public void afterShutdown(ThreadPoolExecutor executor, List remainingTasks) {
+ if (executor instanceof ExtensibleThreadPoolExecutor) {
+ ExtensibleThreadPoolExecutor pool = (ExtensibleThreadPoolExecutor) executor;
+ if (CollectionUtil.isNotEmpty(remainingTasks)) {
+ remainingTasks.forEach(this::cancelRemainingTask);
+ }
+ awaitTerminationIfNecessary(pool);
+ }
+ }
+
+ /**
+ * Get plugin runtime info.
+ *
+ * @return plugin runtime info
+ */
+ @Override
+ public PluginRuntime getPluginRuntime() {
+ return new PluginRuntime(getId())
+ .addInfo("awaitTerminationMillis", awaitTerminationMillis);
+ }
+
+ /**
+ * Cancel the given remaining task which never commended execution,
+ * as returned from {@link ExecutorService#shutdownNow()}.
+ *
+ * @param task the task to cancel (typically a {@link RunnableFuture})
+ * @see RunnableFuture#cancel(boolean)
+ * @since 5.0.5
+ */
+ protected void cancelRemainingTask(Runnable task) {
+ if (task instanceof Future) {
+ ((Future>) task).cancel(true);
+ }
+ }
+
+ /**
+ * Wait for the executor to terminate, according to the value of {@link #awaitTerminationMillis}.
+ */
+ private void awaitTerminationIfNecessary(ExtensibleThreadPoolExecutor executor) {
+ String threadPoolId = executor.getThreadPoolId();
+ if (this.awaitTerminationMillis <= 0) {
+ return;
+ }
+ try {
+ boolean isTerminated = executor.awaitTermination(this.awaitTerminationMillis, TimeUnit.MILLISECONDS);
+ if (!isTerminated && log.isWarnEnabled()) {
+ log.warn("Timed out while waiting for executor {} to terminate.", threadPoolId);
+ } else {
+ log.info("ExecutorService {} has been shutdowned.", threadPoolId);
+ }
+ } catch (InterruptedException ex) {
+ if (log.isWarnEnabled()) {
+ log.warn("Interrupted while waiting for executor {} to terminate.", threadPoolId);
+ }
+ Thread.currentThread().interrupt();
+ }
+ }
+
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/DefaultThreadPoolPluginManager.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/DefaultThreadPoolPluginManager.java
new file mode 100644
index 00000000..50b220d5
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/DefaultThreadPoolPluginManager.java
@@ -0,0 +1,318 @@
+/*
+ * 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.core.plugin.manager;
+
+import cn.hippo4j.common.toolkit.Assert;
+import cn.hippo4j.core.plugin.*;
+import lombok.NonNull;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * The default implementation of {@link ThreadPoolPluginManager}.
+ * Provide basic {@link ThreadPoolPlugin} registration, logout and acquisition functions.
+ * Most APIs ensure limited thread-safe.
+ *
+ *
Usually registered to {@link cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor},
+ * or bound to an {@link java.util.concurrent.ThreadPoolExecutor} instance through {@link ThreadPoolPluginSupport}
+ * to support its plugin based extension functions.
+ *
+ *
NOTE:
+ * When the list of plugins is obtained through the {@code getXXX} method of manager, the list is not immutable.
+ * This means that until actually start iterating over the list,
+ * registering or unregistering plugins through the manager will affect the results of the iteration.
+ * Therefore, we should try to ensure that get the latest plugin list from the manager before each use.
+ *
+ * @see cn.hippo4j.core.executor.DynamicThreadPoolExecutor
+ * @see cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor
+ */
+public class DefaultThreadPoolPluginManager implements ThreadPoolPluginManager {
+
+ /**
+ * lock of this instance
+ */
+ private final ReadWriteLock instanceLock = new ReentrantReadWriteLock();
+
+ /**
+ * Registered {@link ThreadPoolPlugin}.
+ */
+ private final Map registeredPlugins = new ConcurrentHashMap<>(16);
+
+ /**
+ * Registered {@link TaskAwarePlugin}.
+ */
+ private final List taskAwarePluginList = new CopyOnWriteArrayList<>();
+
+ /**
+ * Registered {@link ExecuteAwarePlugin}.
+ */
+ private final List executeAwarePluginList = new CopyOnWriteArrayList<>();
+
+ /**
+ * Registered {@link RejectedAwarePlugin}.
+ */
+ private final List rejectedAwarePluginList = new CopyOnWriteArrayList<>();
+
+ /**
+ * Registered {@link ShutdownAwarePlugin}.
+ */
+ private final List shutdownAwarePluginList = new CopyOnWriteArrayList<>();
+
+ /**
+ * Clear all.
+ */
+ @Override
+ public synchronized void clear() {
+ Lock writeLock = instanceLock.writeLock();
+ writeLock.lock();
+ try {
+ Collection plugins = registeredPlugins.values();
+ registeredPlugins.clear();
+ taskAwarePluginList.clear();
+ executeAwarePluginList.clear();
+ rejectedAwarePluginList.clear();
+ shutdownAwarePluginList.clear();
+ plugins.forEach(ThreadPoolPlugin::stop);
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ /**
+ * Register a {@link ThreadPoolPlugin}
+ *
+ * @param plugin plugin
+ * @throws IllegalArgumentException thrown when a plugin with the same {@link ThreadPoolPlugin#getId()} already exists in the registry
+ * @see ThreadPoolPlugin#getId()
+ */
+ @Override
+ public void register(@NonNull ThreadPoolPlugin plugin) {
+ Lock writeLock = instanceLock.writeLock();
+ writeLock.lock();
+ try {
+ String id = plugin.getId();
+ Assert.isTrue(!isRegistered(id), "The plugin with id [" + id + "] has been registered");
+
+ // register plugin
+ registeredPlugins.put(id, plugin);
+ // quick index
+ if (plugin instanceof TaskAwarePlugin) {
+ taskAwarePluginList.add((TaskAwarePlugin) plugin);
+ }
+ if (plugin instanceof ExecuteAwarePlugin) {
+ executeAwarePluginList.add((ExecuteAwarePlugin) plugin);
+ }
+ if (plugin instanceof RejectedAwarePlugin) {
+ rejectedAwarePluginList.add((RejectedAwarePlugin) plugin);
+ }
+ if (plugin instanceof ShutdownAwarePlugin) {
+ shutdownAwarePluginList.add((ShutdownAwarePlugin) plugin);
+ }
+ plugin.start();
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ /**
+ * Register plugin if it's not registered.
+ *
+ * @param plugin plugin
+ * @return return true if successful register new plugin, false otherwise
+ */
+ @Override
+ public boolean tryRegister(ThreadPoolPlugin plugin) {
+ Lock writeLock = instanceLock.writeLock();
+ writeLock.lock();
+ try {
+ if (registeredPlugins.containsKey(plugin.getId())) {
+ return false;
+ }
+ register(plugin);
+ return true;
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ /**
+ * Unregister {@link ThreadPoolPlugin}
+ *
+ * @param pluginId plugin id
+ */
+ @Override
+ public void unregister(String pluginId) {
+ Lock writeLock = instanceLock.writeLock();
+ writeLock.lock();
+ try {
+ Optional.ofNullable(pluginId)
+ .map(registeredPlugins::remove)
+ .ifPresent(plugin -> {
+ // remove quick index if necessary
+ if (plugin instanceof TaskAwarePlugin) {
+ taskAwarePluginList.remove(plugin);
+ }
+ if (plugin instanceof ExecuteAwarePlugin) {
+ executeAwarePluginList.remove(plugin);
+ }
+ if (plugin instanceof RejectedAwarePlugin) {
+ rejectedAwarePluginList.remove(plugin);
+ }
+ if (plugin instanceof ShutdownAwarePlugin) {
+ shutdownAwarePluginList.remove(plugin);
+ }
+ plugin.stop();
+ });
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ /**
+ * Get all registered plugins.
+ *
+ * @return plugins
+ * @apiNote Be sure to avoid directly modifying returned collection instances,
+ * otherwise, unexpected results may be obtained through the manager
+ */
+ @Override
+ public Collection getAllPlugins() {
+ Lock readLock = instanceLock.readLock();
+ readLock.lock();
+ try {
+ return registeredPlugins.values();
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ /**
+ * Whether the {@link ThreadPoolPlugin} has been registered.
+ *
+ * @param pluginId plugin id
+ * @return ture if target has been registered, false otherwise
+ */
+ @Override
+ public boolean isRegistered(String pluginId) {
+ Lock readLock = instanceLock.readLock();
+ readLock.lock();
+ try {
+ return registeredPlugins.containsKey(pluginId);
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ /**
+ * Get {@link ThreadPoolPlugin}
+ *
+ * @param pluginId plugin id
+ * @param plugin type
+ * @return {@link ThreadPoolPlugin}, null if unregister
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Optional getPlugin(String pluginId) {
+ Lock readLock = instanceLock.readLock();
+ readLock.lock();
+ try {
+ return (Optional) Optional.ofNullable(registeredPlugins.get(pluginId));
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ /**
+ * Get execute plugin list.
+ *
+ * @return {@link ExecuteAwarePlugin}
+ */
+ @Override
+ public Collection getExecuteAwarePluginList() {
+ Lock readLock = instanceLock.readLock();
+ readLock.lock();
+ try {
+ return executeAwarePluginList;
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ /**
+ * Get rejected plugin list.
+ *
+ * @return {@link RejectedAwarePlugin}
+ * @apiNote Be sure to avoid directly modifying returned collection instances,
+ * otherwise, unexpected results may be obtained through the manager
+ */
+ @Override
+ public Collection getRejectedAwarePluginList() {
+ Lock readLock = instanceLock.readLock();
+ readLock.lock();
+ try {
+ return rejectedAwarePluginList;
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ /**
+ * Get shutdown plugin list.
+ *
+ * @return {@link ShutdownAwarePlugin}
+ * @apiNote Be sure to avoid directly modifying returned collection instances,
+ * otherwise, unexpected results may be obtained through the manager
+ */
+ @Override
+ public Collection getShutdownAwarePluginList() {
+ Lock readLock = instanceLock.readLock();
+ readLock.lock();
+ try {
+ return shutdownAwarePluginList;
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ /**
+ * Get shutdown plugin list.
+ *
+ * @return {@link ShutdownAwarePlugin}
+ * @apiNote Be sure to avoid directly modifying returned collection instances,
+ * otherwise, unexpected results may be obtained through the manager
+ */
+ @Override
+ public Collection getTaskAwarePluginList() {
+ Lock readLock = instanceLock.readLock();
+ readLock.lock();
+ try {
+ return taskAwarePluginList;
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/DefaultThreadPoolPluginRegistrar.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/DefaultThreadPoolPluginRegistrar.java
new file mode 100644
index 00000000..211c33a9
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/DefaultThreadPoolPluginRegistrar.java
@@ -0,0 +1,77 @@
+/*
+ * 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.core.plugin.manager;
+
+import cn.hippo4j.core.plugin.ThreadPoolPlugin;
+import cn.hippo4j.core.plugin.impl.*;
+import lombok.AllArgsConstructor;
+import lombok.NoArgsConstructor;
+
+/**
+ * Register default {@link ThreadPoolPlugin}.
+ *
+ * @see TaskDecoratorPlugin
+ * @see TaskTimeoutNotifyAlarmPlugin
+ * @see TaskRejectCountRecordPlugin
+ * @see TaskRejectNotifyAlarmPlugin
+ * @see ThreadPoolExecutorShutdownPlugin
+ */
+@NoArgsConstructor
+@AllArgsConstructor
+public class DefaultThreadPoolPluginRegistrar implements ThreadPoolPluginRegistrar {
+
+ public static final String REGISTRAR_NAME = "DefaultThreadPoolPluginRegistrar";
+
+ /**
+ * execute time out
+ */
+ private long executeTimeOut;
+
+ /**
+ * await termination millis
+ */
+ private long awaitTerminationMillis;
+
+ /**
+ * Get id.
+ *
+ * @return id
+ */
+ @Override
+ public String getId() {
+ return REGISTRAR_NAME;
+ }
+
+ /**
+ * Create and register plugin for the specified thread-pool instance.
+ *
+ * @param support thread pool plugin manager delegate
+ */
+ @Override
+ public void doRegister(ThreadPoolPluginSupport support) {
+ // callback when task execute
+ support.register(new TaskDecoratorPlugin());
+ support.register(new TaskTimeoutNotifyAlarmPlugin(support.getThreadPoolId(), executeTimeOut, support.getThreadPoolExecutor()));
+ // callback when task rejected
+ support.register(new TaskRejectCountRecordPlugin());
+ support.register(new TaskRejectNotifyAlarmPlugin());
+ // callback when pool shutdown
+ support.register(new ThreadPoolExecutorShutdownPlugin(awaitTerminationMillis));
+ }
+
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/EmptyThreadPoolPluginManager.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/EmptyThreadPoolPluginManager.java
new file mode 100644
index 00000000..dff975b4
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/EmptyThreadPoolPluginManager.java
@@ -0,0 +1,154 @@
+/*
+ * 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.core.plugin.manager;
+
+import cn.hippo4j.core.plugin.*;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Optional;
+
+/**
+ * Empty thread pool plugin manager.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class EmptyThreadPoolPluginManager implements ThreadPoolPluginManager {
+
+ /**
+ * default instance
+ */
+ public static final EmptyThreadPoolPluginManager INSTANCE = new EmptyThreadPoolPluginManager();
+
+ /**
+ * Clear all.
+ */
+ @Override
+ public void clear() {
+ // do nothing
+ }
+
+ /**
+ * Get all registered plugins.
+ *
+ * @return plugins
+ */
+ @Override
+ public Collection getAllPlugins() {
+ return Collections.emptyList();
+ }
+
+ /**
+ * Register a {@link ThreadPoolPlugin}
+ *
+ * @param plugin plugin
+ * @throws IllegalArgumentException thrown when a plugin with the same {@link ThreadPoolPlugin#getId()}
+ * already exists in the registry
+ * @see ThreadPoolPlugin#getId()
+ */
+ @Override
+ public void register(ThreadPoolPlugin plugin) {
+ // do nothing
+ }
+
+ /**
+ * Register plugin if it's not registered.
+ *
+ * @param plugin plugin
+ * @return return true if successful register new plugin, false otherwise
+ */
+ @Override
+ public boolean tryRegister(ThreadPoolPlugin plugin) {
+ return false;
+ }
+
+ /**
+ * Whether the {@link ThreadPoolPlugin} has been registered.
+ *
+ * @param pluginId plugin id
+ * @return ture if target has been registered, false otherwise
+ */
+ @Override
+ public boolean isRegistered(String pluginId) {
+ return false;
+ }
+
+ /**
+ * Unregister {@link ThreadPoolPlugin}
+ *
+ * @param pluginId plugin id
+ */
+ @Override
+ public void unregister(String pluginId) {
+ // do nothing
+ }
+
+ /**
+ * Get {@link ThreadPoolPlugin}
+ *
+ * @param pluginId plugin id
+ * @return {@link ThreadPoolPlugin}
+ * @throws ClassCastException thrown when the object obtained by name cannot be converted to target type
+ */
+ @Override
+ public Optional getPlugin(String pluginId) {
+ return Optional.empty();
+ }
+
+ /**
+ * Get execute aware plugin list.
+ *
+ * @return {@link ExecuteAwarePlugin}
+ */
+ @Override
+ public Collection getExecuteAwarePluginList() {
+ return Collections.emptyList();
+ }
+
+ /**
+ * Get rejected aware plugin list.
+ *
+ * @return {@link RejectedAwarePlugin}
+ */
+ @Override
+ public Collection getRejectedAwarePluginList() {
+ return Collections.emptyList();
+ }
+
+ /**
+ * Get shutdown aware plugin list.
+ *
+ * @return {@link ShutdownAwarePlugin}
+ */
+ @Override
+ public Collection getShutdownAwarePluginList() {
+ return Collections.emptyList();
+ }
+
+ /**
+ * Get shutdown aware plugin list.
+ *
+ * @return {@link ShutdownAwarePlugin}
+ */
+ @Override
+ public Collection getTaskAwarePluginList() {
+ return Collections.emptyList();
+ }
+
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginManager.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginManager.java
new file mode 100644
index 00000000..dd2a7777
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginManager.java
@@ -0,0 +1,176 @@
+/*
+ * 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.core.plugin.manager;
+
+import cn.hippo4j.core.plugin.*;
+
+import java.util.Collection;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * Manager of {@link ThreadPoolPlugin}.
+ * Bind with the specified thread-pool instance to register and manage plugins.
+ * when the thread pool is destroyed, please ensure that the manager will also be destroyed.
+ *
+ * @see DefaultThreadPoolPluginManager
+ */
+public interface ThreadPoolPluginManager {
+
+ /**
+ * Get an empty manager.
+ *
+ * @return {@link EmptyThreadPoolPluginManager}
+ */
+ static ThreadPoolPluginManager empty() {
+ return EmptyThreadPoolPluginManager.INSTANCE;
+ }
+
+ /**
+ * Clear all.
+ */
+ void clear();
+
+ /**
+ * Get all registered plugins.
+ *
+ * @return plugins
+ */
+ Collection getAllPlugins();
+
+ /**
+ * Register a {@link ThreadPoolPlugin}
+ *
+ * @param plugin plugin
+ * @throws IllegalArgumentException thrown when a plugin with the same {@link ThreadPoolPlugin#getId()}
+ * already exists in the registry
+ * @see ThreadPoolPlugin#getId()
+ */
+ void register(ThreadPoolPlugin plugin);
+
+ /**
+ * Register plugin if it's not registered.
+ *
+ * @param plugin plugin
+ * @return return true if successful register new plugin, false otherwise
+ */
+ boolean tryRegister(ThreadPoolPlugin plugin);
+
+ /**
+ * Whether the {@link ThreadPoolPlugin} has been registered.
+ *
+ * @param pluginId plugin id
+ * @return ture if target has been registered, false otherwise
+ */
+ boolean isRegistered(String pluginId);
+
+ /**
+ * Unregister {@link ThreadPoolPlugin}
+ *
+ * @param pluginId plugin id
+ */
+ void unregister(String pluginId);
+
+ /**
+ * Get {@link ThreadPoolPlugin}
+ *
+ * @param pluginId plugin id
+ * @param target aware type
+ * @return {@link ThreadPoolPlugin}
+ * @throws ClassCastException thrown when the object obtained by name cannot be converted to target type
+ */
+ Optional getPlugin(String pluginId);
+
+ /**
+ * Get execute aware plugin list.
+ *
+ * @return {@link ExecuteAwarePlugin}
+ */
+ Collection getExecuteAwarePluginList();
+
+ /**
+ * Get rejected aware plugin list.
+ *
+ * @return {@link RejectedAwarePlugin}
+ */
+ Collection getRejectedAwarePluginList();
+
+ /**
+ * Get shutdown aware plugin list.
+ *
+ * @return {@link ShutdownAwarePlugin}
+ */
+ Collection getShutdownAwarePluginList();
+
+ /**
+ * Get shutdown aware plugin list.
+ *
+ * @return {@link ShutdownAwarePlugin}
+ */
+ Collection getTaskAwarePluginList();
+
+ // ==================== default methods ====================
+
+ /**
+ * Get plugin of type.
+ *
+ * @param pluginId plugin id
+ * @param pluginType plugin type
+ * @return target plugin
+ */
+ default Optional getPluginOfType(String pluginId, Class pluginType) {
+ return getPlugin(pluginId)
+ .filter(pluginType::isInstance)
+ .map(pluginType::cast);
+ }
+
+ /**
+ * Get all plugins of type.
+ *
+ * @param pluginType plugin type
+ * @return all plugins of type
+ */
+ default Collection getAllPluginsOfType(Class pluginType) {
+ return getAllPlugins().stream()
+ .filter(pluginType::isInstance)
+ .map(pluginType::cast)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Get {@link PluginRuntime} of all registered plugins.
+ *
+ * @return {@link PluginRuntime} of all registered plugins
+ */
+ default Collection getAllPluginRuntimes() {
+ return getAllPlugins().stream()
+ .map(ThreadPoolPlugin::getPluginRuntime)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Get {@link PluginRuntime} of registered plugin.
+ *
+ * @return {@link PluginRuntime} of registered plugin
+ */
+ default Optional getRuntime(String pluginId) {
+ return getPlugin(pluginId)
+ .map(ThreadPoolPlugin::getPluginRuntime);
+ }
+
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginRegistrar.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginRegistrar.java
new file mode 100644
index 00000000..23576c36
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginRegistrar.java
@@ -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.core.plugin.manager;
+
+import cn.hippo4j.core.plugin.ThreadPoolPlugin;
+
+/**
+ * Registrar of {@link ThreadPoolPlugin}.
+ */
+public interface ThreadPoolPluginRegistrar {
+
+ /**
+ * Get id.
+ * In spring container, the obtained id will be used as the alias of the bean name.
+ *
+ * @return id
+ */
+ String getId();
+
+ /**
+ * Create and register plugin for the specified thread-pool instance.
+ *
+ * @param support thread pool plugin manager delegate
+ */
+ void doRegister(ThreadPoolPluginSupport support);
+
+}
diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginSupport.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginSupport.java
new file mode 100644
index 00000000..c3bd4187
--- /dev/null
+++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginSupport.java
@@ -0,0 +1,168 @@
+/*
+ * 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.core.plugin.manager;
+
+import cn.hippo4j.core.plugin.*;
+import org.checkerframework.checker.nullness.qual.NonNull;
+
+import java.util.Collection;
+import java.util.Optional;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * Used to support the binding of {@link ThreadPoolPluginManager} and {@link ThreadPoolExecutor}.
+ */
+public interface ThreadPoolPluginSupport extends ThreadPoolPluginManager {
+
+ /**
+ * Get thread pool action aware registry.
+ *
+ * @return {@link ThreadPoolPluginManager}
+ */
+ @NonNull
+ ThreadPoolPluginManager getThreadPoolPluginManager();
+
+ /**
+ * Get thread-pool id
+ *
+ * @return thread-pool id
+ */
+ String getThreadPoolId();
+
+ /**
+ * Get thread-pool executor.
+ *
+ * @return thread-pool executor
+ */
+ ThreadPoolExecutor getThreadPoolExecutor();
+
+ // ======================== delegate methods ========================
+
+ /**
+ * Clear all.
+ */
+ @Override
+ default void clear() {
+ getThreadPoolPluginManager().clear();
+ }
+
+ /**
+ * Register a {@link ThreadPoolPlugin}
+ *
+ * @param plugin aware
+ */
+ @Override
+ default void register(ThreadPoolPlugin plugin) {
+ getThreadPoolPluginManager().register(plugin);
+ }
+
+ /**
+ * Register plugin if it's not registered.
+ *
+ * @param plugin plugin
+ * @return return true if successful register new plugin, false otherwise
+ */
+ @Override
+ default boolean tryRegister(ThreadPoolPlugin plugin) {
+ return getThreadPoolPluginManager().tryRegister(plugin);
+ }
+
+ /**
+ * Whether the {@link ThreadPoolPlugin} has been registered.
+ *
+ * @param pluginId name
+ * @return ture if target has been registered, false otherwise
+ */
+ @Override
+ default boolean isRegistered(String pluginId) {
+ return getThreadPoolPluginManager().isRegistered(pluginId);
+ }
+
+ /**
+ * Unregister {@link ThreadPoolPlugin}
+ *
+ * @param pluginId name
+ */
+ @Override
+ default void unregister(String pluginId) {
+ getThreadPoolPluginManager().unregister(pluginId);
+ }
+
+ /**
+ * Get all registered plugins.
+ *
+ * @return plugins
+ */
+ @Override
+ default Collection getAllPlugins() {
+ return getThreadPoolPluginManager().getAllPlugins();
+ }
+
+ /**
+ * Get {@link ThreadPoolPlugin}
+ *
+ * @param pluginId target name
+ * @return {@link ThreadPoolPlugin}, null if unregister
+ * @throws ClassCastException thrown when the object obtained by name cannot be converted to target type
+ */
+ @Override
+ default Optional getPlugin(String pluginId) {
+ return getThreadPoolPluginManager().getPlugin(pluginId);
+ }
+
+ /**
+ * Get execute aware list.
+ *
+ * @return {@link ExecuteAwarePlugin}
+ */
+ @Override
+ default Collection getExecuteAwarePluginList() {
+ return getThreadPoolPluginManager().getExecuteAwarePluginList();
+ }
+
+ /**
+ * Get rejected aware list.
+ *
+ * @return {@link RejectedAwarePlugin}
+ */
+ @Override
+ default Collection getRejectedAwarePluginList() {
+ return getThreadPoolPluginManager().getRejectedAwarePluginList();
+ }
+
+ /**
+ * Get shutdown aware list.
+ *
+ * @return {@link ShutdownAwarePlugin}
+ */
+ @Override
+ default Collection getShutdownAwarePluginList() {
+ return getThreadPoolPluginManager().getShutdownAwarePluginList();
+ }
+
+ /**
+ * Get shutdown aware list.
+ *
+ * @return {@link ShutdownAwarePlugin}
+ */
+ @Override
+ default Collection getTaskAwarePluginList() {
+ return getThreadPoolPluginManager().getTaskAwarePluginList();
+ }
+
+}
diff --git a/hippo4j-core/src/test/java/cn/hippo4j/core/executor/DynamicThreadPoolExecutorTest.java b/hippo4j-core/src/test/java/cn/hippo4j/core/executor/DynamicThreadPoolExecutorTest.java
new file mode 100644
index 00000000..63d362af
--- /dev/null
+++ b/hippo4j-core/src/test/java/cn/hippo4j/core/executor/DynamicThreadPoolExecutorTest.java
@@ -0,0 +1,160 @@
+/*
+ * 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.core.executor;
+
+import cn.hippo4j.common.toolkit.ThreadUtil;
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.core.task.TaskDecorator;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * test for {@link DynamicThreadPoolExecutor}
+ */
+public class DynamicThreadPoolExecutorTest {
+
+ @Test
+ public void testRedundancyHandler() {
+ RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardOldestPolicy();
+
+ DynamicThreadPoolExecutor executor = new DynamicThreadPoolExecutor(
+ 1, 1, 1000L, TimeUnit.MILLISECONDS,
+ 1000L, true, 1000L,
+ new ArrayBlockingQueue<>(1), "test", Thread::new, handler);
+
+ Assert.assertEquals(handler, executor.getRedundancyHandler());
+ handler = new ThreadPoolExecutor.AbortPolicy();
+ executor.setRedundancyHandler(handler);
+ Assert.assertEquals(handler, executor.getRedundancyHandler());
+ }
+
+ @Test
+ public void testTaskDecorator() {
+ DynamicThreadPoolExecutor executor = new DynamicThreadPoolExecutor(
+ 1, 1, 1000L, TimeUnit.MILLISECONDS,
+ 1000L, true, 1000L,
+ new ArrayBlockingQueue<>(1), "test", Thread::new, new ThreadPoolExecutor.DiscardOldestPolicy());
+
+ Assert.assertNull(executor.getTaskDecorator());
+ TaskDecorator decorator = runnable -> runnable;
+ executor.setTaskDecorator(decorator);
+ Assert.assertEquals(decorator, executor.getTaskDecorator());
+
+ decorator = runnable -> runnable;
+ executor.setTaskDecorator(decorator);
+ Assert.assertEquals(decorator, executor.getTaskDecorator());
+ }
+
+ @Test
+ public void testExecuteTimeOut() {
+ DynamicThreadPoolExecutor executor = new DynamicThreadPoolExecutor(
+ 1, 1, 1000L, TimeUnit.MILLISECONDS,
+ 1000L, true, 1000L,
+ new ArrayBlockingQueue<>(1), "test", Thread::new, new ThreadPoolExecutor.DiscardOldestPolicy());
+
+ Assert.assertEquals(1000L, executor.getExecuteTimeOut().longValue());
+ executor.setExecuteTimeOut(500L);
+ Assert.assertEquals(500L, executor.getExecuteTimeOut().longValue());
+ }
+
+ @Test
+ public void testDestroyWhenWaitForTask() {
+ DynamicThreadPoolExecutor executor = new DynamicThreadPoolExecutor(
+ 1, 1, 1000L, TimeUnit.MILLISECONDS,
+ 1000L, true, 1000L,
+ new ArrayBlockingQueue<>(1), "test", Thread::new, new ThreadPoolExecutor.DiscardOldestPolicy());
+ AtomicInteger count = new AtomicInteger(0);
+
+ executor.execute(() -> {
+ ThreadUtil.sleep(500L);
+ count.incrementAndGet();
+ });
+ executor.execute(() -> {
+ ThreadUtil.sleep(500L);
+ count.incrementAndGet();
+ });
+ executor.destroy();
+
+ // waitting for terminated
+ while (!executor.isTerminated()) {
+ } ;
+ Assert.assertEquals(2, count.get());
+ }
+
+ @Test
+ public void testDestroyWhenNotWaitForTask() {
+ DynamicThreadPoolExecutor executor = new DynamicThreadPoolExecutor(
+ 1, 1, 1000L, TimeUnit.MILLISECONDS,
+ 1000L, false, 1000L,
+ new ArrayBlockingQueue<>(1), "test", Thread::new, new ThreadPoolExecutor.DiscardOldestPolicy());
+ AtomicInteger count = new AtomicInteger(0);
+
+ executor.execute(() -> {
+ ThreadUtil.sleep(500L);
+ count.incrementAndGet();
+ });
+ executor.execute(() -> {
+ ThreadUtil.sleep(500L);
+ count.incrementAndGet();
+ });
+ executor.destroy();
+
+ // waitting for terminated
+ while (!executor.isTerminated()) {
+ } ;
+ Assert.assertEquals(1, count.get());
+ }
+
+ @Test
+ public void testRejectCount() {
+ DynamicThreadPoolExecutor executor = new DynamicThreadPoolExecutor(
+ 1, 1, 1000L, TimeUnit.MILLISECONDS,
+ 1000L, true, 1000L,
+ new ArrayBlockingQueue<>(1), "test", Thread::new, new ThreadPoolExecutor.DiscardOldestPolicy());
+
+ Assert.assertEquals(0L, executor.getRejectCountNum().longValue());
+ Assert.assertEquals(0L, executor.getRejectCount().get());
+
+ executor.submit(() -> ThreadUtil.sleep(100L));
+ executor.submit(() -> ThreadUtil.sleep(100L));
+ executor.submit(() -> ThreadUtil.sleep(100L));
+ ThreadUtil.sleep(200L);
+ Assert.assertEquals(1L, executor.getRejectCountNum().longValue());
+ Assert.assertEquals(1L, executor.getRejectCount().get());
+ }
+
+ @Test
+ public void testSupportParam() {
+ DynamicThreadPoolExecutor executor = new DynamicThreadPoolExecutor(
+ 1, 1, 1000L, TimeUnit.MILLISECONDS,
+ 1000L, true, 1000L,
+ new ArrayBlockingQueue<>(1), "test", Thread::new, new ThreadPoolExecutor.DiscardOldestPolicy());
+ Assert.assertEquals(1000L, executor.getAwaitTerminationMillis());
+ Assert.assertTrue(executor.isWaitForTasksToCompleteOnShutdown());
+
+ executor.setSupportParam(500L, false);
+ Assert.assertEquals(500L, executor.getAwaitTerminationMillis());
+ Assert.assertFalse(executor.isWaitForTasksToCompleteOnShutdown());
+ }
+
+}
diff --git a/hippo4j-core/src/test/java/cn/hippo4j/core/executor/ExtensibleThreadPoolExecutorTest.java b/hippo4j-core/src/test/java/cn/hippo4j/core/executor/ExtensibleThreadPoolExecutorTest.java
new file mode 100644
index 00000000..7642adc6
--- /dev/null
+++ b/hippo4j-core/src/test/java/cn/hippo4j/core/executor/ExtensibleThreadPoolExecutorTest.java
@@ -0,0 +1,219 @@
+/*
+ * 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.core.executor;
+
+import cn.hippo4j.common.toolkit.ThreadUtil;
+import cn.hippo4j.core.plugin.ExecuteAwarePlugin;
+import cn.hippo4j.core.plugin.RejectedAwarePlugin;
+import cn.hippo4j.core.plugin.ShutdownAwarePlugin;
+import cn.hippo4j.core.plugin.TaskAwarePlugin;
+import cn.hippo4j.core.plugin.manager.DefaultThreadPoolPluginManager;
+import cn.hippo4j.core.plugin.manager.ThreadPoolPluginManager;
+import lombok.Getter;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * test for {@link ExtensibleThreadPoolExecutor}
+ */
+public class ExtensibleThreadPoolExecutorTest {
+
+ private final RejectedExecutionHandler originalHandler = new ThreadPoolExecutor.DiscardPolicy();
+
+ private ExtensibleThreadPoolExecutor executor;
+
+ private ThreadPoolPluginManager manager;
+
+ @Before
+ public void initExecutor() {
+ manager = new DefaultThreadPoolPluginManager();
+ executor = new ExtensibleThreadPoolExecutor(
+ "test", manager,
+ 5, 5, 1000L, TimeUnit.MILLISECONDS,
+ new ArrayBlockingQueue<>(1), Thread::new, originalHandler);
+ }
+
+ @Test
+ public void testGetThreadPoolId() {
+ Assert.assertEquals("test", executor.getThreadPoolId());
+ }
+
+ @Test
+ public void testGetThreadPoolExecutor() {
+ Assert.assertSame(executor, executor.getThreadPoolExecutor());
+ }
+
+ @Test
+ public void testGetThreadPoolPluginManager() {
+ Assert.assertSame(manager, executor.getThreadPoolPluginManager());
+ }
+
+ @Test
+ public void testGetOrSetRejectedHandler() {
+ RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
+ executor.setRejectedExecutionHandler(handler);
+ Assert.assertSame(handler, executor.getRejectedExecutionHandler());
+ }
+
+ @Test
+ public void testInvokeTaskAwarePlugin() {
+ TestTaskAwarePlugin plugin = new TestTaskAwarePlugin();
+ executor.register(plugin);
+ executor.submit(() -> {
+ });
+ executor.submit(() -> true);
+ executor.submit(() -> {
+ }, false);
+ executor.execute(() -> {
+ });
+ Assert.assertEquals(7, plugin.getInvokeCount().get());
+ }
+
+ @Test
+ public void testInvokeExecuteAwarePlugin() {
+ TestExecuteAwarePlugin plugin = new TestExecuteAwarePlugin();
+ executor.register(plugin);
+ executor.execute(() -> {
+ });
+ ThreadUtil.sleep(500L);
+ Assert.assertEquals(2, plugin.getInvokeCount().get());
+ }
+
+ @Test
+ public void testInvokeRejectedAwarePlugin() {
+ executor.setCorePoolSize(1);
+ executor.setMaximumPoolSize(1);
+
+ TestRejectedAwarePlugin plugin = new TestRejectedAwarePlugin();
+ executor.register(plugin);
+ // blocking pool and queue
+ executor.submit(() -> ThreadUtil.sleep(500L));
+ executor.submit(() -> ThreadUtil.sleep(500L));
+ // reject 3 tasks
+ executor.submit(() -> {
+ });
+ executor.submit(() -> {
+ });
+ executor.submit(() -> {
+ });
+
+ ThreadUtil.sleep(500L);
+ Assert.assertEquals(3, plugin.getInvokeCount().get());
+ }
+
+ @Test
+ public void testInvokeTestShutdownAwarePluginWhenShutdown() throws InterruptedException {
+ TestShutdownAwarePlugin plugin = new TestShutdownAwarePlugin();
+ executor.register(plugin);
+ executor.shutdown();
+ executor.submit(() -> {
+ throw new IllegalArgumentException("???");
+ });
+ if (executor.awaitTermination(500L, TimeUnit.MILLISECONDS)) {
+ Assert.assertEquals(3, plugin.getInvokeCount().get());
+ }
+ }
+
+ @Test
+ public void testInvokeTestShutdownAwarePluginWhenShutdownNow() throws InterruptedException {
+ TestShutdownAwarePlugin plugin = new TestShutdownAwarePlugin();
+ executor.register(plugin);
+ executor.shutdownNow();
+ if (executor.awaitTermination(500L, TimeUnit.MILLISECONDS)) {
+ Assert.assertEquals(3, plugin.getInvokeCount().get());
+ }
+ }
+
+ @Getter
+ private final static class TestTaskAwarePlugin implements TaskAwarePlugin {
+
+ private final AtomicInteger invokeCount = new AtomicInteger(0);
+ private final String id = "TestTaskAwarePlugin";
+ @Override
+ public Runnable beforeTaskCreate(ThreadPoolExecutor executor, Runnable runnable, V value) {
+ invokeCount.incrementAndGet();
+ return TaskAwarePlugin.super.beforeTaskCreate(executor, runnable, value);
+ }
+ @Override
+ public Callable beforeTaskCreate(ThreadPoolExecutor executor, Callable future) {
+ invokeCount.incrementAndGet();
+ return TaskAwarePlugin.super.beforeTaskCreate(executor, future);
+ }
+ @Override
+ public Runnable beforeTaskExecute(Runnable runnable) {
+ invokeCount.incrementAndGet();
+ return TaskAwarePlugin.super.beforeTaskExecute(runnable);
+ }
+ }
+
+ @Getter
+ private final static class TestExecuteAwarePlugin implements ExecuteAwarePlugin {
+
+ private final AtomicInteger invokeCount = new AtomicInteger(0);
+ private final String id = "TestExecuteAwarePlugin";
+ @Override
+ public void beforeExecute(Thread thread, Runnable runnable) {
+ invokeCount.incrementAndGet();
+ ExecuteAwarePlugin.super.beforeExecute(thread, runnable);
+ }
+ @Override
+ public void afterExecute(Runnable runnable, Throwable throwable) {
+ invokeCount.incrementAndGet();
+ ExecuteAwarePlugin.super.afterExecute(runnable, throwable);
+ }
+ }
+
+ @Getter
+ private final static class TestRejectedAwarePlugin implements RejectedAwarePlugin {
+
+ private final AtomicInteger invokeCount = new AtomicInteger(0);
+ private final String id = "TestRejectedAwarePlugin";
+ @Override
+ public void beforeRejectedExecution(Runnable runnable, ThreadPoolExecutor executor) {
+ invokeCount.incrementAndGet();
+ }
+ }
+
+ @Getter
+ private final static class TestShutdownAwarePlugin implements ShutdownAwarePlugin {
+
+ private final AtomicInteger invokeCount = new AtomicInteger(0);
+ private final String id = "TestShutdownAwarePlugin";
+ @Override
+ public void beforeShutdown(ThreadPoolExecutor executor) {
+ invokeCount.incrementAndGet();
+ ShutdownAwarePlugin.super.beforeShutdown(executor);
+ }
+ @Override
+ public void afterShutdown(ThreadPoolExecutor executor, List remainingTasks) {
+ invokeCount.incrementAndGet();
+ ShutdownAwarePlugin.super.afterShutdown(executor, remainingTasks);
+ }
+ @Override
+ public void afterTerminated(ExtensibleThreadPoolExecutor executor) {
+ invokeCount.incrementAndGet();
+ ShutdownAwarePlugin.super.afterTerminated(executor);
+ }
+ }
+
+}
diff --git a/hippo4j-example/hippo4j-example-core/pom.xml b/hippo4j-example/hippo4j-example-core/pom.xml
index 50ed2a3d..2628dbd6 100644
--- a/hippo4j-example/hippo4j-example-core/pom.xml
+++ b/hippo4j-example/hippo4j-example-core/pom.xml
@@ -34,5 +34,20 @@
com.alibaba
transmittable-thread-local
+
+
+ org.openjdk.jmh
+ jmh-core
+ 1.23
+ test
+
+
+
+ org.openjdk.jmh
+ jmh-generator-annprocess
+ 1.23
+ test
+
+
diff --git a/hippo4j-example/hippo4j-example-core/src/test/java/cn/hippo4j/example/core/TaskTimeRecordPluginBenchmarkTest.java b/hippo4j-example/hippo4j-example-core/src/test/java/cn/hippo4j/example/core/TaskTimeRecordPluginBenchmarkTest.java
new file mode 100644
index 00000000..408af6e0
--- /dev/null
+++ b/hippo4j-example/hippo4j-example-core/src/test/java/cn/hippo4j/example/core/TaskTimeRecordPluginBenchmarkTest.java
@@ -0,0 +1,174 @@
+/*
+ * 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.example.core;
+
+import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor;
+import cn.hippo4j.core.plugin.impl.TaskTimeRecordPlugin;
+import cn.hippo4j.core.plugin.manager.DefaultThreadPoolPluginManager;
+import lombok.SneakyThrows;
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.infra.Blackhole;
+import org.openjdk.jmh.results.format.ResultFormatType;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * benchmark test for {@link cn.hippo4j.core.plugin.impl.TaskTimeRecordPlugin}
+ */
+@BenchmarkMode(Mode.All)
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@State(Scope.Thread)
+@Warmup(iterations = 1)
+@Measurement(iterations = 3)
+@Fork(1)
+@Threads(6)
+public class TaskTimeRecordPluginBenchmarkTest {
+
+ @SneakyThrows
+ @Benchmark
+ public void origin_200(Blackhole blackhole) {
+ int threadCount = 200;
+ ThreadPoolExecutor executor = new ThreadPoolExecutor(
+ threadCount, threadCount, 1000L, TimeUnit.MILLISECONDS,
+ new ArrayBlockingQueue<>(threadCount), Thread::new, new ThreadPoolExecutor.DiscardPolicy());
+ executor.prestartAllCoreThreads();
+
+ List tasks = getTask(threadCount, blackhole);
+ tasks.forEach(executor::execute);
+
+ executor.shutdown();
+ while (!executor.isTerminated()) {
+ }
+ }
+
+ @SneakyThrows
+ @Benchmark
+ public void origin_50(Blackhole blackhole) {
+ int threadCount = 50;
+ ThreadPoolExecutor executor = new ThreadPoolExecutor(
+ threadCount, threadCount, 1000L, TimeUnit.MILLISECONDS,
+ new ArrayBlockingQueue<>(threadCount), Thread::new, new ThreadPoolExecutor.DiscardPolicy());
+ executor.prestartAllCoreThreads();
+
+ List tasks = getTask(threadCount, blackhole);
+ tasks.forEach(executor::execute);
+
+ executor.shutdown();
+ while (!executor.isTerminated()) {
+ }
+ }
+
+ @SneakyThrows
+ @Benchmark
+ public void not_plugin_50(Blackhole blackhole) {
+ int threadCount = 50;
+ ExtensibleThreadPoolExecutor executor = new ExtensibleThreadPoolExecutor(
+ "test", new DefaultThreadPoolPluginManager(),
+ threadCount, threadCount, 1000L, TimeUnit.MILLISECONDS,
+ new ArrayBlockingQueue<>(threadCount), Thread::new, new ThreadPoolExecutor.DiscardPolicy());
+ executor.prestartAllCoreThreads();
+
+ List tasks = getTask(threadCount, blackhole);
+ tasks.forEach(executor::execute);
+
+ executor.shutdown();
+ while (!executor.isTerminated()) {
+ }
+ }
+
+ @SneakyThrows
+ @Benchmark
+ public void not_plugin_200(Blackhole blackhole) {
+ int threadCount = 200;
+ ExtensibleThreadPoolExecutor executor = new ExtensibleThreadPoolExecutor(
+ "test", new DefaultThreadPoolPluginManager(),
+ threadCount, threadCount, 1000L, TimeUnit.MILLISECONDS,
+ new ArrayBlockingQueue<>(threadCount), Thread::new, new ThreadPoolExecutor.DiscardPolicy());
+ executor.prestartAllCoreThreads();
+
+ List tasks = getTask(threadCount, blackhole);
+ tasks.forEach(executor::execute);
+
+ executor.shutdown();
+ while (!executor.isTerminated()) {
+ }
+ }
+
+ @SneakyThrows
+ @Benchmark
+ public void plugin_50(Blackhole blackhole) {
+ int threadCount = 50;
+ ExtensibleThreadPoolExecutor executor = new ExtensibleThreadPoolExecutor(
+ "test", new DefaultThreadPoolPluginManager(),
+ threadCount, threadCount, 1000L, TimeUnit.MILLISECONDS,
+ new ArrayBlockingQueue<>(threadCount), Thread::new, new ThreadPoolExecutor.DiscardPolicy());
+ executor.prestartAllCoreThreads();
+ executor.register(new TaskTimeRecordPlugin());
+
+ List tasks = getTask(threadCount, blackhole);
+ tasks.forEach(executor::execute);
+
+ executor.shutdown();
+ while (!executor.isTerminated()) {
+ }
+ }
+
+ @SneakyThrows
+ @Benchmark
+ public void plugin_200(Blackhole blackhole) {
+ int threadCount = 200;
+ ExtensibleThreadPoolExecutor executor = new ExtensibleThreadPoolExecutor(
+ "test", new DefaultThreadPoolPluginManager(),
+ threadCount, threadCount, 1000L, TimeUnit.MILLISECONDS,
+ new ArrayBlockingQueue<>(threadCount), Thread::new, new ThreadPoolExecutor.DiscardPolicy());
+ executor.prestartAllCoreThreads();
+ executor.register(new TaskTimeRecordPlugin());
+
+ List tasks = getTask(threadCount, blackhole);
+ tasks.forEach(executor::execute);
+
+ executor.shutdown();
+ while (!executor.isTerminated()) {
+ }
+ }
+
+ private List getTask(int count, Blackhole blackhole) {
+ List tasks = new ArrayList<>(count);
+ for (int i = 1; i < count * 2; i++) {
+ int index = i;
+ tasks.add(() -> blackhole.consume(index));
+ }
+ return tasks;
+ }
+
+ public static void main(String[] args) throws Exception {
+ Options opts = new OptionsBuilder()
+ .include(TaskTimeRecordPluginBenchmarkTest.class.getSimpleName())
+ .resultFormat(ResultFormatType.JSON)
+ .build();
+ new Runner(opts).run();
+ }
+
+}
diff --git a/hippo4j-message/src/main/resources/message/robot/dynamic-thread-pool/ding-alarm.txt b/hippo4j-message/src/main/resources/message/robot/dynamic-thread-pool/ding-alarm.txt
index 55064be3..7fda29d7 100644
--- a/hippo4j-message/src/main/resources/message/robot/dynamic-thread-pool/ding-alarm.txt
+++ b/hippo4j-message/src/main/resources/message/robot/dynamic-thread-pool/ding-alarm.txt
@@ -1,4 +1,4 @@
-**[警报] %s - 动态线程池运行告警(%s)**
+**[告警] %s - 动态线程池运行告警(%s)**
---
diff --git a/hippo4j-message/src/main/resources/message/robot/dynamic-thread-pool/lark-alarm.json b/hippo4j-message/src/main/resources/message/robot/dynamic-thread-pool/lark-alarm.json
index 0e451e93..2bc88c3a 100644
--- a/hippo4j-message/src/main/resources/message/robot/dynamic-thread-pool/lark-alarm.json
+++ b/hippo4j-message/src/main/resources/message/robot/dynamic-thread-pool/lark-alarm.json
@@ -7,7 +7,7 @@
"header": {
"template": "red",
"title": {
- "content": "[🔥警报] %s 动态线程池运行告警(%s)",
+ "content": "[🔥告警] %s 动态线程池运行告警(%s)",
"tag": "plain_text"
}
},
diff --git a/hippo4j-message/src/main/resources/message/robot/dynamic-thread-pool/wechat-alarm.txt b/hippo4j-message/src/main/resources/message/robot/dynamic-thread-pool/wechat-alarm.txt
index 56f7ace1..00dd33b2 100644
--- a/hippo4j-message/src/main/resources/message/robot/dynamic-thread-pool/wechat-alarm.txt
+++ b/hippo4j-message/src/main/resources/message/robot/dynamic-thread-pool/wechat-alarm.txt
@@ -1,4 +1,4 @@
-### [警报] %s - 动态线程池运行告警(%s)
+### [告警] %s - 动态线程池运行告警(%s)
> 线程池ID:%s
> 应用名称:%s
diff --git a/hippo4j-server/hippo4j-auth/src/main/java/cn/hippo4j/auth/filter/JWTAuthenticationFilter.java b/hippo4j-server/hippo4j-auth/src/main/java/cn/hippo4j/auth/filter/JWTAuthenticationFilter.java
index 8711e89b..f77f579a 100644
--- a/hippo4j-server/hippo4j-auth/src/main/java/cn/hippo4j/auth/filter/JWTAuthenticationFilter.java
+++ b/hippo4j-server/hippo4j-auth/src/main/java/cn/hippo4j/auth/filter/JWTAuthenticationFilter.java
@@ -73,12 +73,11 @@ public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilte
authenticate = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginUser.getUsername(), loginUser.getPassword(), new ArrayList()));
} catch (BadCredentialsException e) {
- log.warn("BadCredentialsException:{}", e.getMessage());
+ log.warn("Bad credentials exception: {}", e.getMessage());
} catch (Exception e) {
- log.error("attemptauthentication error:", e);
- } finally {
- return authenticate;
+ log.error("Attempt authentication error", e);
}
+ return authenticate;
}
@Override
diff --git a/hippo4j-server/hippo4j-auth/src/main/java/cn/hippo4j/auth/filter/RewriteUserInfoApiFilter.java b/hippo4j-server/hippo4j-auth/src/main/java/cn/hippo4j/auth/filter/RewriteUserInfoApiFilter.java
index 8e789d30..8144f7bc 100644
--- a/hippo4j-server/hippo4j-auth/src/main/java/cn/hippo4j/auth/filter/RewriteUserInfoApiFilter.java
+++ b/hippo4j-server/hippo4j-auth/src/main/java/cn/hippo4j/auth/filter/RewriteUserInfoApiFilter.java
@@ -34,7 +34,7 @@ public class RewriteUserInfoApiFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
- boolean enableAuthentication = AuthUtil.enableAuthentication;
+ boolean enableAuthentication = AuthUtil.ENABLE_AUTHENTICATION;
HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
String path = httpRequest.getRequestURI();
if (!enableAuthentication && path.contains("users/info")) {
diff --git a/hippo4j-server/hippo4j-auth/src/main/java/cn/hippo4j/auth/toolkit/AuthUtil.java b/hippo4j-server/hippo4j-auth/src/main/java/cn/hippo4j/auth/toolkit/AuthUtil.java
index ab6f9b9a..62e0371f 100644
--- a/hippo4j-server/hippo4j-auth/src/main/java/cn/hippo4j/auth/toolkit/AuthUtil.java
+++ b/hippo4j-server/hippo4j-auth/src/main/java/cn/hippo4j/auth/toolkit/AuthUtil.java
@@ -20,13 +20,19 @@ package cn.hippo4j.auth.toolkit;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
+/**
+ * Auth util.
+ */
@Component
public class AuthUtil {
- public static boolean enableAuthentication;
+ /**
+ * Enable authentication
+ */
+ public static boolean ENABLE_AUTHENTICATION;
@Value("${hippo4j.core.auth.enabled:true}")
public void setEnableAuthentication(boolean enabled) {
- AuthUtil.enableAuthentication = enabled;
+ AuthUtil.ENABLE_AUTHENTICATION = enabled;
}
}
\ No newline at end of file
diff --git a/hippo4j-server/hippo4j-auth/src/test/java/cn/hippo4j/auth/toolkit/AuthUtilTest.java b/hippo4j-server/hippo4j-auth/src/test/java/cn/hippo4j/auth/toolkit/AuthUtilTest.java
new file mode 100644
index 00000000..dd522658
--- /dev/null
+++ b/hippo4j-server/hippo4j-auth/src/test/java/cn/hippo4j/auth/toolkit/AuthUtilTest.java
@@ -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.auth.toolkit;
+
+import cn.hippo4j.common.toolkit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public final class AuthUtilTest {
+
+ private AuthUtil authUtil;
+
+ @Before
+ public void beforeInit() {
+ authUtil = new AuthUtil();
+ authUtil.setEnableAuthentication(true);
+ }
+
+ @Test
+ public void assertGetEnableAuthentication() {
+ Assert.isTrue(AuthUtil.ENABLE_AUTHENTICATION);
+ }
+}
diff --git a/hippo4j-server/hippo4j-auth/src/test/java/cn/hippo4j/auth/toolkit/ReturnTTest.java b/hippo4j-server/hippo4j-auth/src/test/java/cn/hippo4j/auth/toolkit/ReturnTTest.java
new file mode 100644
index 00000000..8c2ff9b2
--- /dev/null
+++ b/hippo4j-server/hippo4j-auth/src/test/java/cn/hippo4j/auth/toolkit/ReturnTTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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.auth.toolkit;
+
+import cn.hippo4j.common.toolkit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Objects;
+
+public final class ReturnTTest {
+
+ private ReturnT returnT;
+
+ @Before
+ public void beforeInit() {
+ returnT = new ReturnT("success");
+ }
+
+ @Test
+ public void assertGetCode() {
+ Assert.isTrue(Objects.equals(returnT.getCode(), 200));
+ }
+
+ @Test
+ public void assertGetMessage() {
+ Assert.isNull(returnT.getMsg());
+ }
+
+ @Test
+ public void assertGetContent() {
+ Assert.isTrue(Objects.equals(returnT.getContent(), "success"));
+ }
+}
diff --git a/hippo4j-server/hippo4j-config/src/main/java/cn/hippo4j/config/controller/ConfigController.java b/hippo4j-server/hippo4j-config/src/main/java/cn/hippo4j/config/controller/ConfigController.java
index f4c48610..2011f5e8 100644
--- a/hippo4j-server/hippo4j-config/src/main/java/cn/hippo4j/config/controller/ConfigController.java
+++ b/hippo4j-server/hippo4j-config/src/main/java/cn/hippo4j/config/controller/ConfigController.java
@@ -17,6 +17,12 @@
package cn.hippo4j.config.controller;
+import java.net.URLDecoder;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
import cn.hippo4j.common.constant.ConfigModifyTypeConstants;
import cn.hippo4j.common.constant.Constants;
import cn.hippo4j.common.model.register.DynamicThreadPoolRegisterWrapper;
@@ -35,13 +41,14 @@ import cn.hippo4j.config.toolkit.Md5ConfigUtil;
import cn.hippo4j.config.verify.ConfigModificationVerifyServiceChoose;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
-import org.springframework.util.StringUtils;
-import org.springframework.web.bind.annotation.*;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.net.URLDecoder;
-import java.util.Map;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
/**
* Server configuration controller.
@@ -76,7 +83,7 @@ public class ConfigController {
modifySaveReqDTO.setCorePoolSize(config.getCoreSize());
modifySaveReqDTO.setMaximumPoolSize(config.getMaxSize());
modifySaveReqDTO.setModifyUser(UserContext.getUserName());
- modifySaveReqDTO.setModifyAll(StringUtil.isEmpty(identify) ? true : false);
+ modifySaveReqDTO.setModifyAll(StringUtil.isEmpty(identify));
modifySaveReqDTO.setIdentify(identify);
modifySaveReqDTO.setType(ConfigModifyTypeConstants.THREAD_POOL_INSTANCE);
configModificationVerifyServiceChoose.choose(modifySaveReqDTO.getType()).saveConfigModifyApplication(modifySaveReqDTO);
diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/event/DynamicThreadPoolRefreshListener.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/event/DynamicThreadPoolRefreshListener.java
index e570caa4..8f1e4a3b 100644
--- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/event/DynamicThreadPoolRefreshListener.java
+++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/event/DynamicThreadPoolRefreshListener.java
@@ -29,8 +29,6 @@ import cn.hippo4j.core.executor.DynamicThreadPoolExecutor;
import cn.hippo4j.core.executor.ThreadPoolNotifyAlarmHandler;
import cn.hippo4j.core.executor.manage.GlobalNotifyAlarmManage;
import cn.hippo4j.core.executor.manage.GlobalThreadPoolManage;
-import cn.hippo4j.core.executor.support.AbstractDynamicExecutorSupport;
-import cn.hippo4j.core.proxy.RejectedProxyUtil;
import cn.hippo4j.message.dto.NotifyConfigDTO;
import cn.hippo4j.message.request.ChangeParameterNotifyRequest;
import cn.hippo4j.message.service.Hippo4jBaseSendMessageService;
@@ -43,7 +41,6 @@ import java.util.*;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
import static cn.hippo4j.common.constant.ChangeThreadPoolConstants.CHANGE_DELIMITER;
import static cn.hippo4j.common.constant.ChangeThreadPoolConstants.CHANGE_THREAD_POOL_TEXT;
@@ -105,10 +102,18 @@ public class DynamicThreadPoolRefreshListener extends AbstractRefreshListener