Officially added internationalization function (#866)

pull/876/head
chen.ma 2 years ago
parent 70146d00cb
commit 25ae85a487

@ -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

@ -65,7 +65,7 @@ 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) 或以上,以及 6 个 [good first issue]((https://github.com/opengoofy/hippo4j/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)) 或以上。
持续对 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) 或以上,以及 6 个 [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)

@ -23,8 +23,18 @@ const config = {
// 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'],
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 <a target="_blank" rel="noopener noreferrer" href="https://gitee.com/mabaiwancn/hippo4j">Gitee</a>, thanks.`,
content: `⭐️ 如果您喜欢 hippo4j请在 <a target="_blank" rel="noopener noreferrer" href="https://gitee.com/mabaiwancn/hippo4j">Gitee</a> 和 <a target="_blank" rel="noopener noreferrer" href="https://github.com/opengoofy/hippo4j">GitHub</a> 上给它一个 star谢谢`,
// content: `⭐️ 如果您喜欢 hippo4j请在 <a target="_blank" rel="noopener noreferrer" href="https://gitee.com/mabaiwancn/hippo4j">Gitee</a> 和 <a target="_blank" rel="noopener noreferrer" href="https://github.com/opengoofy/hippo4j">GitHub</a> 上给它一个 star谢谢`,
content: `⭐️ 开源不易hippo4j 如果对您工作有帮助,请在 <a target="_blank" rel="noopener noreferrer" href="https://github.com/opengoofy/hippo4j">GitHub</a> 上给它一个 🌟`,
// content: `<a target="_blank" rel="noopener noreferrer" href="https://xiaomage.info/knowledge-planet/">👉 《小马哥的代码实战课》官方知识星球来啦!!!</a>`,
},
navbar: {
title: 'HIPPO-4J',
title: '',
logo: {
alt: 'HIPPO-4J 动态可观测线程池框架',
src: 'img/web.png',
src: 'img/hippo4j.png',
},
items: [
{

@ -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"
}
}

@ -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
<dependency>
<groupId>cn.hippo4j</groupId>
<!-- Dubbo -->
<artifactId>hippo4j-spring-boot-starter-adapter-dubbo</artifactId>
<!-- RabbitMQ -->
<artifactId>hippo4j-spring-boot-starter-adapter-rabbitmq</artifactId>
<!-- RocketMQ -->
<artifactId>hippo4j-spring-boot-starter-adapter-rocketmq</artifactId>
<!-- SpringCloud Stream RocketMQ -->
<artifactId>hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rocketmq</artifactId>
<version>1.3.0</version>
</dependency>
```
如果想觉得引入多个 jar 包繁琐可以仅需引入一个全量包Hippo-4J 框架底层会根据各中间件的条件,判断加载具体线程池适配器。
```xml
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-spring-boot-starter-adapter-all</artifactId>
<version>1.3.0</version>
</dependency>
```
### HIPPO-4J Server
Hippo-4J server 引入上述适配 jar 包后,即可在 Hippo-4J server 的控制台进行查看及修改三方框架线程池。
![图1 线程池适配列表](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220531194810047.png)
点击编辑即可修改该 Java 应用对应的框架底层线程池。
![图2 修改三方线程池](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220605152549732.png)
点击 **全部修改** 按钮可以修改当前组下所有应用实例的线程池配置。
修改成功后,应用控制台打印以下日志,即为修改成功。
```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 做出过贡献的成员。
![图3 GVP 证书](https://images-machen.oss-cn-beijing.aliyuncs.com/170607238-7308c9be-1d63-46a6-852c-eef2e4cf7405.jpeg)
感谢所有为 Hippo-4J 做出贡献的开发者!
https://github.com/opengoofy/hippo4j/graphs/contributors
![图4 Hippo-4J 开发者](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220605151136276.png)
## 最后总结
开源不易,如果各位小伙伴看了 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 影响力,帮助它能走得更远。

@ -0,0 +1,5 @@
xiaomage:
name: 小马哥
title: hippo4j 作者
url: https://github.com/magegoofy
image_url: https://avatars.githubusercontent.com/u/77398366?v=4

@ -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"
}
}

@ -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"
}
}

@ -0,0 +1,7 @@
{
"label": "社区",
"position": 1,
"link": {
"type": "generated-index"
}
}

@ -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) 的贡献列表中找到全部的贡献者名单。
<a href="https://github.com/opengoofy/hippo4j/graphs/contributors">
<img src="https://contrib.rocks/image?repo=opengoofy/hippo4j" />
</a>

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

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

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

@ -0,0 +1,82 @@
---
sidebar_position: 2
---
# 核心开发者
<table>
<tr>
<td align="center" width="16%"></td>
<td align="center" width="16%">姓名</td>
<td align="center" width="18%">GitHub ID</td>
<td align="center" width="24%">博客地址</td>
<td align="center" width="26%">联系方式</td>
</tr>
<tr>
<td align="center" ><a href="https://github.com/magegoofy"><img src="https://avatars.githubusercontent.com/u/77398366?v=4?s=64" width="64px;"/></a></td>
<td align="center" >马称</td>
<td align="center" ><a href="https://github.com/magegoofy">magegoofy</a></td>
<td align="center" ><a href="https://www.xiaomage.info/">小马哥的技术专栏</a></td>
<td align="center" >machen@apache.org</td>
</tr>
<tr>
<td align="center"><a href="https://github.com/shining-stars-lk"><img src="https://avatars.githubusercontent.com/u/40255310?v=4?s=64" width="64px;"/></a></td>
<td align="center">陆宽</td>
<td align="center" ><a href="https://github.com/shining-stars-lk">shining-stars-lk</a></td>
<td align="center" ><a href="https://blog.csdn.net/guntun8987">宽仔的代码之路</a></td>
<td align="center" >1031900093@qq.com</td>
</tr>
<tr>
<td align="center"><a href="https://github.com/iwangjie"><img src="https://avatars.githubusercontent.com/u/23075587?v=4?s=64" width="64px;"/></a></td>
<td align="center">王杰</td>
<td align="center" ><a href="https://github.com/iwangjie">iwangjie</a></td>
<td align="center" >-</td>
<td align="center" >wangchenmo1025@gmail.com</td>
</tr>
<tr>
<td align="center"><a href="https://github.com/weihubeats"><img src="https://avatars.githubusercontent.com/u/42484192?v=4?s=64" width="64px;"/></a></td>
<td align="center">魏虎</td>
<td align="center" ><a href="https://github.com/weihubeats">weihubeats</a></td>
<td align="center" ><a href="https://weihubeats.blog.csdn.net/">weihubeats</a></td>
<td align="center" >weihubeats@163.com</td>
</tr>
<tr>
<td align="center"><a href="https://github.com/BigXin0109"><img src="https://avatars.githubusercontent.com/u/24769514?v=4?s=64" width="64px;"/></a></td>
<td align="center">李剑鑫</td>
<td align="center" ><a href="https://github.com/BigXin0109">BigXin0109</a></td>
<td align="center" ><a href="https://blog.csdn.net/qq_34741165">OnlyBig</a></td>
<td align="center" >1064730540@qq.com</td>
</tr>
<tr>
<td align="center"><a href="https://github.com/pizihao"><img src="https://avatars.githubusercontent.com/u/48643103?v=4?s=64" width="64px;"/></a></td>
<td align="center">刘文浩</td>
<td align="center" ><a href="https://github.com/pizihao">pizihao</a></td>
<td align="center" ><a href="https://www.yuque.com/chenghu-08dla/pizig1">pizihao</a></td>
<td align="center" >hao3073liu@163.com</td>
</tr>
<tr>
<td align="center"><a href="https://github.com/pizihao"><img src="https://avatars.githubusercontent.com/u/49084314?v=4?s=64" width="64px;"/></a></td>
<td align="center">叶炜</td>
<td align="center" ><a href="https://github.com/shanjianq">shanjianq</a></td>
<td align="center" >-</td>
<td align="center" >17855368071@163.com</td>
</tr>
</table>
## 成为核心开发者
持续对 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) 或以上,以及 6 个 [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。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20221030134303060.png)

@ -0,0 +1,36 @@
---
sidebar_position: 3
---
# 采用公司
## 登记
欢迎采用了 Hippo4J 的公司在此登记,非常感谢大家对 Hippo4J 的关注和支持,这是我们前进最大的动力。
请按公司名 + 首页的格式在 [此处](https://github.com/opengoofy/hippo4j/issues/13) 登记。
## 谁在使用 Hippo4J
共计 20+ 家公司生产接入 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/)

@ -0,0 +1,23 @@
---
sidebar_position: 4
---
# 支持开源
如果您正在使用这个项目并感觉良好,或者是想支持我继续开发,通过以下二维码一次性捐款。
在这里承诺将,将收到的所有赞助支持资金完全公开化,且后续资金用途仅 Hippo-4J 项目的运转。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/IMG_6719_2.jpg?x-oss-process=image/resize,h_180,w_180)
感谢给予支持的朋友,您的支持是 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 | - |

@ -0,0 +1,8 @@
{
"label": "开发者手册",
"position": 5,
"link": {
"type": "generated-index",
"description": "Hippo4J 留给使用者能够扩展的知识点。"
}
}

@ -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 策略)`
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220813173907814.png)
拒绝策略触发时,完成上述代码效果,仅打印异常日志提示。
```text
2022-08-01 21:27:49.515 ERROR 48928 --- [ateHandler.test] r$CustomErrorLogRejectedExecutionHandler : 线程池抛出拒绝策略
```
:::note
具体参考 `hippo4j-example/hippo4j-spring-boot-starter-example` 模块。
:::

@ -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<Runnable> 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);
}
}
}
```

@ -0,0 +1,7 @@
{
"label": "快速开始",
"position": 3,
"link": {
"type": "generated-index"
}
}

@ -0,0 +1,5 @@
{
"label": "依赖配置中心",
"position": 2,
"collapsed": true
}

@ -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` 层级下参数,不提供动态刷新功能。

