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

pull/1027/head
hongdan.qin 3 years ago
commit d4a64d17e6

@ -1,3 +1,3 @@
# These are supported funding model platforms
custom: ['https://hippo4j.cn/docs/community/sponsor']
custom: ['https://hippo4j.cn/community/sponsor']

@ -3,4 +3,4 @@ Fixes #ISSUSE_ID
Changes proposed in this pull request:
-
> Check mailbox configuration when submitting. [Contributor Guide](https://hippo4j.cn/docs/community/contributor)
> Check mailbox configuration when submitting. [Contributor Guide](https://hippo4j.cn/community/contributor-guide)

@ -43,6 +43,7 @@
- 框架适配 - Dubbo、Hystrix、RabbitMQ、RocketMQ 等消费线程池运行时数据查看和线程数变更。
- 变更审核 - 提供多种用户角色,普通用户变更线程池参数需要 Admin 用户审核方可生效。
- 动态化插件 - 内置多种线程池插件,支持用户自定义插件以及运行时扩展。
- 多版本适配 - 经过实际测试,已支持客户端 SpringBoot 1.5.x => 2.7.5 版本(更高版本未测试)。
## 快速开始
@ -60,6 +61,20 @@
扫码添加微信备注hippo4j邀您加入群聊。若图片加载不出来访问 [官网站点](https://hippo4j.cn/docs/user_docs/other/group)。
## 关于学习
如果您公司没有使用 Hippo4j 场景的话,我也建议去阅读下项目的底层原理,主要有以下几个原因:
- 为了提高代码质量以及后续的扩展行为,运用多种设计模式实现高内聚、低耦合。
- 框架底层依赖 Spring 框架运行,并在源码中大量使用 Spring 相关功能。
- 运用 JUC 并发包下多种工具保障多线程运行安全,通过实际场景理解并发编程。
- 借鉴主流开源框架 Nacos、Eureka 实现轻量级配置中心和注册中心功能。
- 自定义 RPC 框架实现,封装 Netty 完成客户端/服务端网络通信优化。
- 通过 CheckStyle、Spotless 等插件规范代码编写,保障高质量代码行为和代码样式。
> 还有很多优秀的代码设计就不逐一列举了,相信认真研究过底层原理的同学一定会有所收获。
## 友情链接
- [[ Sa-Token ]](https://github.com/dromara/sa-token):一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!

@ -4,7 +4,7 @@ sidebar_position: 1
# 接入流程
Nacos、Apollo、Zookeeper、ETCD、Polaris 配置中心任选其一。
Nacos、Apollo、Zookeeper、ETCD、Polaris、Consul 配置中心任选其一。
## hippo4j 配置
@ -59,7 +59,7 @@ spring:
secret: xxx # 加签专属
- platform: 'LARK'
token: xxx
# Nacos、Apollo、Zookeeper、ETCD、Polaris 任选其一
# Nacos、Apollo、Zookeeper、ETCD、Polaris、Consul 任选其一
nacos:
data-id: xxx
group: xxx

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

@ -47,6 +47,16 @@ spring:
thread-pool-types: dynamic # 采集线程池的类型。egdynamic、web、adapter。可任意配置默认 dynamic
```
如果使用 `micrometer` 类型的监控指标,需要添加以下依赖。
```xml
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-spring-boot-starter-monitor-micrometer</artifactId>
<version>1.4.3-upgrade</version>
</dependency>
```
项目启动,访问 `http://localhost:29999/actuator/prometheus` 出现 `dynamic_thread_pool_` 前缀的指标,即为成功。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220912220401016.png)

@ -116,7 +116,7 @@ const config = {
},
{
href: 'https://xiaomage.info/knowledge-planet',
label: '🥇代码实战课',
label: '知识星球',
position: 'left',
},
{

@ -4,7 +4,7 @@ sidebar_position: 1
# 接入流程
Nacos、Apollo、Zookeeper、ETCD、Polaris 配置中心任选其一。
Nacos、Apollo、Zookeeper、ETCD、Polaris、Consul 配置中心任选其一。
## hippo4j 配置
@ -59,7 +59,7 @@ spring:
secret: xxx # 加签专属
- platform: 'LARK'
token: xxx
# Nacos、Apollo、Zookeeper、ETCD、Polaris 任选其一
# Nacos、Apollo、Zookeeper、ETCD、Polaris、Consul 任选其一
nacos:
data-id: xxx
group: xxx

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

@ -47,6 +47,16 @@ spring:
thread-pool-types: dynamic # 采集线程池的类型。egdynamic、web、adapter。可任意配置默认 dynamic
```
如果使用 `micrometer` 类型的监控指标,需要添加以下依赖。
```xml
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-spring-boot-starter-monitor-micrometer</artifactId>
<version>1.4.3-upgrade</version>
</dependency>
```
项目启动,访问 `http://localhost:29999/actuator/prometheus` 出现 `dynamic_thread_pool_` 前缀的指标,即为成功。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220912220401016.png)

@ -47,6 +47,16 @@ spring:
thread-pool-types: dynamic # 采集线程池的类型。egdynamic、web、adapter。可任意配置默认 dynamic
```
如果使用 `micrometer` 类型的监控指标,需要添加以下依赖。
```xml
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-spring-boot-starter-monitor-micrometer</artifactId>
<version>1.4.3-upgrade</version>
</dependency>
```
项目启动,访问 `http://localhost:29999/actuator/prometheus` 出现 `dynamic_thread_pool_` 前缀的指标,即为成功。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220912220401016.png)

@ -72,6 +72,13 @@ sidebar_position: 1
<td align="center" ><a href="https://blog.xiajibagao.top">Createsequence's Blog</a></td>
<td align="center" >841396397@qq.com</td>
</tr>
<tr>
<td align="center"><a href="https://github.com/road2master"><img src="https://avatars.githubusercontent.com/u/53806703?v=4" width="64px;"/></ a></td>
<td align="center">黎金星</td>
<td align="center"><a href="https://github.com/road2master">road2master</a></td>
<td align="center"><a href="https://www.cnblogs.com/road2master/">road2master's Blog</a></td>
<td align="center">lijinxingerm@gmail.com</td>
</tr>
</table>
## 贡献者

@ -5,7 +5,7 @@ title: 采用公司
## 谁在使用 Hippo4j
共计 23+ 家公司生产接入 Hippo4j。按照公司登记时间排序。
共计 25+ 家公司生产接入 Hippo4j。按照公司登记时间排序。
- [身边云](https://serviceshare.com)
- [思派健康科技](https://www.medbanks.cn)
@ -30,6 +30,8 @@ title: 采用公司
- [三立人(深圳)科技有限公司-焦内](https://www.bananain.com/)
- [上海天猫好房添玑网络服务有限公司](http://www.eju.com/)
- [郑州力通水务](http://www.zzltsw.com/)
- [北京自如信息科技有限公司](https://www.ziroom.com/)
- [易车](https://www.yiche.com/)
## 登记

@ -79,6 +79,13 @@ sidebar_position: 1
<td align="center" >-</td>
<td align="center" >sanliangitch@foxmail.com</td>
</tr>
<tr>
<td align="center"><a href="https://github.com/road2master"><img src="https://avatars.githubusercontent.com/u/53806703?v=4" width="64px;"/></ a></td>
<td align="center">黎金星</td>
<td align="center"><a href="https://github.com/road2master">road2master</a></td>
<td align="center"><a href="https://www.cnblogs.com/road2master/">road2master's Blog</a></td>
<td align="center">lijinxingerm@gmail.com</td>
</tr>
</table>
## 贡献者

@ -5,7 +5,7 @@ title: 采用公司
## 谁在使用 Hippo4j
共计 23+ 家公司生产接入 Hippo4j。按照公司登记时间排序。
共计 25+ 家公司生产接入 Hippo4j。按照公司登记时间排序。
- [身边云](https://serviceshare.com)
- [思派健康科技](https://www.medbanks.cn)
@ -30,6 +30,8 @@ title: 采用公司
- [三立人(深圳)科技有限公司-焦内](https://www.bananain.com/)
- [上海天猫好房添玑网络服务有限公司](http://www.eju.com/)
- [郑州力通水务](http://www.zzltsw.com/)
- [北京自如信息科技有限公司](https://www.ziroom.com/)
- [易车](https://www.yiche.com/)
## 登记

@ -47,6 +47,16 @@ spring:
thread-pool-types: dynamic # 采集线程池的类型。egdynamic、web、adapter。可任意配置默认 dynamic
```
如果使用 `micrometer` 类型的监控指标,需要添加以下依赖。
```xml
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-spring-boot-starter-monitor-micrometer</artifactId>
<version>1.4.3-upgrade</version>
</dependency>
```
项目启动,访问 `http://localhost:29999/actuator/prometheus` 出现 `dynamic_thread_pool_` 前缀的指标,即为成功。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220912220401016.png)

@ -114,7 +114,7 @@ public class DubboThreadPoolAdapter implements ThreadPoolAdapter, ApplicationLis
ConcurrentMap<Integer, ExecutorService> executorServiceMap = data.get(poolKey);
executorServiceMap.forEach((key, value) -> DUBBO_PROTOCOL_EXECUTOR.put(String.valueOf(key), (ThreadPoolExecutor) value));
} catch (Exception ex) {
log.error("Failed to get Dubbo {}.X protocol thread pool", isLegacyVersion ? "2" : "3", ex);
log.error("Failed to get Dubbo {} protocol thread pool", Version.getVersion(), ex);
}
}
}

@ -17,5 +17,74 @@
package cn.hippo4j.common.executor;
import cn.hippo4j.common.design.builder.ThreadFactoryBuilder;
import cn.hippo4j.common.toolkit.MapUtil;
import cn.hippo4j.common.toolkit.ReflectUtil;
import org.junit.Assert;
import org.junit.Test;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.stream.IntStream;
public final class ExecutorFactoryTest {
ThreadFactory threadFactory = new ThreadFactoryBuilder().prefix("test").build();
/**
* data range min
*/
Integer rangeMin = 1;
/**
* data range max
*/
Integer rangeMax = 10;
/**
* default test index
*/
Integer defaultIndex = 0;
@Test
public void assertNewSingleScheduledExecutorService() {
// init data snapshot
ThreadPoolManager poolManager = (ThreadPoolManager) ReflectUtil.getFieldValue(ExecutorFactory.Managed.class, "THREAD_POOL_MANAGER");
String poolName = (String) ReflectUtil.getFieldValue(ExecutorFactory.Managed.class, "DEFAULT_NAMESPACE");
Map<String, Map<String, Set<ExecutorService>>> manager = (Map<String, Map<String, Set<ExecutorService>>>) ReflectUtil.getFieldValue(poolManager, "resourcesManager");
Map<String, Set<ExecutorService>> initRelationMap = manager.get(poolName);
int defaultManagerSize = manager.size();
int defaultRelationSize = MapUtil.isEmpty(initRelationMap) ? 0 : initRelationMap.size();
// test begin
ScheduledExecutorService executorService = ExecutorFactory.Managed.newSingleScheduledExecutorService(String.format("test-group-%s", defaultIndex), threadFactory);
Assert.assertNotNull(executorService);
// check default init
Assert.assertEquals(1, manager.size() - defaultManagerSize);
// check multiple registrations and check to see if it is still an instance
IntStream.rangeClosed(rangeMin, rangeMax).forEach(index -> ExecutorFactory.Managed.newSingleScheduledExecutorService(String.format("test-group-%s", index), threadFactory));
Assert.assertEquals(1, manager.size() - defaultManagerSize);
// check group size
Map<String, Set<ExecutorService>> relationMap = manager.get(poolName);
Assert.assertEquals(11, relationMap.size() - defaultRelationSize);
// check the number of threads between the group and the thread pool
IntStream.rangeClosed(rangeMin, rangeMax).forEach(index -> {
String relationKey = String.format("test-group-%s", index);
Assert.assertNotNull(relationMap.get(relationKey));
Assert.assertEquals(1, relationMap.get(relationKey).size());
});
// instantiate the same group a second time and check the corresponding quantitative relationship
IntStream.rangeClosed(defaultIndex, rangeMax).forEach(index -> ExecutorFactory.Managed.newSingleScheduledExecutorService(String.format("test-group-%s", index), threadFactory));
// chek group size
Assert.assertEquals(11, manager.get(poolName).size() - defaultRelationSize);
// check the number of threads between the group and the thread pool
IntStream.rangeClosed(rangeMin, rangeMax).forEach(index -> Assert.assertEquals(2, relationMap.get(String.format("test-group-%s", index)).size()));
}
}

@ -0,0 +1,102 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.common.web.base;
import cn.hippo4j.common.toolkit.Assert;
import cn.hippo4j.common.web.exception.AbstractException;
import cn.hippo4j.common.web.exception.ErrorCode;
import org.junit.jupiter.api.Test;
import static cn.hippo4j.common.web.exception.ErrorCodeEnum.SERVICE_ERROR;
public class ResultsTest {
@Test
public void success() {
Assert.isTrue(Result.SUCCESS_CODE.equals(Results.success().getCode()));
}
@Test
public void testSuccess() {
Object o = new Object();
Assert.isTrue(o.equals(Results.success(o).getData()));
Assert.isTrue(Result.SUCCESS_CODE.equals(Results.success().getCode()));
}
@Test
public void failure() {
Assert.isTrue(SERVICE_ERROR.getCode().equals(Results.failure().getCode()));
Assert.isTrue(SERVICE_ERROR.getMessage().equals(Results.failure().getMessage()));
}
@Test
public void testFailure() {
String code = "500";
String msg = "message";
AbstractException abstractException = new AbstractException(msg, new Throwable(), new ErrorCode() {
@Override
public String getCode() {
return code;
}
@Override
public String getMessage() {
return "errorMsg";
}
});
Assert.isTrue(code.equals(Results.failure(abstractException).getCode()));
Assert.isTrue(msg.equals(Results.failure(abstractException).getMessage()));
}
@Test
public void testFailure1() {
String msg = "throwableMsg";
Throwable throwable = new Throwable(msg);
Assert.isTrue(SERVICE_ERROR.getCode().equals(Results.failure(throwable).getCode()));
Assert.isTrue(msg.equals(Results.failure(throwable).getMessage()));
}
@Test
public void testFailure2() {
String code = "500";
String msg = "message";
ErrorCode errorCode = new ErrorCode() {
@Override
public String getCode() {
return code;
}
@Override
public String getMessage() {
return msg;
}
};
Assert.isTrue(code.equals(Results.failure(errorCode).getCode()));
Assert.isTrue(msg.equals(Results.failure(errorCode).getMessage()));
}
@Test
public void testFailure3() {
String code = "500";
String msg = "message";
Assert.isTrue(code.equals(Results.failure(code, msg).getCode()));
Assert.isTrue(msg.equals(Results.failure(code, msg).getMessage()));
}
}

@ -37,6 +37,7 @@ 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.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
/**
@ -45,6 +46,12 @@ import java.util.concurrent.atomic.AtomicLong;
@Slf4j
public class DynamicThreadPoolExecutor extends ExtensibleThreadPoolExecutor implements DisposableBean {
/**
* A flag used to indicate whether destroy() method has been called,
* after the flag is set to false, calling destroy() method again will not take effect
*/
private final AtomicBoolean active;
/**
* Wait for tasks to complete on shutdown
*/
@ -92,11 +99,22 @@ public class DynamicThreadPoolExecutor extends ExtensibleThreadPoolExecutor impl
threadPoolId, new DefaultThreadPoolPluginManager().setPluginComparator(AnnotationAwareOrderComparator.INSTANCE),
corePoolSize, maximumPoolSize, keepAliveTime, unit,
blockingQueue, threadFactory, rejectedExecutionHandler);
log.info("Initializing ExecutorService {}", threadPoolId);
log.info("Initializing ExecutorService '{}'", threadPoolId);
this.waitForTasksToCompleteOnShutdown = waitForTasksToCompleteOnShutdown;
// Init default plugins.
new DefaultThreadPoolPluginRegistrar(executeTimeOut, awaitTerminationMillis)
.doRegister(this);
this.active = new AtomicBoolean(true);
}
/**
* <p>Whether the current instance is in the active state. <br />
* It returns false when the xx method is called at least once.
*
* @return true if current instance is in the active state, false otherwise
*/
public boolean isActive() {
return active.get();
}
/**
@ -104,12 +122,21 @@ public class DynamicThreadPoolExecutor extends ExtensibleThreadPoolExecutor impl
*/
@Override
public void destroy() {
// instance has been destroyed, not need to call this method again
if (!isActive()) {
log.warn("Failed to destroy ExecutorService '{}' because it has already been destroyed", getThreadPoolId());
return;
}
if (isWaitForTasksToCompleteOnShutdown()) {
super.shutdown();
} else {
super.shutdownNow();
}
getThreadPoolPluginManager().clear();
log.info("ExecutorService '{}' has been destroyed", getThreadPoolId());
// modify the flag to false avoid the method being called repeatedly
active.set(false);
}
/**

@ -95,7 +95,7 @@ public class DynamicThreadPoolExecutorTest {
});
executor.destroy();
// waitting for terminated
// waiting for terminated
while (!executor.isTerminated()) {
} ;
Assert.assertEquals(2, count.get());
@ -119,9 +119,9 @@ public class DynamicThreadPoolExecutorTest {
});
executor.destroy();
// waitting for terminated
// waiting for terminated
while (!executor.isTerminated()) {
} ;
}
Assert.assertEquals(1, count.get());
}
@ -157,4 +157,21 @@ public class DynamicThreadPoolExecutorTest {
Assert.assertFalse(executor.isWaitForTasksToCompleteOnShutdown());
}
@Test
public void testIsActive() {
DynamicThreadPoolExecutor executor = new DynamicThreadPoolExecutor(
1, 1, 1000L, TimeUnit.MILLISECONDS,
1000L, true, 1000L,
new ArrayBlockingQueue<>(1), "test", Thread::new, new ThreadPoolExecutor.DiscardOldestPolicy());
Assert.assertTrue(executor.isActive());
// waiting for terminated
executor.destroy();
while (!executor.isTerminated()) {
}
Assert.assertFalse(executor.isActive());
executor.destroy();
Assert.assertFalse(executor.isActive());
}
}

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-example</artifactId>
<version>${revision}</version>
</parent>
<artifactId>hippo4j-config-consul-spring-boot-starter-example</artifactId>
<properties>
<maven.deploy.skip>true</maven.deploy.skip>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-example-core</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-config-spring-boot-starter</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-config</artifactId>
<version>${consul.version}</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>

@ -15,37 +15,17 @@
* limitations under the License.
*/
package cn.hippo4j.common.api;
package cn.hippo4j.example.config.consul;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import cn.hippo4j.core.enable.EnableDynamicThreadPool;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* when init thread-pool dynamic refresh.
*/
public interface ThreadPoolInitRefresh extends ApplicationRunner {
/**
* Initializes the thread pool after system startup
*
* @param context new properties
*/
void initRefresh(String context);
/**
* get from the Configuration center
*
* @return new properties
* @throws Exception exception
*/
String getProperties() throws Exception;
@EnableDynamicThreadPool
@SpringBootApplication(scanBasePackages = "cn.hippo4j.example")
public class ConfigConsulExampleApplication {
@Override
default void run(ApplicationArguments args) throws Exception {
String properties = getProperties();
if (properties == null) {
return;
}
initRefresh(properties);
public static void main(String[] args) {
SpringApplication.run(ConfigConsulExampleApplication.class, args);
}
}

@ -0,0 +1,18 @@
server:
port: 8091
spring:
application:
name: hippo4j-config-consul-spring-boot-starter-example
profiles:
active: dev
cloud:
consul:
host: 127.0.0.1
port: 8500
config:
enabled: true
format: yaml
data-key: hippo4j-consul
default-context: application
prefix: config

@ -0,0 +1,52 @@
# 以下内容复制到 consul 配置文件中
# Copy the following to the consul configuration file
spring.dynamic.thread-pool.tomcat.core-pool-size=64
spring.dynamic.thread-pool.tomcat.maximum-pool-size=128
spring.dynamic.thread-pool.tomcat.keep-alive-time=1000
spring.dynamic.thread-pool.tomcat.enable=true
spring.dynamic.thread-pool.default-executor.core-pool-size=1
spring.dynamic.thread-pool.default-executor.maximum-pool-size=2
spring.dynamic.thread-pool.default-executor.blocking-queue=ResizableCapacityLinkedBlockingQueue
spring.dynamic.thread-pool.default-executor.execute-time-out=100
spring.dynamic.thread-pool.default-executor.keep-alive-time=6691
spring.dynamic.thread-pool.default-executor.queue-capacity=1
spring.dynamic.thread-pool.default-executor.rejected-handler=AbortPolicy
spring.dynamic.thread-pool.default-executor.active-alarm=90
spring.dynamic.thread-pool.default-executor.capacity-alarm=85
spring.dynamic.thread-pool.default-executor.alarm=true
spring.dynamic.thread-pool.default-executor.allow-core-thread-time-out=true
spring.dynamic.thread-pool.default-executor.notify.interval=5
spring.dynamic.thread-pool.default-executor.notify.receives=chen.ma
spring.dynamic.thread-pool.notify-platforms[0].platform=WECHAT
spring.dynamic.thread-pool.notify-platforms[0].secret-key=ec3be378-6c99-45d2-a147-b400c7e94a08
spring.dynamic.thread-pool.executors[0].thread-pool-id=message-consume
spring.dynamic.thread-pool.executors[0].thread-name-prefix=message-consume
spring.dynamic.thread-pool.executors[0].core-pool-size=2
spring.dynamic.thread-pool.executors[0].maximum-pool-size=4
spring.dynamic.thread-pool.executors[0].queue-capacity=1024
spring.dynamic.thread-pool.executors[0].blocking-queue=ResizableCapacityLinkedBlockingQueue
spring.dynamic.thread-pool.executors[0].execute-time-out=800
spring.dynamic.thread-pool.executors[0].rejected-handler=AbortPolicy
spring.dynamic.thread-pool.executors[0].keep-alive-time=6691
spring.dynamic.thread-pool.executors[0].allow-core-thread-time-out=true
spring.dynamic.thread-pool.executors[0].alarm=true
spring.dynamic.thread-pool.executors[0].active-alarm=80
spring.dynamic.thread-pool.executors[0].capacity-alarm=80
spring.dynamic.thread-pool.executors[0].notify.interval=8
spring.dynamic.thread-pool.executors[0].notify.receives=chen.ma
spring.dynamic.thread-pool.executors[1].thread-pool-id=message-produce
spring.dynamic.thread-pool.executors[1].thread-name-prefix=message-produce
spring.dynamic.thread-pool.executors[1].core-pool-size=2
spring.dynamic.thread-pool.executors[1].maximum-pool-size=4
spring.dynamic.thread-pool.executors[1].queue-capacity=1024
spring.dynamic.thread-pool.executors[1].blocking-queue=ResizableCapacityLinkedBlockingQueue
spring.dynamic.thread-pool.executors[1].execute-time-out=800
spring.dynamic.thread-pool.executors[1].rejected-handler=AbortPolicy
spring.dynamic.thread-pool.executors[1].keep-alive-time=6691
spring.dynamic.thread-pool.executors[1].allow-core-thread-time-out=true
spring.dynamic.thread-pool.executors[1].alarm=true
spring.dynamic.thread-pool.executors[1].active-alarm=80
spring.dynamic.thread-pool.executors[1].capacity-alarm=80
spring.dynamic.thread-pool.executors[1].notify.interval=8
spring.dynamic.thread-pool.executors[1].notify.receives=chen.ma

@ -21,7 +21,11 @@
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>1.5.1.RELEASE</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.alibaba.boot</groupId>-->
<!-- <artifactId>nacos-config-spring-boot-starter</artifactId>-->
<!-- <version>0.1.4</version>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>

@ -0,0 +1,66 @@
#debug=true
server.port=8089
server.servlet.context-path=/example
management.security.enabled=false
management.context-path=/actuator
spring.profiles.active=dev
spring.application.name=hippo4j-config-nacos-spring-boot-1x-starter-example
## nacos spring-boot
nacos.config.server-addr=127.0.0.1:8848
nacos.config.ext-config[0].data-id=hippo4j-nacos.yaml
nacos.config.ext-config[0].group=DEFAULT_GROUP
nacos.config.ext-config[0].auto-refresh=true
spring.dynamic.thread-pool.enable=true
spring.dynamic.thread-pool.banner=true
spring.dynamic.thread-pool.check-state-interval=5
spring.dynamic.thread-pool.monitor.enable=true
spring.dynamic.thread-pool.monitor.collect-types=micrometer
spring.dynamic.thread-pool.monitor.thread-pool-types=dynamic,web
spring.dynamic.thread-pool.monitor.initial-delay=10000
spring.dynamic.thread-pool.monitor.collect-interval=5000
spring.dynamic.thread-pool.notify-platforms[0].platform=WECHAT
spring.dynamic.thread-pool.notify-platforms[0].token=ac0426a5-c712-474c-9bff-72b8b8f5caff
spring.dynamic.thread-pool.notify-platforms[1].platform=DING
spring.dynamic.thread-pool.notify-platforms[1].token=56417ebba6a27ca352f0de77a2ae9da66d01f39610b5ee8a6033c60ef9071c55
spring.dynamic.thread-pool.notify-platforms[2].platform=LARK
spring.dynamic.thread-pool.notify-platforms[2].token=2cbf2808-3839-4c26-a04d-fd201dd51f9e
spring.dynamic.thread-pool.nacos.data-id=hippo4j-nacos.yaml
spring.dynamic.thread-pool.nacos.group=DEFAULT_GROUP
spring.dynamic.thread-pool.config-file-type=yaml
spring.dynamic.thread-pool.executors[0].thread-pool-id=message-consume
spring.dynamic.thread-pool.executors[0].thread-name-prefix=message-consume
spring.dynamic.thread-pool.executors[0].core-pool-size=2
spring.dynamic.thread-pool.executors[0].maximum-pool-size=4
spring.dynamic.thread-pool.executors[0].queue-capacity=1024
spring.dynamic.thread-pool.executors[0].blocking-queue=ResizableCapacityLinkedBlockingQueue
spring.dynamic.thread-pool.executors[0].execute-time-out=800
spring.dynamic.thread-pool.executors[0].rejected-handler=AbortPolicy
spring.dynamic.thread-pool.executors[0].keep-alive-time=6691
spring.dynamic.thread-pool.executors[0].allow-core-thread-time-out=true
spring.dynamic.thread-pool.executors[0].alarm=true
spring.dynamic.thread-pool.executors[0].active-alarm=80
spring.dynamic.thread-pool.executors[0].capacity-alarm=80
spring.dynamic.thread-pool.executors[0].notify.interval=8
spring.dynamic.thread-pool.executors[0].notify.receives=chen.ma
spring.dynamic.thread-pool.executors[1].thread-pool-id=message-produce
spring.dynamic.thread-pool.executors[1].thread-name-prefix=message-produce
spring.dynamic.thread-pool.executors[1].core-pool-size=2
spring.dynamic.thread-pool.executors[1].maximum-pool-size=4
spring.dynamic.thread-pool.executors[1].queue-capacity=1024
spring.dynamic.thread-pool.executors[1].blocking-queue=ResizableCapacityLinkedBlockingQueue
spring.dynamic.thread-pool.executors[1].execute-time-out=800
spring.dynamic.thread-pool.executors[1].rejected-handler=AbortPolicy
spring.dynamic.thread-pool.executors[1].keep-alive-time=6691
spring.dynamic.thread-pool.executors[1].allow-core-thread-time-out=true
spring.dynamic.thread-pool.executors[1].alarm=true
spring.dynamic.thread-pool.executors[1].active-alarm=80
spring.dynamic.thread-pool.executors[1].capacity-alarm=80
spring.dynamic.thread-pool.executors[1].notify.interval=8
spring.dynamic.thread-pool.executors[1].notify.receives=chen.ma

@ -8,6 +8,7 @@ management.context-path=/actuator
spring.profiles.active=dev
spring.application.name=hippo4j-config-nacos-spring-boot-1x-starter-example
# nacos spring-cloud
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.ext-config[0].data-id=hippo4j-nacos.yaml
spring.cloud.nacos.config.ext-config[0].group=DEFAULT_GROUP

@ -1,6 +1,8 @@
server.port=8091
spring.profiles.active=dev
spring.application.name=hippo4j-spring-boot-starter-adapter-rabbitmq-example
spring.dynamic.thread-pool.server-addr=http://localhost:6691
spring.dynamic.thread-pool.namespace=prescription
spring.dynamic.thread-pool.item-id=dynamic-threadpool-example

@ -21,6 +21,7 @@
<module>hippo4j-config-nacos-spring-boot-starter-example</module>
<module>hippo4j-config-apollo-spring-boot-starter-example</module>
<module>hippo4j-config-zookeeper-spring-boot-starter-example</module>
<module>hippo4j-config-consul-spring-boot-starter-example</module>
<module>hippo4j-spring-boot-starter-adapter-rabbitmq-example</module>
<module>hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rabbitmq-example</module>
<module>hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rocketmq-example</module>

@ -15,18 +15,6 @@
<artifactId>hippo4j-core</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>alibaba-dingtalk-service-sdk</artifactId>
<version>${dingtalk-sdk.version}</version>
<!-- User feedback that javax.jms cannot be downloaded, log4j is not found useful, so it is excluded for the time being. -->
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>

@ -21,16 +21,16 @@ import cn.hippo4j.common.toolkit.CollectionUtil;
import cn.hippo4j.common.toolkit.FileUtil;
import cn.hippo4j.common.toolkit.Singleton;
import cn.hippo4j.common.toolkit.StringUtil;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.common.toolkit.Assert;
import cn.hippo4j.common.toolkit.http.HttpUtil;
import cn.hippo4j.message.dto.NotifyConfigDTO;
import cn.hippo4j.message.enums.NotifyPlatformEnum;
import cn.hippo4j.message.platform.base.AbstractRobotSendMessageHandler;
import cn.hippo4j.message.platform.base.RobotMessageActualContent;
import cn.hippo4j.message.platform.base.RobotMessageExecuteDTO;
import cn.hippo4j.message.platform.constant.DingAlarmConstants;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiRobotSendRequest;
import com.taobao.api.ApiException;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
@ -38,11 +38,14 @@ import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
import static cn.hippo4j.message.platform.constant.DingAlarmConstants.*;
/**
* doc:<a href="https://open.dingtalk.com/document/robots/custom-robot-access"></a>
* Send ding notification message.
*/
@Slf4j
@ -86,20 +89,44 @@ public class DingSendMessageHandler extends AbstractRobotSendMessageHandler {
log.error("Failed to sign the message sent by nailing.", ex);
}
}
DingTalkClient dingTalkClient = new DefaultDingTalkClient(serverUrl);
OapiRobotSendRequest request = new OapiRobotSendRequest();
request.setMsgtype("markdown");
OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown();
markdown.setTitle(Objects.equals(notifyConfig.getType(), "CONFIG") ? DING_NOTICE_TITLE : DING_ALARM_TITLE);
markdown.setText(robotMessageExecuteDTO.getText());
OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
at.setAtMobiles(CollectionUtil.newArrayList(notifyConfig.getReceives().split(",")));
request.setAt(at);
request.setMarkdown(markdown);
String title = Objects.equals(notifyConfig.getType(), "CONFIG") ? DING_NOTICE_TITLE : DING_ALARM_TITLE;
String text = robotMessageExecuteDTO.getText();
ArrayList<String> atMobiles = CollectionUtil.newArrayList(notifyConfig.getReceives().split(","));
HashMap<String, Object> markdown = new HashMap<>();
markdown.put("title", title);
markdown.put("text", text);
HashMap<String, Object> at = new HashMap<>();
at.put("atMobiles", atMobiles);
HashMap<String, Object> markdownJson = new HashMap<>();
markdownJson.put("msgtype", "markdown");
markdownJson.put("markdown", markdown);
markdownJson.put("at", at);
try {
dingTalkClient.execute(request);
} catch (ApiException ex) {
log.error("Ding failed to send message", ex);
String responseBody = HttpUtil.post(serverUrl, markdownJson);
DingRobotResponse response = JSONUtil.parseObject(responseBody, DingRobotResponse.class);
Assert.isTrue(response != null, "Response is null.");
if (response.getErrcode() != 0) {
log.error("Ding failed to send message, reason : {}", response.errmsg);
}
} catch (Exception ex) {
log.error("Ding failed to send message.", ex);
}
}
/**
* Ding robot response.
*/
@Data
static class DingRobotResponse {
/**
* Error code
*/
private Long errcode;
/**
* Error message
*/
private String errmsg;
}
}

@ -108,7 +108,7 @@ public class NettyClientConnection implements ClientConnection {
}
@Override
public void close() {
public synchronized void close() {
if (this.channel == null) {
return;
}

@ -105,12 +105,13 @@ public class NettyServerConnection extends AbstractNettyHandlerManager implement
}
@Override
public void close() {
public synchronized void close() {
if (port == null) {
return;
}
leader.shutdownGracefully();
worker.shutdownGracefully();
this.leader.shutdownGracefully();
this.worker.shutdownGracefully();
this.channel.close();
this.future.channel().close();
log.info("The server is shut down and no more requests are received. The release port is {}", port.getPort());
}
@ -146,4 +147,5 @@ public class NettyServerConnection extends AbstractNettyHandlerManager implement
super.addFirst(handler);
return this;
}
}

@ -27,7 +27,7 @@ import java.io.IOException;
public class NettyServerSupportTest {
@Test
public void bind() throws IOException {
public synchronized void bind() throws IOException {
NettyServerSupport support = new NettyServerSupport(() -> 8891, InstanceServerLoader.class);
support.bind();
while (!support.isActive()) {
@ -35,6 +35,7 @@ public class NettyServerSupportTest {
}
Assert.assertTrue(support.isActive());
support.close();
ThreadUtil.sleep(1000L);
Assert.assertFalse(support.isActive());
}

@ -17,5 +17,59 @@
package cn.hippo4j.auth.toolkit;
import cn.hippo4j.common.toolkit.Assert;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public final class JwtTokenUtilTest {
private Long userId = 1L;
private String username = "baymax";
private String role = "";
private boolean isRememberMe = true;
private String token;
@BeforeEach
public void setUp() {
token = JwtTokenUtil.createToken(userId, username, role, isRememberMe);
}
@Test
public void createToken() {
String name = JwtTokenUtil.getUsername(token);
Assert.isTrue(username.equals(name));
Integer userId = JwtTokenUtil.getUserId(token);
String userRole = JwtTokenUtil.getUserRole(token);
Assert.isTrue(username.equals(name));
Assert.isTrue(this.userId.intValue() == userId);
Assert.isTrue(role.equals(userRole));
}
@Test
public void getUsername() {
String name = JwtTokenUtil.getUsername(token);
Assert.isTrue(username.equals(name));
}
@Test
public void getUserId() {
Integer id = JwtTokenUtil.getUserId(token);
Assert.isTrue(userId.intValue() == id);
}
@Test
public void getUserRole() {
String userRole = JwtTokenUtil.getUserRole(token);
Assert.isTrue(role.equals(userRole));
}
@Test
public void isExpiration() {
boolean isExpiration = JwtTokenUtil.isExpiration(token);
Assert.isTrue(!isExpiration);
}
}

File diff suppressed because one or more lines are too long

@ -1 +1 @@
.social-signup-container[data-v-7309fbbb]{margin:20px 0}.social-signup-container .sign-btn[data-v-7309fbbb]{display:inline-block;cursor:pointer}.social-signup-container .icon[data-v-7309fbbb]{color:#fff;font-size:24px;margin-top:8px}.social-signup-container .qq-svg-container[data-v-7309fbbb],.social-signup-container .wx-svg-container[data-v-7309fbbb]{display:inline-block;width:40px;height:40px;line-height:40px;text-align:center;padding-top:1px;border-radius:4px;margin-bottom:20px;margin-right:5px}.social-signup-container .wx-svg-container[data-v-7309fbbb]{background-color:#24da70}.social-signup-container .qq-svg-container[data-v-7309fbbb]{background-color:#6ba2d6;margin-left:50px}@supports(-webkit-mask:none) and (not (cater-color:#fff)){.login-container .el-input input{color:#fff}}.login-container .el-input{display:inline-block;height:47px;width:85%}.login-container .el-input input{background:transparent;border:0;-webkit-appearance:none;border-radius:0;padding:12px 5px 12px 15px;color:#fff;height:47px;caret-color:#fff}.login-container .el-input input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #283443 inset!important;box-shadow:inset 0 0 0 1000px #283443!important;-webkit-text-fill-color:#fff!important}.login-container .el-form-item{border:1px solid hsla(0,0%,100%,.1);background:rgba(0,0,0,.1);border-radius:5px;color:#454545}.login-container[data-v-13dcd441]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.login-container .login-form[data-v-13dcd441]{position:relative;width:520px;max-width:100%;padding:160px 35px 0;margin:0 auto;overflow:hidden}.login-container .tips[data-v-13dcd441]{font-size:14px;color:#fff;margin-bottom:10px}.login-container .tips span[data-v-13dcd441]:first-of-type{margin-right:16px}.login-container .svg-container[data-v-13dcd441]{padding:6px 5px 6px 15px;color:#889aa4;vertical-align:middle;width:30px;display:inline-block}.login-container .title-container[data-v-13dcd441]{position:relative}.login-container .title-container .title[data-v-13dcd441]{font-size:26px;color:#eee;margin:0 auto 40px auto;text-align:center;font-weight:700}.login-container .show-pwd[data-v-13dcd441]{position:absolute;right:10px;top:7px;font-size:16px;color:#889aa4;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.login-container .thirdparty-button[data-v-13dcd441]{position:absolute;right:0;bottom:6px}@media only screen and (max-width:470px){.login-container .thirdparty-button[data-v-13dcd441]{display:none}}
.social-signup-container[data-v-7309fbbb]{margin:20px 0}.social-signup-container .sign-btn[data-v-7309fbbb]{display:inline-block;cursor:pointer}.social-signup-container .icon[data-v-7309fbbb]{color:#fff;font-size:24px;margin-top:8px}.social-signup-container .qq-svg-container[data-v-7309fbbb],.social-signup-container .wx-svg-container[data-v-7309fbbb]{display:inline-block;width:40px;height:40px;line-height:40px;text-align:center;padding-top:1px;border-radius:4px;margin-bottom:20px;margin-right:5px}.social-signup-container .wx-svg-container[data-v-7309fbbb]{background-color:#24da70}.social-signup-container .qq-svg-container[data-v-7309fbbb]{background-color:#6ba2d6;margin-left:50px}@supports(-webkit-mask:none) and (not (cater-color:#fff)){.login-container .el-input input{color:#fff}}.login-container .el-input{display:inline-block;height:47px;width:85%}.login-container .el-input input{background:transparent;border:0;-webkit-appearance:none;border-radius:0;padding:12px 5px 12px 15px;color:#fff;height:47px;caret-color:#fff}.login-container .el-input input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #283443 inset!important;box-shadow:inset 0 0 0 1000px #283443!important;-webkit-text-fill-color:#fff!important}.login-container .el-form-item{border:1px solid hsla(0,0%,100%,.1);background:rgba(0,0,0,.1);border-radius:5px;color:#454545}.login-container[data-v-7cb824ba]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.login-container .login-form[data-v-7cb824ba]{position:relative;width:520px;max-width:100%;padding:160px 35px 0;margin:0 auto;overflow:hidden}.login-container .tips[data-v-7cb824ba]{font-size:14px;color:#fff;margin-bottom:10px}.login-container .tips span[data-v-7cb824ba]:first-of-type{margin-right:16px}.login-container .svg-container[data-v-7cb824ba]{padding:6px 5px 6px 15px;color:#889aa4;vertical-align:middle;width:30px;display:inline-block}.login-container .title-container[data-v-7cb824ba]{position:relative}.login-container .title-container .title[data-v-7cb824ba]{font-size:26px;color:#eee;margin:0 auto 40px auto;text-align:center;font-weight:700}.login-container .show-pwd[data-v-7cb824ba]{position:absolute;right:10px;top:7px;font-size:16px;color:#889aa4;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.login-container .thirdparty-button[data-v-7cb824ba]{position:absolute;right:0;bottom:6px}@media only screen and (max-width:470px){.login-container .thirdparty-button[data-v-7cb824ba]{display:none}}

@ -1 +0,0 @@
.github-corner:hover .octo-arm[data-v-fedac698]{-webkit-animation:octocat-wave-data-v-fedac698 .56s ease-in-out;animation:octocat-wave-data-v-fedac698 .56s ease-in-out}@-webkit-keyframes octocat-wave-data-v-fedac698{0%,to{-webkit-transform:rotate(0);transform:rotate(0)}20%,60%{-webkit-transform:rotate(-25deg);transform:rotate(-25deg)}40%,80%{-webkit-transform:rotate(10deg);transform:rotate(10deg)}}@keyframes octocat-wave-data-v-fedac698{0%,to{-webkit-transform:rotate(0);transform:rotate(0)}20%,60%{-webkit-transform:rotate(-25deg);transform:rotate(-25deg)}40%,80%{-webkit-transform:rotate(10deg);transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm[data-v-fedac698]{-webkit-animation:none;animation:none}.github-corner .octo-arm[data-v-fedac698]{-webkit-animation:octocat-wave-data-v-fedac698 .56s ease-in-out;animation:octocat-wave-data-v-fedac698 .56s ease-in-out}}.panel-group[data-v-787f9ab2]{margin-top:18px}.panel-group .card-panel-col[data-v-787f9ab2]{margin-bottom:32px}.panel-group .card-panel[data-v-787f9ab2]{height:108px;cursor:pointer;font-size:12px;position:relative;overflow:hidden;color:#666;background:#fff;-webkit-box-shadow:4px 4px 40px rgba(0,0,0,.05);box-shadow:4px 4px 40px rgba(0,0,0,.05);border-color:rgba(0,0,0,.05)}.panel-group .card-panel:hover .card-panel-icon-wrapper[data-v-787f9ab2]{color:#fff}.panel-group .card-panel:hover .icon-people[data-v-787f9ab2]{background:#dae8d6}.panel-group .card-panel:hover .icon-message[data-v-787f9ab2]{background:#36a3f7}.panel-group .card-panel:hover .icon-money[data-v-787f9ab2]{background:#a0a6f4}.panel-group .card-panel:hover .icon-shopping[data-v-787f9ab2]{background:#dae8d6}.panel-group .card-panel .icon-people[data-v-787f9ab2]{color:#40c9c6}.panel-group .card-panel .icon-message[data-v-787f9ab2]{color:#36a3f7}.panel-group .card-panel .icon-money[data-v-787f9ab2]{color:#a0a6f4}.panel-group .card-panel .icon-shopping[data-v-787f9ab2]{color:#34bfa3}.panel-group .card-panel .card-panel-icon-wrapper[data-v-787f9ab2]{float:left;margin:14px 0 0 14px;padding:16px;-webkit-transition:all .38s ease-out;transition:all .38s ease-out;border-radius:6px}.panel-group .card-panel .card-panel-icon[data-v-787f9ab2]{float:left;font-size:48px}.panel-group .card-panel .card-panel-description[data-v-787f9ab2]{float:right;font-weight:700;margin:26px;margin-left:0}.panel-group .card-panel .card-panel-description .card-panel-text[data-v-787f9ab2]{line-height:18px;color:rgba(0,0,0,.45);font-size:16px;margin-bottom:12px}.panel-group .card-panel .card-panel-description .card-panel-num[data-v-787f9ab2]{font-size:20px}@media(max-width:550px){.card-panel-description[data-v-787f9ab2]{display:none}.card-panel-icon-wrapper[data-v-787f9ab2]{float:none!important;width:100%;height:100%;margin:0!important}.card-panel-icon-wrapper .svg-icon[data-v-787f9ab2]{display:block;margin:14px auto!important;float:none!important}}.dashboard-editor-container[data-v-73ee0239]{padding:32px;background-color:#f0f2f5;position:relative}.dashboard-editor-container .github-corner[data-v-73ee0239]{position:absolute;top:0;border:0;right:0}.dashboard-editor-container .el-form-item[data-v-73ee0239]{margin-bottom:5px!important;padding-bottom:20px}.dashboard-editor-container .chart-wrapper[data-v-73ee0239]{background:#fff;padding:16px 16px 0;margin-bottom:32px}@media(max-width:1024px){.chart-wrapper[data-v-73ee0239]{padding:8px}}

@ -0,0 +1 @@
.github-corner:hover .octo-arm[data-v-fedac698]{-webkit-animation:octocat-wave-data-v-fedac698 .56s ease-in-out;animation:octocat-wave-data-v-fedac698 .56s ease-in-out}@-webkit-keyframes octocat-wave-data-v-fedac698{0%,to{-webkit-transform:rotate(0);transform:rotate(0)}20%,60%{-webkit-transform:rotate(-25deg);transform:rotate(-25deg)}40%,80%{-webkit-transform:rotate(10deg);transform:rotate(10deg)}}@keyframes octocat-wave-data-v-fedac698{0%,to{-webkit-transform:rotate(0);transform:rotate(0)}20%,60%{-webkit-transform:rotate(-25deg);transform:rotate(-25deg)}40%,80%{-webkit-transform:rotate(10deg);transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm[data-v-fedac698]{-webkit-animation:none;animation:none}.github-corner .octo-arm[data-v-fedac698]{-webkit-animation:octocat-wave-data-v-fedac698 .56s ease-in-out;animation:octocat-wave-data-v-fedac698 .56s ease-in-out}}.panel-group[data-v-78d00531]{margin-top:18px}.panel-group .card-panel-col[data-v-78d00531]{margin-bottom:32px}.panel-group .card-panel[data-v-78d00531]{height:108px;cursor:pointer;font-size:12px;position:relative;overflow:hidden;color:#666;background:#fff;-webkit-box-shadow:4px 4px 40px rgba(0,0,0,.05);box-shadow:4px 4px 40px rgba(0,0,0,.05);border-color:rgba(0,0,0,.05)}.panel-group .card-panel:hover .card-panel-icon-wrapper[data-v-78d00531]{color:#fff}.panel-group .card-panel:hover .icon-people[data-v-78d00531]{background:#dae8d6}.panel-group .card-panel:hover .icon-message[data-v-78d00531]{background:#36a3f7}.panel-group .card-panel:hover .icon-money[data-v-78d00531]{background:#a0a6f4}.panel-group .card-panel:hover .icon-shopping[data-v-78d00531]{background:#dae8d6}.panel-group .card-panel .icon-people[data-v-78d00531]{color:#40c9c6}.panel-group .card-panel .icon-message[data-v-78d00531]{color:#36a3f7}.panel-group .card-panel .icon-money[data-v-78d00531]{color:#a0a6f4}.panel-group .card-panel .icon-shopping[data-v-78d00531]{color:#34bfa3}.panel-group .card-panel .card-panel-icon-wrapper[data-v-78d00531]{float:left;margin:14px 0 0 14px;padding:16px;-webkit-transition:all .38s ease-out;transition:all .38s ease-out;border-radius:6px}.panel-group .card-panel .card-panel-icon[data-v-78d00531]{float:left;font-size:48px}.panel-group .card-panel .card-panel-description[data-v-78d00531]{float:right;font-weight:700;margin:26px;margin-left:0}.panel-group .card-panel .card-panel-description .card-panel-text[data-v-78d00531]{line-height:18px;color:rgba(0,0,0,.45);font-size:16px;margin-bottom:12px}.panel-group .card-panel .card-panel-description .card-panel-num[data-v-78d00531]{font-size:20px}@media(max-width:550px){.card-panel-description[data-v-78d00531]{display:none}.card-panel-icon-wrapper[data-v-78d00531]{float:none!important;width:100%;height:100%;margin:0!important}.card-panel-icon-wrapper .svg-icon[data-v-78d00531]{display:block;margin:14px auto!important;float:none!important}}.dashboard-editor-container[data-v-6e862226]{padding:32px;background-color:#f0f2f5;position:relative}.dashboard-editor-container .github-corner[data-v-6e862226]{position:absolute;top:0;border:0;right:0}.dashboard-editor-container .el-form-item[data-v-6e862226]{margin-bottom:5px!important;padding-bottom:20px}.dashboard-editor-container .chart-wrapper[data-v-6e862226]{background:#fff;padding:16px 16px 0;margin-bottom:32px}@media(max-width:1024px){.chart-wrapper[data-v-6e862226]{padding:8px}}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-04a4268a"],{"386d":function(n,t,e){"use strict";var r=e("cb7c"),a=e("83a1"),i=e("5f1b");e("214f")("search",1,(function(n,t,e,o){return[function(e){var r=n(this),a=void 0==e?void 0:e[t];return void 0!==a?a.call(e,r):new RegExp(e)[t](String(r))},function(n){var t=o(e,n,this);if(t.done)return t.value;var c=r(n),u=String(this),d=c.lastIndex;a(d,0)||(c.lastIndex=0);var l=i(c,u);return a(c.lastIndex,d)||(c.lastIndex=d),null===l?-1:l.index}]}))},"83a1":function(n,t){n.exports=Object.is||function(n,t){return n===t?0!==n||1/n===1/t:n!=n&&t!=t}},b829:function(n,t,e){"use strict";e.r(t);e("386d");var r,a,i={name:"AuthRedirect",created:function(){var n=window.location.search.slice(1);window.localStorage&&(window.localStorage.setItem("x-admin-oauth-code",n),window.close())},render:function(n){return n()}},o=i,c=e("2877"),u=Object(c["a"])(o,r,a,!1,null,null,null);t["default"]=u.exports}}]);

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d230a36"],{ecac:function(e,t,a){"use strict";a.r(t);var s=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("div",{staticClass:"app-container"},[e.user?a("div",[a("el-row",{attrs:{gutter:20}},[a("el-col",{attrs:{span:6,xs:24}},[a("user-card",{attrs:{user:e.user}})],1),e._v(" "),a("el-col",{attrs:{span:18,xs:24}},[a("el-card",[a("el-tabs",{model:{value:e.activeTab,callback:function(t){e.activeTab=t},expression:"activeTab"}},[a("el-tab-pane",{attrs:{label:"Account",name:"account"}},[a("account",{attrs:{user:e.user}})],1)],1)],1)],1)],1)],1):e._e()])},n=[],r=(a("7f7f"),a("db72")),l=a("2f62"),c=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("el-form",[a("el-form-item",{attrs:{label:"Name"}},[a("el-input",{model:{value:e.user.name,callback:function(t){e.$set(e.user,"name","string"===typeof t?t.trim():t)},expression:"user.name"}})],1),e._v(" "),a("el-form-item",{attrs:{label:"Email"}},[a("el-input",{model:{value:e.user.email,callback:function(t){e.$set(e.user,"email","string"===typeof t?t.trim():t)},expression:"user.email"}})],1),e._v(" "),a("el-form-item",[a("el-button",{attrs:{type:"primary"},on:{click:e.submit}},[e._v("Update")])],1)],1)},i=[],u={props:{user:{type:Object,default:function(){return{name:"",email:""}}}},methods:{submit:function(){this.$message({message:"User information has been updated successfully",type:"success",duration:5e3})}}},o=u,m=a("2877"),p=Object(m["a"])(o,c,i,!1,null,null,null),f=p.exports,b={name:"Profile",components:{Account:f},data:function(){return{user:{},activeTab:"activity"}},computed:Object(r["a"])({},Object(l["b"])(["name","avatar","roles"])),created:function(){this.getUser()},methods:{getUser:function(){this.user={name:this.name,role:this.roles.join(" | "),email:"admin@test.com",avatar:this.avatar}}}},d=b,v=Object(m["a"])(d,s,n,!1,null,null,null);t["default"]=v.exports}}]);

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d230a36"],{ecac:function(e,t,a){"use strict";a.r(t);var s=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("div",{staticClass:"app-container"},[e.user?a("div",[a("el-row",{attrs:{gutter:20}},[a("el-col",{attrs:{span:6,xs:24}},[a("user-card",{attrs:{user:e.user}})],1),e._v(" "),a("el-col",{attrs:{span:18,xs:24}},[a("el-card",[a("el-tabs",{model:{value:e.activeTab,callback:function(t){e.activeTab=t},expression:"activeTab"}},[a("el-tab-pane",{attrs:{label:"Account",name:"account"}},[a("account",{attrs:{user:e.user}})],1)],1)],1)],1)],1)],1):e._e()])},n=[],r=a("5530"),l=(a("b0c0"),a("a15b"),a("2f62")),c=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("el-form",[a("el-form-item",{attrs:{label:"Name"}},[a("el-input",{model:{value:e.user.name,callback:function(t){e.$set(e.user,"name","string"===typeof t?t.trim():t)},expression:"user.name"}})],1),e._v(" "),a("el-form-item",{attrs:{label:"Email"}},[a("el-input",{model:{value:e.user.email,callback:function(t){e.$set(e.user,"email","string"===typeof t?t.trim():t)},expression:"user.email"}})],1),e._v(" "),a("el-form-item",[a("el-button",{attrs:{type:"primary"},on:{click:e.submit}},[e._v("Update")])],1)],1)},i=[],u={props:{user:{type:Object,default:function(){return{name:"",email:""}}}},methods:{submit:function(){this.$message({message:"User information has been updated successfully",type:"success",duration:5e3})}}},o=u,m=a("2877"),p=Object(m["a"])(o,c,i,!1,null,null,null),b=p.exports,f={name:"Profile",components:{Account:b},data:function(){return{user:{},activeTab:"activity"}},computed:Object(r["a"])({},Object(l["b"])(["name","avatar","roles"])),created:function(){this.getUser()},methods:{getUser:function(){this.user={name:this.name,role:this.roles.join(" | "),email:"admin@test.com",avatar:this.avatar}}}},d=f,v=Object(m["a"])(d,s,n,!1,null,null,null);t["default"]=v.exports}}]);

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d230fe7"],{ef3c:function(e,r,n){"use strict";n.r(r);n("a481");var t,u,a={created:function(){var e=this.$route,r=e.params,n=e.query,t=r.path;this.$router.replace({path:"/"+t,query:n})},render:function(e){return e()}},c=a,o=n("2877"),p=Object(o["a"])(c,t,u,!1,null,null,null);r["default"]=p.exports}}]);

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d230fe7"],{ef3c:function(e,r,n){"use strict";n.r(r);n("ac1f"),n("5319");var t,u,a={created:function(){var e=this.$route,r=e.params,n=e.query,t=r.path;this.$router.replace({path:"/"+t,query:n})},render:function(e){return e()}},c=a,o=n("2877"),p=Object(o["a"])(c,t,u,!1,null,null,null);r["default"]=p.exports}}]);

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-9472305a"],{"129f":function(n,e){n.exports=Object.is||function(n,e){return n===e?0!==n||1/n===1/e:n!=n&&e!=e}},"841c":function(n,e,t){"use strict";var a=t("c65b"),c=t("d784"),r=t("825a"),o=t("7234"),i=t("1d80"),u=t("129f"),d=t("577e"),l=t("dc4a"),s=t("14c3");c("search",(function(n,e,t){return[function(e){var t=i(this),c=o(e)?void 0:l(e,n);return c?a(c,e,t):new RegExp(e)[n](d(t))},function(n){var a=r(this),c=d(n),o=t(e,a,c);if(o.done)return o.value;var i=a.lastIndex;u(i,0)||(a.lastIndex=0);var l=s(a,c);return u(a.lastIndex,i)||(a.lastIndex=i),null===l?-1:l.index}]}))},b829:function(n,e,t){"use strict";t.r(e);t("fb6a"),t("ac1f"),t("841c");var a,c,r={name:"AuthRedirect",created:function(){var n=window.location.search.slice(1);window.localStorage&&(window.localStorage.setItem("x-admin-oauth-code",n),window.close())},render:function(n){return n()}},o=r,i=t("2877"),u=Object(i["a"])(o,a,c,!1,null,null,null);e["default"]=u.exports}}]);

@ -1 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-ef888edc"],{"24e2":function(t,a,i){"use strict";i.r(a);var e=function(){var t=this,a=t.$createElement,i=t._self._c||a;return i("div",{staticClass:"errPage-container"},[i("el-button",{staticClass:"pan-back-btn",attrs:{icon:"arrow-left"},on:{click:t.back}},[t._v("\n 返回\n ")]),t._v(" "),i("el-row",[i("el-col",{attrs:{span:12}},[i("h1",{staticClass:"text-jumbo text-ginormous"},[t._v("\n Oops!\n ")]),t._v("\n gif来源"),i("a",{attrs:{href:"https://zh.airbnb.com/",target:"_blank"}},[t._v("airbnb")]),t._v(" 页面\n "),i("h2",[t._v("你没有权限去该页面")]),t._v(" "),i("h6",[t._v("如有不满请联系你领导")]),t._v(" "),i("ul",{staticClass:"list-unstyled"},[i("li",[t._v("或者你可以去:")]),t._v(" "),i("li",{staticClass:"link-type"},[i("router-link",{attrs:{to:"/dashboard"}},[t._v("\n 回首页\n ")])],1),t._v(" "),i("li",{staticClass:"link-type"},[i("a",{attrs:{href:"https://www.taobao.com/"}},[t._v("随便看看")])]),t._v(" "),i("li",[i("a",{attrs:{href:"#"},on:{click:function(a){a.preventDefault(),t.dialogVisible=!0}}},[t._v("点我看图")])])])]),t._v(" "),i("el-col",{attrs:{span:12}},[i("img",{attrs:{src:t.errGif,width:"313",height:"428",alt:"Girl has dropped her ice cream."}})])],1),t._v(" "),i("el-dialog",{attrs:{visible:t.dialogVisible,title:"随便看"},on:{"update:visible":function(a){t.dialogVisible=a}}},[i("img",{staticClass:"pan-img",attrs:{src:t.ewizardClap}})])],1)},s=[],n=i("cc6c"),r=i.n(n),l={name:"Page401",data:function(){return{errGif:r.a+"?"+ +new Date,ewizardClap:"https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646",dialogVisible:!1}},methods:{back:function(){this.$route.query.noGoBack?this.$router.push({path:"/dashboard"}):this.$router.go(-1)}}},c=l,o=(i("6f5a"),i("2877")),u=Object(o["a"])(c,e,s,!1,null,"6fb1594e",null);a["default"]=u.exports},"6f5a":function(t,a,i){"use strict";i("a68a")},a68a:function(t,a,i){},cc6c:function(t,a,i){t.exports=i.p+"static/img/401.089007e7.gif"}}]);
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-ef888edc"],{"24e2":function(t,a,i){"use strict";i.r(a);var e=function(){var t=this,a=t.$createElement,i=t._self._c||a;return i("div",{staticClass:"errPage-container"},[i("el-button",{staticClass:"pan-back-btn",attrs:{icon:"arrow-left"},on:{click:t.back}},[t._v("\n 返回\n ")]),t._v(" "),i("el-row",[i("el-col",{attrs:{span:12}},[i("h1",{staticClass:"text-jumbo text-ginormous"},[t._v("\n Oops!\n ")]),t._v("\n gif来源"),i("a",{attrs:{href:"https://zh.airbnb.com/",target:"_blank"}},[t._v("airbnb")]),t._v(" 页面\n "),i("h2",[t._v("你没有权限去该页面")]),t._v(" "),i("h6",[t._v("如有不满请联系你领导")]),t._v(" "),i("ul",{staticClass:"list-unstyled"},[i("li",[t._v("或者你可以去:")]),t._v(" "),i("li",{staticClass:"link-type"},[i("router-link",{attrs:{to:"/dashboard"}},[t._v("\n 回首页\n ")])],1),t._v(" "),i("li",{staticClass:"link-type"},[i("a",{attrs:{href:"https://www.taobao.com/"}},[t._v("随便看看")])]),t._v(" "),i("li",[i("a",{attrs:{href:"#"},on:{click:function(a){a.preventDefault(),t.dialogVisible=!0}}},[t._v("点我看图")])])])]),t._v(" "),i("el-col",{attrs:{span:12}},[i("img",{attrs:{src:t.errGif,width:"313",height:"428",alt:"Girl has dropped her ice cream."}})])],1),t._v(" "),i("el-dialog",{attrs:{visible:t.dialogVisible,title:"随便看"},on:{"update:visible":function(a){t.dialogVisible=a}}},[i("img",{staticClass:"pan-img",attrs:{src:t.ewizardClap}})])],1)},s=[],n=(i("14d9"),i("cc6c")),r=i.n(n),l={name:"Page401",data:function(){return{errGif:r.a+"?"+ +new Date,ewizardClap:"https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646",dialogVisible:!1}},methods:{back:function(){this.$route.query.noGoBack?this.$router.push({path:"/dashboard"}):this.$router.go(-1)}}},c=l,o=(i("6f5a"),i("2877")),u=Object(o["a"])(c,e,s,!1,null,"6fb1594e",null);a["default"]=u.exports},"6f5a":function(t,a,i){"use strict";i("a68a")},a68a:function(t,a,i){},cc6c:function(t,a,i){t.exports=i.p+"static/img/401.089007e7.gif"}}]);

@ -47,6 +47,13 @@
<version>${apollo.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-config</artifactId>
<version>${consul.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>

@ -17,19 +17,26 @@
package cn.hippo4j.config.springboot.starter.config;
import cn.hippo4j.config.springboot.starter.refresher.*;
import com.alibaba.cloud.nacos.NacosConfigManager;
import cn.hippo4j.config.springboot.starter.refresher.ApolloRefresherHandler;
import cn.hippo4j.config.springboot.starter.refresher.BootstrapConfigPropertiesBinderAdapt;
import cn.hippo4j.config.springboot.starter.refresher.ConsulRefresherHandler;
import cn.hippo4j.config.springboot.starter.refresher.DefaultBootstrapConfigPropertiesBinderAdapt;
import cn.hippo4j.config.springboot.starter.refresher.EtcdRefresherHandler;
import cn.hippo4j.config.springboot.starter.refresher.NacosCloudRefresherHandler;
import cn.hippo4j.config.springboot.starter.refresher.NacosRefresherHandler;
import cn.hippo4j.config.springboot.starter.refresher.PolarisRefresherHandler;
import cn.hippo4j.config.springboot.starter.refresher.ZookeeperRefresherHandler;
import com.alibaba.cloud.nacos.NacosConfigProperties;
import com.alibaba.nacos.api.config.ConfigService;
import com.tencent.polaris.configuration.api.core.ConfigFileService;
import io.etcd.jetcd.Client;
import lombok.RequiredArgsConstructor;
import org.apache.curator.framework.CuratorFramework;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.consul.config.ConsulConfigProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -41,10 +48,14 @@ public class ConfigHandlerConfiguration {
private static final String NACOS_CONFIG_MANAGER_KEY = "com.alibaba.cloud.nacos.NacosConfigManager";
private static final String NACOS_INJECTED_BEAN_NAME = "com.alibaba.nacos.spring.beans.factory.annotation.AnnotationNacosInjectedBeanPostProcessor";
private static final String NACOS_DATA_ID_KEY = "nacos.data-id";
private static final String APOLLO_NAMESPACE_KEY = "apollo.namespace";
private static final String CONSUL_DATA_KEY = "consul.data-key";
private static final String ZOOKEEPER_CONNECT_STR_KEY = "zookeeper.zk-connect-str";
private static final String ETCD = "etcd.endpoints";
@ -58,18 +69,18 @@ public class ConfigHandlerConfiguration {
}
@RequiredArgsConstructor
@ConditionalOnClass(ConfigService.class)
@ConditionalOnClass(value = ConfigService.class, name = NACOS_INJECTED_BEAN_NAME)
@ConditionalOnMissingClass(NACOS_CONFIG_MANAGER_KEY)
@ConditionalOnProperty(prefix = BootstrapConfigProperties.PREFIX, name = NACOS_DATA_ID_KEY)
static class EmbeddedNacos {
@Bean
public NacosRefresherHandler nacosRefresherHandler(NacosConfigProperties nacosConfigProperties) {
return new NacosRefresherHandler(nacosConfigProperties);
public NacosRefresherHandler nacosRefresherHandler() {
return new NacosRefresherHandler();
}
}
@ConditionalOnClass(NacosConfigManager.class)
@ConditionalOnClass(NacosConfigProperties.class)
@ConditionalOnProperty(prefix = BootstrapConfigProperties.PREFIX, name = NACOS_DATA_ID_KEY)
static class EmbeddedNacosCloud {
@ -89,6 +100,16 @@ public class ConfigHandlerConfiguration {
}
}
@ConditionalOnClass(ConsulConfigProperties.class)
@ConditionalOnProperty(prefix = BootstrapConfigProperties.PREFIX, name = CONSUL_DATA_KEY)
static class EmbeddedConsul {
@Bean
public ConsulRefresherHandler consulRefresher() {
return new ConsulRefresherHandler();
}
}
@ConditionalOnClass(CuratorFramework.class)
@ConditionalOnProperty(prefix = BootstrapConfigProperties.PREFIX, name = ZOOKEEPER_CONNECT_STR_KEY)
static class EmbeddedZookeeper {

@ -21,7 +21,7 @@ import cn.hippo4j.common.api.ThreadPoolCheckAlarm;
import cn.hippo4j.common.api.ThreadPoolConfigChange;
import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hippo4j.config.springboot.starter.monitor.ThreadPoolMonitorExecutor;
import cn.hippo4j.config.springboot.starter.notify.CoreNotifyConfigBuilder;
import cn.hippo4j.config.springboot.starter.notify.ConfigModeNotifyConfigBuilder;
import cn.hippo4j.config.springboot.starter.refresher.event.AdapterExecutorsRefreshListener;
import cn.hippo4j.config.springboot.starter.refresher.event.DynamicThreadPoolRefreshListener;
import cn.hippo4j.config.springboot.starter.refresher.event.PlatformsRefreshListener;
@ -77,7 +77,7 @@ public class DynamicThreadPoolAutoConfiguration {
@Bean
public NotifyConfigBuilder notifyConfigBuilder(AlarmControlHandler alarmControlHandler) {
return new CoreNotifyConfigBuilder(alarmControlHandler, bootstrapConfigProperties);
return new ConfigModeNotifyConfigBuilder(alarmControlHandler, bootstrapConfigProperties);
}
@Bean
@ -105,9 +105,9 @@ public class DynamicThreadPoolAutoConfiguration {
@Bean
@SuppressWarnings("all")
public DynamicThreadPoolRefreshListener hippo4jExecutorsListener(ThreadPoolConfigChange threadPoolConfigChange,
CoreNotifyConfigBuilder coreNotifyConfigBuilder,
ConfigModeNotifyConfigBuilder configModeNotifyConfigBuilder,
Hippo4jBaseSendMessageService hippoBaseSendMessageService) {
return new DynamicThreadPoolRefreshListener(threadPoolConfigChange, coreNotifyConfigBuilder, hippoBaseSendMessageService);
return new DynamicThreadPoolRefreshListener(threadPoolConfigChange, configModeNotifyConfigBuilder, hippoBaseSendMessageService);
}
@Bean

@ -32,11 +32,11 @@ import java.util.*;
import java.util.stream.Collectors;
/**
* Core notify config builder.
* Config mode notify config builder.
*/
@AllArgsConstructor
@Slf4j
public class CoreNotifyConfigBuilder implements NotifyConfigBuilder {
public class ConfigModeNotifyConfigBuilder implements NotifyConfigBuilder {
private final AlarmControlHandler alarmControlHandler;

@ -18,7 +18,6 @@
package cn.hippo4j.config.springboot.starter.refresher;
import cn.hippo4j.common.api.ThreadPoolDynamicRefresh;
import cn.hippo4j.common.api.ThreadPoolInitRefresh;
import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hippo4j.common.toolkit.CollectionUtil;
import cn.hippo4j.config.springboot.starter.config.BootstrapConfigProperties;
@ -27,6 +26,8 @@ import cn.hippo4j.config.springboot.starter.refresher.event.Hippo4jConfigDynamic
import cn.hippo4j.core.executor.support.ThreadPoolBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import java.util.Map;
import java.util.Optional;
@ -36,7 +37,7 @@ import java.util.concurrent.ExecutorService;
* Abstract core thread-pool dynamic refresh.
*/
@Slf4j
public abstract class AbstractConfigThreadPoolDynamicRefresh implements ThreadPoolDynamicRefresh, ThreadPoolInitRefresh, InitializingBean {
public abstract class AbstractConfigThreadPoolDynamicRefresh implements ThreadPoolDynamicRefresh, InitializingBean, ApplicationRunner {
private final BootstrapConfigPropertiesBinderAdapt bootstrapConfigPropertiesBinderAdapt;
@ -49,10 +50,10 @@ public abstract class AbstractConfigThreadPoolDynamicRefresh implements ThreadPo
bootstrapConfigPropertiesBinderAdapt = ApplicationContextHolder.getBean(BootstrapConfigPropertiesBinderAdapt.class);
}
@Override
public void initRefresh(String context) {
dynamicRefresh(context);
}
/**
* Init register listener.
*/
protected abstract void initRegisterListener();
@Override
public void dynamicRefresh(String configContent) {
@ -67,9 +68,31 @@ public abstract class AbstractConfigThreadPoolDynamicRefresh implements ThreadPo
Optional.ofNullable(configInfo).ifPresent(each -> each.putAll(newValueChangeMap));
}
BootstrapConfigProperties binderCoreProperties = bootstrapConfigPropertiesBinderAdapt.bootstrapCorePropertiesBinder(configInfo, bootstrapConfigProperties);
ApplicationContextHolder.getInstance().publishEvent(new Hippo4jConfigDynamicRefreshEvent(this, binderCoreProperties));
publishDynamicThreadPoolEvent(binderCoreProperties);
} catch (Exception ex) {
log.error("Hippo4j config mode dynamic refresh failed.", ex);
}
}
private void publishDynamicThreadPoolEvent(BootstrapConfigProperties configProperties) {
ApplicationContextHolder.getInstance().publishEvent(new Hippo4jConfigDynamicRefreshEvent(this, configProperties));
}
@Override
public void afterPropertiesSet() {
try {
initRegisterListener();
} catch (Exception ex) {
log.error("Hippo4j failed to initialize register listener.", ex);
}
}
@Override
public void run(ApplicationArguments args) {
try {
publishDynamicThreadPoolEvent(bootstrapConfigProperties);
} catch (Exception ex) {
log.error("Hippo-4J core dynamic refresh failed.", ex);
log.error("Hippo4j failed to initialize update configuration.", ex);
}
}
}

@ -42,17 +42,7 @@ public class ApolloRefresherHandler extends AbstractConfigThreadPoolDynamicRefre
private String namespace;
@Override
public String getProperties() {
String[] apolloNamespaces = this.namespace.split(",");
this.namespace = apolloNamespaces[0];
String copyNamespace = this.namespace.replaceAll("." + bootstrapConfigProperties.getConfigFileType().getValue(), "");
ConfigFileFormat configFileFormat = ConfigFileFormat.fromString(bootstrapConfigProperties.getConfigFileType().getValue());
ConfigFile configFile = ConfigService.getConfigFile(copyNamespace, configFileFormat);
return configFile.getContent();
}
@Override
public void afterPropertiesSet() {
public void initRegisterListener() {
String[] apolloNamespaces = this.namespace.split(",");
this.namespace = apolloNamespaces[0];
Config config = ConfigService.getConfig(String.format("%s.%s", namespace, bootstrapConfigProperties.getConfigFileType().getValue()));

@ -0,0 +1,79 @@
/*
* 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.config.springboot.starter.refresher;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.cloud.bootstrap.config.BootstrapPropertySource;
import org.springframework.cloud.consul.config.ConsulPropertySource;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.env.AbstractEnvironment;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* Consul refresher handler.
*/
@Slf4j
public class ConsulRefresherHandler extends AbstractConfigThreadPoolDynamicRefresh {
@EventListener(EnvironmentChangeEvent.class)
public void refreshed(EnvironmentChangeEvent event) {
Map<String, Object> configInfo = extractLatestConfigInfo(event);
dynamicRefresh(StringUtils.EMPTY, configInfo);
}
private Map<String, Object> extractLatestConfigInfo(EnvironmentChangeEvent event) {
AbstractEnvironment environment = (AbstractEnvironment) ((AnnotationConfigServletWebServerApplicationContext) event.getSource()).getEnvironment();
String activeProfile = Optional.ofNullable(environment.getActiveProfiles().length > 0 ? environment.getActiveProfiles()[0] : null)
.orElseGet(() -> String.valueOf(getApplicationConfigDefaultContext(environment)));
List<BootstrapPropertySource<?>> bootstrapPropertySourceList = environment.getPropertySources().stream()
.filter(propertySource -> propertySource instanceof BootstrapPropertySource)
.map(propertySource -> (BootstrapPropertySource<?>) propertySource).collect(Collectors.toList());
Optional<BootstrapPropertySource<?>> bootstrapPropertySource = bootstrapPropertySourceList.stream()
.filter(source -> source.getName().contains(activeProfile) && source.getPropertyNames().length != 0).findFirst();
Map<String, Object> configInfo = new HashMap<>(64);
if (bootstrapPropertySource.isPresent()) {
ConsulPropertySource consulPropertySource = (ConsulPropertySource) bootstrapPropertySource.get().getDelegate();
String[] propertyNames = consulPropertySource.getPropertyNames();
for (String propertyName : propertyNames) {
configInfo.put(propertyName, consulPropertySource.getProperty(propertyName));
}
}
return configInfo;
}
private CharSequence getApplicationConfigDefaultContext(AbstractEnvironment environment) {
return environment.getPropertySources().stream()
.filter(propertySource -> propertySource instanceof OriginTrackedMapPropertySource)
.map(propertySource -> ((Map<String, CharSequence>) propertySource.getSource()).get("spring.cloud.consul.config.default-context"))
.findFirst().orElse(StringUtils.EMPTY);
}
@Override
protected void initRegisterListener() {
// The listener has been registered by annotation.
}
}

@ -23,12 +23,14 @@ import io.etcd.jetcd.*;
import io.etcd.jetcd.kv.GetResponse;
import io.etcd.jetcd.watch.WatchEvent;
import io.etcd.jetcd.watch.WatchResponse;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
/**
* Etcd refresher handler.
@ -50,19 +52,9 @@ public class EtcdRefresherHandler extends AbstractConfigThreadPoolDynamicRefresh
private static final String KEY = "key";
@SneakyThrows(value = {InterruptedException.class, ExecutionException.class})
@Override
public String getProperties() throws Exception {
Map<String, String> etcd = bootstrapConfigProperties.getEtcd();
Charset charset = StringUtil.isBlank(etcd.get(CHARSET)) ? StandardCharsets.UTF_8 : Charset.forName(etcd.get(CHARSET));
initClient(etcd, charset);
String key = etcd.get(KEY);
GetResponse getResponse = client.getKVClient().get(ByteSequence.from(key, charset)).get();
KeyValue keyValue = getResponse.getKvs().get(0);
return Objects.isNull(keyValue) ? null : keyValue.getValue().toString(charset);
}
@Override
public void afterPropertiesSet() throws Exception {
public void initRegisterListener() {
Map<String, String> etcd = bootstrapConfigProperties.getEtcd();
String key = etcd.get(KEY);
Charset charset = StringUtil.isBlank(etcd.get(CHARSET)) ? StandardCharsets.UTF_8 : Charset.forName(etcd.get(CHARSET));

@ -18,8 +18,11 @@
package cn.hippo4j.config.springboot.starter.refresher;
import cn.hippo4j.common.config.ApplicationContextHolder;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.cloud.nacos.NacosConfigProperties;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
@ -35,24 +38,17 @@ public class NacosCloudRefresherHandler extends AbstractConfigThreadPoolDynamicR
static final String GROUP = "group";
private final NacosConfigManager nacosConfigManager;
private final ConfigService configService;
public NacosCloudRefresherHandler() {
nacosConfigManager = ApplicationContextHolder.getBean(NacosConfigManager.class);
configService = ApplicationContextHolder.getBean(NacosConfigProperties.class).configServiceInstance();
}
@SneakyThrows(NacosException.class)
@Override
public String getProperties() throws Exception {
public void initRegisterListener() {
Map<String, String> nacosConfig = bootstrapConfigProperties.getNacos();
String dataId = nacosConfig.get(DATA_ID);
String group = nacosConfig.get(GROUP);
return nacosConfigManager.getConfigService().getConfig(dataId, group, 5000L);
}
@Override
public void afterPropertiesSet() throws Exception {
Map<String, String> nacosConfig = bootstrapConfigProperties.getNacos();
nacosConfigManager.getConfigService().addListener(nacosConfig.get(DATA_ID),
configService.addListener(nacosConfig.get(DATA_ID),
nacosConfig.get(GROUP), new Listener() {
@Override

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

Loading…
Cancel
Save