@ -0,0 +1,117 @@
---
sidebar_position: 3
---
# 线程池监控
## 线程池监控配置
监控前置条件:需要先完成 hippo4j-config 的 [接入工作](/docs/user_docs/getting_started/config/hippo4j-config-start)。
接下来引入 SpringBoot Actuator。Spring 2.x 一般都有版本指定,所以这里不用写版本号。
```xml
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
```
添加动态线程池监控相关配置:
```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_` 前缀的指标,即为成功。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220912220401016.png)
## 配置 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` 路径,能够展示相关指标即为配置成功。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220912221237597.png)
## 配置 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 数据源。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220912221646866.png)
> 如果 Prometheus 为 Docker 方式部署HTTP URL 需要为本地 IP比如http://192.168.1.5:9090
关注公众号 `龙台的技术笔记`,回复:`监控`,获取 Hippo4J Grafana DashBoard JSON 配置。
| 公众号 | 回复关键词 |
|:------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------------------------------:|
| ![](https://images-machen.oss-cn-beijing.aliyuncs.com/43_65f6020ed111b6bb3808ec338576bd6b.png?x-oss-process=image/resize,h_300,w_400) | ![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220327171957444.png?x-oss-process=image/resize,h_300,w_400) |
获取到 JSON 文件后,通过 `http://localhost:3000/dashboard/import` 将 JSON 文件导入至 Grafana DashBoard。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220912225627272.png)
下拉框内动态选择创建好的 Prometheus 数据源,并点击 `Import`
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220912225700200.png)
即可使用炫酷的 Hippo-4J 动态线程池监控 DashBoard。大家伙儿也可以根据个人喜好进行定制 DashBoard如果觉得有优化点欢迎和我联系贡献。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220912225813972.png)
如果项目客户端启动多个示例,动态线程池监控效果图如下:
![](https://images-machen.oss-cn-beijing.aliyuncs.com/20220814_hippo4j_monitor.jpg)

@ -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<br>
* nodes is ip + port.Get 'nodes' in the new Properties,Compare this with the ip + port of Application.<br>
* support prefix pattern matching. e.g: <br>
* <ul>
* <li>192.168.1.5:* -- Matches all ports of 192.168.1.5</li>
* <li>192.168.1.*:2009 -- Matches 2009 port of 192.168.1.*</li>
* <li>* -- all</li>
* <li>empty -- all</li>
* </ul>
* The format of ip + port is ip : port.
*/
```
`nodes` 可与 `enable` 同时使用。如此,基于配置中心的动态线程池实现方式,将能够更方便的支持个性化需求。

@ -0,0 +1,121 @@
---
sidebar_position: 5
---
# 适配SpringBoot1x
目前已支持 Nacos、Apollo 配置中心适配 SpringBoot 1.5.x 版本。
```xml
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-config-spring-boot-1x-starter</artifactId>
<version>1.4.2</version>
</dependency>
```
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`

@ -0,0 +1,193 @@
---
sidebar_position: 1
---
# 接入流程
Nacos、Apollo、Zookeeper、ETCD、Polaris 配置中心任选其一。
## hippo4j 配置
```xml
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-config-spring-boot-starter</artifactId>
<version>1.4.2</version>
</dependency>
```
启动类上添加注解 `@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);
```

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

@ -0,0 +1,72 @@
---
sidebar_position: 6
---
# 三方框架线程池适配
Hippo4J 目前已支持的三方框架线程池列表:
- Dubbo
- Hystrix
- RabbitMQ
- RocketMQ
- AlibabaDubbo
- RocketMQSpringCloudStream
- RabbitMQSpringCloudStream
引入 Hippo4J Server 或 Core 的 Maven Jar 坐标后,还需要引入对应的框架适配 Jar
```xml
<dependency>
<groupId>cn.hippo4j</groupId>
<!-- Dubbo -->
<artifactId>hippo4j-spring-boot-starter-adapter-dubbo</artifactId>
<!-- Alibaba Dubbo -->
<artifactId>hippo4j-spring-boot-starter-adapter-alibaba-dubbo</artifactId>
<!-- Hystrix -->
<artifactId>hippo4j-spring-boot-starter-adapter-hystrix</artifactId>
<!-- RabbitMQ -->
<artifactId>hippo4j-spring-boot-starter-adapter-rabbitmq</artifactId>
<!-- RocketMQ -->
<artifactId>hippo4j-spring-boot-starter-adapter-rocketmq</artifactId>
<!-- SpringCloud Stream RocketMQ -->
<artifactId>hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rocketmq</artifactId>
<!-- SpringCloud Stream RabbitMQ -->
<artifactId>hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rabbitmq</artifactId>
<version>1.4.2</version>
</dependency>
```
如果想省事,仅需引入一个全量包,框架底层会根据条件判断加载具体线程池适配器。
```xml
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-spring-boot-starter-adapter-all</artifactId>
<version>1.4.2</version>
</dependency>
```
## Hippo4J Server
Hippo4J Server 仅需要引入上述 Jar 包,即可在 Hippo4J Server 的控制台进行查看及修改三方框架线程池。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220531194810047.png)
## Hippo4J Config
Hippo4J Config 除了依赖上述适配 Jar 包外,还需要在配置中心添加以下配置项。
```yaml
spring:
dynamic:
thread-pool:
# 省略其它配置
adapter-executors:
# threadPoolKey 代表线程池标识
- threadPoolKey: 'input'
# mark 为三方线程池框架类型,参见文初已支持框架集合
mark: 'RocketMQSpringCloudStream'
corePoolSize: 10
maximumPoolSize: 10
```

@ -0,0 +1,5 @@
{
"label": "无中间件依赖",
"position": 3,
"collapsed": true
}

@ -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 配置后,需要在客户端对应开启才可生效。用来应对大量动态线程池监控场景。

@ -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
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-spring-boot-starter</artifactId>
<version>1.4.2</version>
</dependency>
```
启动类上添加注解 `@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);
```

@ -0,0 +1,73 @@
---
sidebar_position: 1
---
# 简介
## 动态可观测线程池框架
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 容器线程池运行时查看和线程数变更。
- 🌈 中间件适配 - Apache RocketMQ、Dubbo、RabbitMQ、Hystrix 消费线程池运行时数据查看和线程数变更。
> 看完有收获GitHub 右上角帮忙点个小星星,开源作者为爱发电也不容易 🤣
## 快速开始
对于本地演示目的,请参阅 [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
## 联系我
![image](https://user-images.githubusercontent.com/77398366/169202380-6c068acd-700a-41fa-8823-e01c92bb5e88.png)
## 开发者
感谢所有为 Hippo-4J 做出贡献的开发者!
<a href="https://github.com/opengoofy/hippo4j/graphs/contributors"><img src="https://opencollective.com/hippo4j/contributors.svg?width=890&button=false"/></a>
## 我们的荣誉
Hippo-4J 获得了一些宝贵的荣誉,这属于每一位对 Hippo-4J 做出过贡献的成员,谢谢各位的付出。
![](https://user-images.githubusercontent.com/77398366/170607238-7308c9be-1d63-46a6-852c-eef2e4cf7405.JPG)
## Stars 趋势
![](https://starchart.cc/longtai-cn/hippo4j.svg)
## 友情链接
- [[ LiteFlow ]](https://liteflow.yomahub.com/):轻量,快速,稳定可编排的组件式规则引擎。
- [[ Sa-Token ]](https://github.com/dromara/sa-token):一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!
- [[ HertzBeat ]](https://github.com/dromara/hertzbeat):易用友好的云监控系统, 无需 Agent, 强大自定义监控能力。
- [[ JavaGuide ]](https://github.com/Snailclimb/JavaGuide):一份涵盖大部分 Java 程序员所需要掌握的核心知识。
- [[ toBeBetterJavaer ]](https://github.com/itwanger/toBeBetterJavaer)一份通俗易懂、风趣幽默的Java学习指南内容涵盖Java基础、Java并发编程等核心知识点。
## 鸣谢
Hippo4J 项目基于或参考以下项目:[Nacos](https://github.com/alibaba/nacos)、[Eureka](https://github.com/Netflix/Eureka)。
感谢 JetBrains 提供的免费开源 License

@ -0,0 +1,7 @@
{
"label": "运维指南",
"position": 4,
"link": {
"type": "generated-index"
}
}

@ -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
```

@ -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
```

@ -0,0 +1,7 @@
{
"label": "其它",
"position": 6,
"link": {
"type": "generated-index"
}
}

@ -0,0 +1,9 @@
---
sidebar_position: 1
---
# 加群沟通
扫码添加微信,备注:`hippo4j`,邀您加入群聊。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/185774220-c11951f9-e130-4d60-8204-afb5c51d4401.png)

@ -0,0 +1,90 @@
---
sidebar_position: 2
---
# 常见问题
- <a href="#租户和项目在-hippo4j-中是什么意思">租户和项目在 Hippo4J 中是什么意思</a>
- <a href="#控制台线程池管理和线程池实例的区别">控制台线程池管理和线程池实例的区别</a>
- <a href="#示例项目为什么会有跨域请求">示例项目为什么会有跨域请求</a>
- <a href="#更新代码后运行时服务端sql报错">更新代码后运行时服务端SQL报错</a>
- <a href="#生产环境如何不启用动态线程池">生产环境如何不启用动态线程池</a>
- <a href="#server-端宕机会影响-client-运行么">Server 端宕机会影响 Client 运行么</a>
- <a href="#hippo4j-的发布方式是怎样的-如何选择正确的版本">Hippo4J 的发布方式是怎样的?如何选择正确的版本</a>
- <a href="#群机器人接受不到通知报警">群机器人接受不到通知报警</a>
- <a href="#设置线程池参数优先级问题">设置线程池参数优先级问题</a>
- <a href="#线程池实例中修改队列容量参数问题">线程池实例中修改队列容量参数问题</a>
- <a href="#控制台-sockettimeoutexception-connect-timed-out">控制台 SocketTimeoutException: connect timed out</a>
## 租户和项目在 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 包版本不变。
## 群机器人接受不到通知报警
如果是钉钉机器人,需在机器人配置自定义关键字,才可发送成功。如下所示:
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220530200133377.png?x-oss-process=image/resize,h_500,w_800)
如果使用 hippo4j-server请检查在 hippo4j-server 添加的报警通知记录,是否在客户端项目启动前,因为客户端只有在启动时会去 hippo4j-server 拉取报警通知记录。
重启客户端项目,会重新拉取最新报警推送配置,问题解决。
## 设置线程池参数优先级问题
- 当使用 `@DynamicThreadPool` 进行修饰的方法中和在管理界面设置中同时存在的话,则管理界面设置的优先级最高;
- 如果连接 server 端失败的话,使用 `@DynamicThreadPool` 进行修饰设置的优先级最高。
## 线程池实例中修改队列容量参数问题
在线程池管理中添加时,只有当选择队列类型为 `ResizableCapacityLinkedBlockingQueue` 时,后续再进行修改容量大小时才会实时的刷新修改成功。
## 控制台 SocketTimeoutException: connect timed out
控制台中触发的某些操作涉及到 hippo4j-server 调用客户端项目。如果 hippo4j-server 部署在测试环境,而客户端项目为本地启动,则会触发该问题。
为什么编辑线程池参数不报错?因为线程池的动态变更是客户端主动发起连接,和服务端保持了一个长轮询,所以不存在服务端主动调用客户端行为。

@ -0,0 +1,23 @@
---
sidebar_position: 5
---
# 推荐公众号
## JavaGuide
专注Java后端学习和大厂面试的公众号
![](https://images-machen.oss-cn-beijing.aliyuncs.com/JavaGuide.png)
## HelloGitHub
HelloGitHub专注于开源社区技术和知识内容分享。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/HelloGitHub.png)
## macrozheng
专注Java技术分享解析优质开源项目。涵盖SpringBoot、SpringCloud、Docker、K8S等实用技术作者Github开源项目mall50K+Star
![](https://images-machen.oss-cn-beijing.aliyuncs.com/macrozheng.png)

@ -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)。

@ -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都没有结果网站上也许还有报告 BugBug-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 的原因是什么?有谁知道接下来我该做些什么测试才能找出问题?
## 如果得不到回答
如果仍得不到回答,请不要以为我们觉得无法帮助你。有时只是看到你问题的人不知道答案罢了。没有回应不代表你被忽视,虽然不可否认这种差别很难区分。
总的来说,简单的重复张贴问题是个很糟的点子。这将被视为无意义的喧闹。有点耐心,知道你问题答案的人可能生活在不同的时区,可能正在睡觉,也有可能你的问题一开始就没有组织好。
你可以通过其他渠道获得帮助,这些渠道通常更适合初学者的需要。

@ -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线程池上下文获取失败

@ -0,0 +1,8 @@
{
"label": "用户指南",
"position": 2,
"link": {
"type": "generated-index",
"description": "帮助想要了解 Hippo4J 的用户快速掌握核心开发理念。"
}
}

@ -0,0 +1,60 @@
---
sidebar_position: 1
---
# 为什么写
[美团线程池文章](https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html "美团线程池文章") 介绍中,因为业务对线程池参数没有合理配置,触发过几起生产事故,进而引发了一系列思考。最终决定封装线程池动态参数调整,扩展线程池监控以及消息报警等功能。
在开源平台找了挺多动态线程池项目,从功能性以及健壮性而言,个人感觉不满足企业级应用。
因为对动态线程池比较感兴趣,加上想写一个有意义的项目,所以决定自己来造一个轻量级的轮子。
想给项目起一个简单易记的名字,类似于 Eureka、Nacos、Redis后和朋友商量决定命名**Hippo4J**。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/动态线程池功能架构-1.jpg)
## 它解决了什么问题
线程池在业务系统应该都有使用到,帮助业务流程提升效率以及管理线程,多数场景应用于大量的异步任务处理。
虽然线程池提供了我们许多便利,但也并非尽善尽美,比如下面这些问题就无法很好解决。
- 线程池随便定义,线程资源过多,造成服务器高负载。
- 线程池参数不易评估,随着业务的并发提升,业务面临出现故障的风险。
- 线程池任务执行时间超过平均执行周期,开发人员无法感知。
- 线程池任务堆积,触发拒绝策略,影响既有业务正常运行。
- 当业务出现超时、熔断等问题时,因为没有监控,无法确定是不是线程池引起。
- 原生线程池不支持运行时变量的传递,比如 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。

@ -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
对接前端项目,包括不限于以下模块管理:
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20211107122504126.png)
## 消息通知Notify
Hippo4J 内置了很多需要通知的事件,比如:线程池参数变更通知、线程池活跃度报警、拒绝策略执行报警以及阻塞队列容量报警等。
目前 Notify 已经接入了钉钉、企业微信和飞书后续持续集成邮件、短信等通知渠道并且Notify 模块提供了消息事件的 SPI 方案,可以接受三方自定义的推送。
## Hippo4j-Spring-Boot-Starter
熟悉 SpringBoot 的小伙伴对 Starter 应该不会陌生。Hippo4J 提供以 Starter Jar 包的形式嵌套在应用内,负责与 Server 端完成交互。
## 功能架构
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20211105230953626.png)

@ -0,0 +1,71 @@
---
sidebar_position: 4
---
# 通知报警
现阶段已集成钉钉、企业微信、飞书的消息推送,后续会持续接入邮箱、短信和自定义通知渠道。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220904181527453.png)
**通知平台**
- 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://images-machen.oss-cn-beijing.aliyuncs.com/image-20211013122816688.png) | ![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20211013113649068.png) |
添加钉钉机器人后,需在机器人配置自定义关键字,才可发送成功。如下所示:
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220530200133377.png?x-oss-process=image/resize,h_500,w_800)
## 企业微信
[企业微信创建群机器人](https://open.work.weixin.qq.com/help2/pc/14931?person_id=1&from=homesearch)
| 配置变更 | 报警通知 |
| :---: | :---: |
| ![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20211203213443242.png) | ![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20211203213512019.png) |
## 飞书平台
[飞书创建群机器人](https://www.feishu.cn/hc/zh-CN/articles/360024984973)
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220304081729347.png)
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220304081507907.png)

@ -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
## 配置变更
访问控制台动态线程池菜单下线程池实例,修改动态线程池相关参数。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220813173811668.png)
观察 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 集群部署时,可以修改某一个实例,或选择 `全部修改` 按钮,修改所有实例线程池信息。

@ -0,0 +1,7 @@
---
title: Markdown page example
---
# Markdown page example
You don't need React to write simple standalone pages.

@ -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 小马哥版权所有 <a href=\"https://beian.miit.gov.cn\">京ICP备2021038095号-2\n</a>",
"description": "The footer copyright"
}
}

@ -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 🥇代码实战课"
}
}

@ -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 采集监控帮助排查以及确定线程池问题
支持自定义时长线程池运行数据采集存储同时也支持 PrometheusInfluxDB 等采集监控通过 Grafana 或内置监控页面提供可视化大屏监控运行指标
</>
),
},

@ -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';

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Loading…
Cancel
Save