Merge branch 'opengoofy:develop' into develop

pull/680/head
lucky 8 3 years ago committed by GitHub
commit 7f99067fe0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -56,6 +56,8 @@ Hippo-4J 获得了一些宝贵的荣誉,这属于每一位对 Hippo-4J 做出
## 友情链接
- [[ LiteFlow ]](https://liteflow.yomahub.com/):轻量,快速,稳定可编排的组件式规则引擎。
- [[ Sa-Token ]](https://github.com/dromara/sa-token):一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!
- [[ HertzBeat ]](https://github.com/dromara/hertzbeat):易用友好的云监控系统, 无需 Agent, 强大自定义监控能力。

@ -2,14 +2,11 @@
sidebar_position: 3
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# 快速开始
## 服务启动
MySQL 创建名为 `hippo4j_manager`数据库,字符集选择 `utf8mb4`,并导入 [Hippo4J 初始化 SQL 语句](https://github.com/longtai-cn/hippo4j/blob/develop/hippo4j-server/conf/hippo4j_manager.sql)。
MySQL 数据库导入 [Hippo4J 初始化 SQL 语句](https://github.com/longtai-cn/hippo4j/blob/develop/hippo4j-server/conf/hippo4j_manager.sql)。
使用 Docker 运行服务端,可以灵活定制相关参数。如果 MySQL 非 Docker 部署,`MYSQL_HOST` 需要使用本地 IP。

@ -0,0 +1,106 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.common.model;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
/**
* Web ip and port info
*/
@Data
@Slf4j
public class WebIpAndPortInfo {
protected static final String ALL = "*";
protected static final String SPOT = "\\.";
protected static final String COLON = ":";
private String ip;
private String port;
private String[] ipSegment;
public WebIpAndPortInfo(String ip, String port) {
this.ip = ip;
this.port = port;
this.ipSegment = ip.split(SPOT);
}
public static WebIpAndPortInfo build(String node) {
if (ALL.equals(node)) {
return new WebIpAndPortInfo(ALL, ALL);
}
String[] ipPort = node.split(COLON);
if (ipPort.length != 2) {
log.error("The IP address format is error : {}", node);
return null;
}
return new WebIpAndPortInfo(ipPort[0], ipPort[1]);
}
/**
* Check.
*
* @param appIpSegment application ip segment
* @param port application port
*/
public boolean check(String[] appIpSegment, String port) {
return checkPort(port) && checkIp(appIpSegment);
}
/**
* Check ip.
*
* @param appIpSegment application ip segment
*/
protected boolean checkIp(String[] appIpSegment) {
if (ALL.equals(this.ip)) {
return true;
}
boolean flag = true;
for (int i = 0; i < ipSegment.length && flag; i++) {
String propIp = ipSegment[i];
String appIp = appIpSegment[i];
flag = contrastSegment(appIp, propIp);
}
return flag;
}
/**
* Check port.
*
* @param port application port
*/
protected boolean checkPort(String port) {
return contrastSegment(port, this.port);
}
/**
* Check whether the strings are the same.
*
* @param appIp appIp
* @param propIp propIp
*/
protected boolean contrastSegment(String appIp, String propIp) {
return ALL.equals(propIp) || appIp.equals(propIp);
}
}

@ -23,9 +23,17 @@ public class FileUtilTest {
@Test
public void assertReadUtf8String() {
String testText = "abcd简体繁体\uD83D\uDE04\uD83D\uDD25& *\n" +
"second line\n" +
"empty line next\n";
String testFilePath = "test/test_utf8.txt";
String contentByFileUtil = FileUtil.readUtf8String(testFilePath);
Assert.notEmpty(contentByFileUtil);
}
@Test
public void assertReadUtf8String2() {
String linebreaks = System.getProperty("line.separator");
String testText = "abcd简体繁体\uD83D\uDE04\uD83D\uDD25& *" + linebreaks +
"second line" + linebreaks +
"empty line next" + linebreaks;
String testFilePath = "test/test_utf8.txt";
String contentByFileUtil = FileUtil.readUtf8String(testFilePath);
Assert.isTrue(testText.equals(contentByFileUtil));

@ -17,5 +17,55 @@
package cn.hippo4j.common.toolkit;
import cn.hippo4j.common.model.ThreadPoolParameterInfo;
import org.junit.Test;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
public class Md5UtilTest {
@Test
public void assertMd5Hex() throws NoSuchAlgorithmException {
String md5 = "3cdefff74dcf7a5d60893865b84b62c8";
String message = "message-consume";
Assert.isTrue(md5.equals(Md5Util.md5Hex(message.getBytes())));
}
@Test
public void assertMd5Hex2() {
String md5 = "503840dc3af3cdb39749cd099e4dfeff";
String message = "dynamic-threadpool-example";
Assert.isTrue(md5.equals(Md5Util.md5Hex(message, "UTF-8")));
}
@Test
public void assetEncodeHexString() {
String encodeHexString = "00010f107f80203040506070";
byte[] bytes = {0, 1, 15, 16, 127, -128, 32, 48, 64, 80, 96, 112};
Assert.isTrue(encodeHexString.equals(Md5Util.encodeHexString(bytes)));
}
@Test
public void assetGetTpContentMd5() {
String md5Result = "ef5ea7cb47377fb9fb85a7125e76715d";
ThreadPoolParameterInfo threadPoolParameterInfo = ThreadPoolParameterInfo.builder().tenantId("prescription")
.itemId("dynamic-threadpool-example").tpId("message-consume").content("描述信息").corePoolSize(1)
.maximumPoolSize(2).queueType(1).capacity(4).keepAliveTime(513).executeTimeOut(null).rejectedType(4)
.isAlarm(1).capacityAlarm(80).livenessAlarm(80).allowCoreThreadTimeOut(1).build();
Assert.isTrue(md5Result.equals(Md5Util.getTpContentMd5(threadPoolParameterInfo)));
}
@Test
public void assetCompareMd5ResultString() throws IOException {
Assert.isTrue("".equals(Md5Util.compareMd5ResultString(null)));
String result = "prescription%02dynamic-threadpool-example%02message-consume%01" +
"prescription%02dynamic-threadpool-example%02message-produce%01";
List<String> changedGroupKeys = new ArrayList<>(2);
changedGroupKeys.add("prescription+dynamic-threadpool-example+message-consume+12");
changedGroupKeys.add("prescription+dynamic-threadpool-example+message-produce+11");
Assert.isTrue(result.equals(Md5Util.compareMd5ResultString(changedGroupKeys)));
}
}

@ -17,6 +17,97 @@
package cn.hippo4j.common.toolkit;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.junit.Test;
import java.lang.reflect.Field;
import java.util.Objects;
public class ReflectUtilTest {
@Test
public void getFieldValueTest() {
TestSubClass testSubClass = new TestSubClass();
Object privateField = ReflectUtil.getFieldValue(testSubClass, "privateField");
Assert.isTrue(Objects.equals("privateField", privateField));
Object field = ReflectUtil.getFieldValue(testSubClass, "field");
Assert.isTrue(Objects.equals("field", field));
}
@Test
public void getFieldValueByFiledTest(){
TestSubClass testSubClass = new TestSubClass();
Field privateField = ReflectUtil.getField(TestSubClass.class, "privateField");
Object privateFieldVal = ReflectUtil.getFieldValue(testSubClass, privateField);
Assert.isTrue(Objects.equals("privateField", privateFieldVal));
}
@Test
public void getFieldTest(){
Field privateField = ReflectUtil.getField(TestSubClass.class, "privateField");
Assert.notNull(privateField);
Field field = ReflectUtil.getField(TestSubClass.class, "field");
Assert.notNull(field);
}
@Test
public void getFieldsTest(){
Field[] fields = ReflectUtil.getFields(TestSubClass.class);
Assert.isTrue(Objects.equals(4, fields.length));
}
@Test
public void getFieldsDirectlyTest(){
Field[] fields = ReflectUtil.getFieldsDirectly(TestSubClass.class, false);
Assert.isTrue(Objects.equals(2, fields.length));
fields = ReflectUtil.getFieldsDirectly(TestSubClass.class, true);
Assert.isTrue(Objects.equals(4, fields.length));
}
@Test
public void getFieldNameTest(){
Field privateField = ReflectUtil.getField(TestSubClass.class, "privateField");
String fieldName = ReflectUtil.getFieldName(privateField);
Assert.notNull(fieldName);
Field subField = ReflectUtil.getField(TestSubClass.class, "subField");
String subfieldName = ReflectUtil.getFieldName(subField);
Assert.notNull(subfieldName);
}
@Test
public void setFieldValueTest(){
TestClass testClass = new TestClass();
ReflectUtil.setFieldValue(testClass, "field", "fieldVal");
Assert.isTrue(Objects.equals("fieldVal", testClass.getField()));
Field privateField = ReflectUtil.getField(TestSubClass.class, "privateField");
ReflectUtil.setFieldValue(testClass, privateField, "privateFieldVal");
Assert.isTrue(Objects.equals("privateFieldVal", testClass.getPrivateField()));
}
@Getter
static class TestClass {
private String privateField;
protected String field;
public TestClass() {
this.privateField = "privateField";
this.field = "field";
}
}
class TestSubClass extends TestClass {
private String subField;
}
}

@ -17,5 +17,26 @@
package cn.hippo4j.common.toolkit;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
public class ThreadUtilTest {
@Test
public void testNewThread() {
// Setup
final Runnable runnable = null;
// Run the test
final Thread result = ThreadUtil.newThread(runnable, "name", false);
// Verify the results
Assert.notNull(result);
}
@Test
public void testSleep() {
assertTrue(ThreadUtil.sleep(0L));
}
}

@ -17,5 +17,45 @@
package cn.hippo4j.common.toolkit;
import cn.hutool.core.util.ReflectUtil;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
public class UserContextTest {
private static final String USERNAME = "test";
private static final String USER_ROLE = "role1";
@Test
public void testSetUserInfo() {
UserContext.setUserInfo(USERNAME, USER_ROLE);
ThreadLocal<UserContext.User> userThreadLocal = (ThreadLocal<UserContext.User>) ReflectUtil.getFieldValue(UserContext.class, "USER_THREAD_LOCAL");
Assert.notNull(userThreadLocal.get());
}
@Test
public void testGetUserName() {
UserContext.setUserInfo(USERNAME, USER_ROLE);
String userName = UserContext.getUserName();
Assert.isTrue(USERNAME.equals(userName));
}
@Test
public void testGetUserRole() {
UserContext.setUserInfo(USERNAME, USER_ROLE);
String userRole = UserContext.getUserRole();
Assert.isTrue(USER_ROLE.equals(userRole));
}
@Test
public void testClear() {
UserContext.setUserInfo(USERNAME, USER_ROLE);
ThreadLocal<UserContext.User> userThreadLocal = (ThreadLocal<UserContext.User>) ReflectUtil.getFieldValue(UserContext.class, "USER_THREAD_LOCAL");
Assert.notNull(userThreadLocal.get());
UserContext.clear();
Assert.isNull(userThreadLocal.get());
}
}

@ -35,6 +35,12 @@
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>

@ -20,6 +20,8 @@ package cn.hippo4j.config.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -29,10 +31,13 @@ import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig {
@Value("${spring.profiles.active:mysql}")
private String profilesActive;
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.getDbType(profilesActive)));
return interceptor;
}
}

@ -17,6 +17,12 @@
package cn.hippo4j.console.service.impl;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import cn.hippo4j.common.enums.DelEnum;
import cn.hippo4j.common.model.InstanceInfo;
import cn.hippo4j.common.toolkit.GroupKey;
@ -24,9 +30,17 @@ import cn.hippo4j.config.mapper.ConfigInfoMapper;
import cn.hippo4j.config.mapper.HisRunDataMapper;
import cn.hippo4j.config.mapper.ItemInfoMapper;
import cn.hippo4j.config.mapper.TenantInfoMapper;
import cn.hippo4j.config.model.*;
import cn.hippo4j.config.model.CacheItem;
import cn.hippo4j.config.model.ConfigAllInfo;
import cn.hippo4j.config.model.ConfigInfoBase;
import cn.hippo4j.config.model.ItemInfo;
import cn.hippo4j.config.model.TenantInfo;
import cn.hippo4j.config.service.ConfigCacheService;
import cn.hippo4j.console.model.*;
import cn.hippo4j.console.model.ChartInfo;
import cn.hippo4j.console.model.LineChartInfo;
import cn.hippo4j.console.model.PieChartInfo;
import cn.hippo4j.console.model.RankingChart;
import cn.hippo4j.console.model.TenantChart;
import cn.hippo4j.console.service.DashboardService;
import cn.hippo4j.discovery.core.BaseInstanceRegistry;
import cn.hippo4j.discovery.core.Lease;
@ -38,13 +52,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.stereotype.Service;
import static cn.hippo4j.common.toolkit.ContentUtil.getGroupKey;
@ -67,9 +76,9 @@ public class DashboardServiceImpl implements DashboardService {
@Override
public ChartInfo getChartInfo() {
Integer tenantCount = tenantInfoMapper.selectCount(Wrappers.lambdaQuery(TenantInfo.class).eq(TenantInfo::getDelFlag, DelEnum.NORMAL));
Integer itemCount = itemInfoMapper.selectCount(Wrappers.lambdaQuery(ItemInfo.class).eq(ItemInfo::getDelFlag, DelEnum.NORMAL));
Integer threadPoolCount = configInfoMapper.selectCount(Wrappers.lambdaQuery(ConfigAllInfo.class).eq(ConfigAllInfo::getDelFlag, DelEnum.NORMAL));
Integer tenantCount = tenantInfoMapper.selectCount(Wrappers.lambdaQuery(TenantInfo.class).eq(TenantInfo::getDelFlag, DelEnum.NORMAL.getCode()));
Integer itemCount = itemInfoMapper.selectCount(Wrappers.lambdaQuery(ItemInfo.class).eq(ItemInfo::getDelFlag, DelEnum.NORMAL.getIntCode()));
Integer threadPoolCount = configInfoMapper.selectCount(Wrappers.lambdaQuery(ConfigAllInfo.class).eq(ConfigAllInfo::getDelFlag, DelEnum.NORMAL.getCode()));
ChartInfo chartInfo = new ChartInfo();
chartInfo.setTenantCount(tenantCount)
.setItemCount(itemCount)

@ -28,5 +28,4 @@ public class ConfigNacosExampleApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigNacosExampleApplication.class, args);
}
}

@ -0,0 +1,6 @@
### Default database
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:hippo4j_manager;DB_CLOSE_DELAY=-1;MODE=MySQL;
spring.datasource.username=sa
spring.datasource.password=sa
spring.datasource.schema=classpath:sql-script/h2/hippo4j_manager.sql

@ -0,0 +1,5 @@
### Data source customization section
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/hippo4j_manager?characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root

@ -4,6 +4,7 @@
### Server Startup Port
server.port=6691
spring.profiles.active=mysql
### Server Tomcat
server.tomcat.accesslog.enabled=true
@ -24,13 +25,7 @@ hippo4j.core.clean-history-data-enable=true
# hippo4j.core.monitor.report-type=netty
#*************** Config Module Related Configurations ***************#
### Data source customization section
spring.datasource.url=jdbc:mysql://localhost:3306/hippo4j_manager?characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
### Hikari Datasource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.hikari.pool-name=Hikari
spring.datasource.hikari.connectionTimeout=30000
spring.datasource.hikari.idleTimeout=30000

@ -0,0 +1,235 @@
/******************************************/
/* 数据库全名 = hippo4j_manager */
/* 表名称 = tenant */
/******************************************/
DROP TABLE IF EXISTS `tenant`, `tenant_info`;
CREATE TABLE `tenant` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tenant_id` varchar(128) DEFAULT NULL COMMENT '租户ID',
`tenant_name` varchar(128) DEFAULT NULL COMMENT '租户名称',
`tenant_desc` varchar(256) DEFAULT NULL COMMENT '租户介绍',
`owner` varchar(32) DEFAULT '-' COMMENT '负责人',
`gmt_create` datetime DEFAULT NULL COMMENT '创建时间',
`gmt_modified` datetime DEFAULT NULL COMMENT '修改时间',
`del_flag` tinyint(1) DEFAULT NULL COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `tenant_id` (`id`),
KEY `uk_tenantinfo_tenantid` (`tenant_id`,`del_flag`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='租户表';
/******************************************/
/* 数据库全名 = hippo4j_manager */
/* 表名称 = item */
/******************************************/
DROP TABLE IF EXISTS `item`, `item_info`;
CREATE TABLE `item` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tenant_id` varchar(128) DEFAULT NULL COMMENT '租户ID',
`item_id` varchar(128) DEFAULT NULL COMMENT '项目ID',
`item_name` varchar(128) DEFAULT NULL COMMENT '项目名称',
`item_desc` varchar(256) DEFAULT NULL COMMENT '项目介绍',
`owner` varchar(32) DEFAULT NULL COMMENT '负责人',
`gmt_create` datetime DEFAULT NULL COMMENT '创建时间',
`gmt_modified` datetime DEFAULT NULL COMMENT '修改时间',
`del_flag` tinyint(1) DEFAULT NULL COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `item_id` (`id`),
UNIQUE KEY `item_uk_iteminfo_tenantitem` (`tenant_id`,`item_id`,`del_flag`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='项目表';
/******************************************/
/* 数据库全名 = hippo4j_manager */
/* 表名称 = config */
/******************************************/
DROP TABLE IF EXISTS `config`, `config_info`;
CREATE TABLE `config` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tenant_id` varchar(128) DEFAULT NULL COMMENT '租户ID',
`item_id` varchar(256) DEFAULT NULL COMMENT '项目ID',
`tp_id` varchar(56) DEFAULT NULL COMMENT '线程池ID',
`tp_name` varchar(56) DEFAULT NULL COMMENT '线程池名称',
`core_size` int(11) DEFAULT NULL COMMENT '核心线程数',
`max_size` int(11) DEFAULT NULL COMMENT '最大线程数',
`queue_type` int(11) DEFAULT NULL COMMENT '队列类型...',
`capacity` int(11) DEFAULT NULL COMMENT '队列大小',
`rejected_type` int(11) DEFAULT NULL COMMENT '拒绝策略',
`keep_alive_time` int(11) DEFAULT NULL COMMENT '线程存活时间',
`allow_core_thread_time_out` tinyint(1) DEFAULT NULL COMMENT '允许核心线程超时',
`content` longtext COMMENT '线程池内容',
`md5` varchar(32) NOT NULL COMMENT 'MD5',
`is_alarm` tinyint(1) DEFAULT NULL COMMENT '是否报警',
`capacity_alarm` int(11) DEFAULT NULL COMMENT '容量报警',
`liveness_alarm` int(11) DEFAULT NULL COMMENT '活跃度报警',
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`del_flag` tinyint(1) DEFAULT NULL COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `config_id` (`id`),
UNIQUE KEY `config_uk_configinfo_datagrouptenant` (`tenant_id`,`item_id`,`tp_id`,`del_flag`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='线程池配置表';
/******************************************/
/* 数据库全名 = hippo4j_manager */
/* 表名称 = inst_config */
/******************************************/
DROP TABLE IF EXISTS `inst_config`;
CREATE TABLE `inst_config` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tenant_id` varchar(128) DEFAULT NULL COMMENT '租户ID',
`item_id` varchar(256) DEFAULT NULL COMMENT '项目ID',
`tp_id` varchar(56) DEFAULT NULL COMMENT '线程池ID',
`instance_id` varchar(256) DEFAULT NULL COMMENT '实例ID',
`content` longtext COMMENT '线程池内容',
`md5` varchar(32) NOT NULL COMMENT 'MD5',
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `inst_config_id` (`id`),
KEY `idx_config_instance` (`tenant_id`,`item_id`,`tp_id`,`instance_id`) USING BTREE,
KEY `idx_instance` (`instance_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='线程池配置实例表';
/******************************************/
/* 数据库全名 = hippo4j_manager */
/* 表名称 = his_run_data */
/******************************************/
DROP TABLE IF EXISTS `his_run_data`;
CREATE TABLE `his_run_data` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`tenant_id` varchar(128) DEFAULT NULL COMMENT '租户ID',
`item_id` varchar(256) DEFAULT NULL COMMENT '项目ID',
`tp_id` varchar(56) DEFAULT NULL COMMENT '线程池ID',
`instance_id` varchar(256) DEFAULT NULL COMMENT '实例ID',
`current_load` bigint(20) DEFAULT NULL COMMENT '当前负载',
`peak_load` bigint(20) DEFAULT NULL COMMENT '峰值负载',
`pool_size` bigint(20) DEFAULT NULL COMMENT '线程数',
`active_size` bigint(20) DEFAULT NULL COMMENT '活跃线程数',
`queue_capacity` bigint(20) DEFAULT NULL COMMENT '队列容量',
`queue_size` bigint(20) DEFAULT NULL COMMENT '队列元素',
`queue_remaining_capacity` bigint(20) DEFAULT NULL COMMENT '队列剩余容量',
`completed_task_count` bigint(20) DEFAULT NULL COMMENT '已完成任务计数',
`reject_count` bigint(20) DEFAULT NULL COMMENT '拒绝次数',
`timestamp` bigint(20) DEFAULT NULL COMMENT '时间戳',
`gmt_create` datetime DEFAULT NULL COMMENT '创建时间',
`gmt_modified` datetime DEFAULT NULL COMMENT '修改时间',
PRIMARY KEY (`id`),
KEY `idx_group_key` (`tenant_id`,`item_id`,`tp_id`,`instance_id`) USING BTREE,
KEY `idx_timestamp` (`timestamp`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='历史运行数据表';
/******************************************/
/* 数据库全名 = hippo4j_manager */
/* 表名称 = log_record_info */
/******************************************/
DROP TABLE IF EXISTS `log_record_info`;
CREATE TABLE `log_record_info` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`tenant` varchar(128) NOT NULL DEFAULT '' COMMENT '租户标识',
`biz_key` varchar(128) NOT NULL DEFAULT '' COMMENT '日志业务标识',
`biz_no` varchar(128) NOT NULL DEFAULT '' COMMENT '业务码标识',
`operator` varchar(64) NOT NULL DEFAULT '' COMMENT '操作人',
`action` varchar(128) NOT NULL DEFAULT '' COMMENT '动作',
`category` varchar(128) NOT NULL DEFAULT '' COMMENT '种类',
`detail` varchar(2048) NOT NULL DEFAULT '' COMMENT '修改的详细信息可以为json',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_biz_key` (`biz_key`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='操作日志表';
/******************************************/
/* 数据库全名 = hippo4j_manager */
/* 表名称 = user */
/******************************************/
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`user_name` varchar(64) NOT NULL COMMENT '用户名',
`password` varchar(512) NOT NULL COMMENT '用户密码',
`role` varchar(50) NOT NULL COMMENT '角色',
`gmt_create` datetime NOT NULL COMMENT '创建时间',
`gmt_modified` datetime NOT NULL COMMENT '修改时间',
`del_flag` tinyint(1) NOT NULL COMMENT '是否删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
/******************************************/
/* 数据库全名 = hippo4j_manager */
/* 表名称 = role */
/******************************************/
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`role` varchar(64) NOT NULL COMMENT '角色',
`user_name` varchar(64) NOT NULL COMMENT '用户名',
`gmt_create` datetime NOT NULL COMMENT '创建时间',
`gmt_modified` datetime NOT NULL COMMENT '修改时间',
`del_flag` tinyint(1) NOT NULL COMMENT '是否删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='角色表';
/******************************************/
/* 数据库全名 = hippo4j_manager */
/* 表名称 = permission */
/******************************************/
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`role` varchar(512) NOT NULL COMMENT '角色',
`resource` varchar(512) NOT NULL COMMENT '资源',
`action` varchar(8) NOT NULL COMMENT '读写权限',
`gmt_create` datetime NOT NULL COMMENT '创建时间',
`gmt_modified` datetime NOT NULL COMMENT '修改时间',
`del_flag` tinyint(1) NOT NULL COMMENT '是否删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='权限表';
/******************************************/
/* 数据库全名 = hippo4j_manager */
/* 表名称 = notify */
/******************************************/
DROP TABLE IF EXISTS `alarm`, `notify`;
CREATE TABLE `notify` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT '租户ID',
`item_id` varchar(128) NOT NULL COMMENT '项目ID',
`tp_id` varchar(128) NOT NULL COMMENT '线程池ID',
`platform` varchar(32) NOT NULL COMMENT '通知平台',
`type` varchar(32) NOT NULL COMMENT '通知类型',
`secret_key` varchar(256) NOT NULL COMMENT '密钥',
`interval` int(11) DEFAULT NULL COMMENT '报警间隔',
`receives` varchar(512) NOT NULL COMMENT '接收者',
`enable` tinyint(1) DEFAULT NULL COMMENT '是否启用',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`del_flag` tinyint(1) NOT NULL COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `notify_uk_notify_biz_key` (`tenant_id`,`item_id`,`tp_id`,`platform`,`type`,`del_flag`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='通知表';
/* 租户 */
INSERT INTO `tenant` (`id`, `tenant_id`, `tenant_name`, `tenant_desc`, `owner`, `gmt_create`, `gmt_modified`, `del_flag`) VALUES ('1', 'prescription', '处方组', '负责维护处方服务, 包括不限于电子处方等业务', '谢良辰', '2021-10-24 13:42:11', '2021-10-24 13:42:11', '0');
/* 项目 */
INSERT INTO `item` (`id`, `tenant_id`, `item_id`, `item_name`, `item_desc`, `owner`, `gmt_create`, `gmt_modified`, `del_flag`) VALUES ('1', 'prescription', 'dynamic-threadpool-example', '动态线程池示例项目', '动态线程池示例项目,对应 Hippo 项目的 example 模块', '马称', '2021-10-24 16:11:00', '2021-10-24 16:11:00', '0');
/* 线程池 */
INSERT INTO `config` (`id`, `tenant_id`, `item_id`, `tp_id`, `tp_name`, `core_size`, `max_size`, `queue_type`, `capacity`, `rejected_type`, `keep_alive_time`, `allow_core_thread_time_out`, `content`, `md5`, `is_alarm`, `capacity_alarm`, `liveness_alarm`, `gmt_create`, `gmt_modified`, `del_flag`) VALUES ('1', 'prescription', 'dynamic-threadpool-example', 'message-consume', '示例消费者线程池', '5', '10', '9', '1024', '2', '9999', '0', '{\"tenantId\":\"prescription\",\"itemId\":\"dynamic-threadpool-example\",\"tpId\":\"message-consume\",\"coreSize\":5,\"maxSize\":10,\"queueType\":9,\"capacity\":1024,\"keepAliveTime\":9999,\"rejectedType\":2,\"isAlarm\":0,\"capacityAlarm\":80,\"livenessAlarm\":80,\"allowCoreThreadTimeOut\":0}', 'f80ea89044889fb6cec20e1a517f2ec3', '0', '80', '80', '2021-10-24 10:24:00', '2021-12-22 08:58:55', '0'),
('2', 'prescription', 'dynamic-threadpool-example', 'message-produce', '示例生产者线程池', '5', '15', '9', '1024', '1', '9999', '0', '{\"tenantId\":\"prescription\",\"itemId\":\"dynamic-threadpool-example\",\"tpId\":\"message-produce\",\"coreSize\":5,\"maxSize\":15,\"queueType\":9,\"capacity\":1024,\"keepAliveTime\":9999,\"rejectedType\":1,\"isAlarm\":0,\"capacityAlarm\":30,\"livenessAlarm\":30,\"allowCoreThreadTimeOut\":0}', '525e1429468bcfe98df7e70a75710051', '0', '30', '30', '2021-10-24 10:24:00', '2021-12-22 08:59:02', '0');
/* 用户 */
INSERT INTO `user` (`id`, `user_name`, `password`, `role`, `gmt_create`, `gmt_modified`, `del_flag`) VALUES ('1', 'admin', '$2a$10$2KCqRbra0Yn2TwvkZxtfLuWuUP5KyCWsljO/ci5pLD27pqR3TV1vy', 'ROLE_ADMIN', '2021-11-04 21:35:17', '2021-11-15 23:04:59', '0');
/* 通知表 */
INSERT INTO `notify` (`id`, `tenant_id`, `item_id`, `tp_id`, `platform`, `type`, `secret_key`, `interval`, `receives`, `enable`, `gmt_create`, `gmt_modified`, `del_flag`) VALUES ('1', 'prescription', 'dynamic-threadpool-example', 'message-produce', 'DING', 'CONFIG', '4a582a588a161d6e3a1bd1de7eea9ee9f562cdfcbe56b6e72029e7fd512b2eae', NULL, '15601166691', '0', '2021-11-18 22:49:50', '2021-11-18 22:49:50', '0'),
('2', 'prescription', 'dynamic-threadpool-example', 'message-produce', 'DING', 'ALARM', '4a582a588a161d6e3a1bd1de7eea9ee9f562cdfcbe56b6e72029e7fd512b2eae', '30', '15601166691', '0', '2021-11-18 22:50:06', '2021-11-18 22:50:06', '0');
/* 1.1.0 Upgrade Start */
ALTER TABLE `config` DROP INDEX `config_uk_configinfo_datagrouptenant`;
ALTER TABLE `item` DROP INDEX `item_uk_iteminfo_tenantitem`;
ALTER TABLE `tenant` DROP INDEX `uk_tenantinfo_tenantid`;
/* 1.1.0 Upgrade End */
/* 1.4.0 Upgrade Start */
ALTER TABLE config Modify COLUMN keep_alive_time int(11) COMMENT '线程存活时间(秒)';
ALTER TABLE config Add execute_time_out int(11) COMMENT '执行超时时间(毫秒)' AFTER keep_alive_time;
/* 1.4.0 Upgrade Start */

@ -64,7 +64,7 @@ import org.springframework.core.annotation.Order;
ConfigHandlerConfiguration.EmbeddedApollo.class, ConfigHandlerConfiguration.EmbeddedZookeeper.class,
ConfigHandlerConfiguration.EmbeddedEtcd.class
})
public class DynamicThreadPoolCoreAutoConfiguration {
public class DynamicThreadPoolAutoConfiguration {
private final BootstrapConfigProperties bootstrapConfigProperties;

@ -17,14 +17,14 @@
package cn.hippo4j.config.springboot.starter.refresher.event;
import cn.hippo4j.adapter.web.WebThreadPoolHandlerChoose;
import cn.hippo4j.adapter.web.WebThreadPoolService;
import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hippo4j.common.model.WebIpAndPortInfo;
import cn.hippo4j.common.toolkit.Assert;
import cn.hippo4j.common.toolkit.StringUtil;
import cn.hippo4j.core.toolkit.inet.InetUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.event.EventListener;
import java.util.Arrays;
import java.util.Objects;
@ -37,32 +37,33 @@ public abstract class AbstractRefreshListener<M> implements RefreshListener<Hipp
protected static final String ALL = "*";
protected static final String SPOT = "\\.";
protected static final String SEPARATOR = ",";
protected static final String COLON = ":";
/**
* application ip
*/
protected final String[] ipSegment;
/**
* application post
* Application ip and application post
*/
protected String port;
protected static volatile WebIpAndPortInfo webIpAndPort;
protected void initIpAndPort() {
if (webIpAndPort == null) {
synchronized (AbstractRefreshListener.class) {
if (webIpAndPort == null) {
webIpAndPort = getWebIpAndPortInfo();
}
}
}
}
AbstractRefreshListener() {
private WebIpAndPortInfo getWebIpAndPortInfo() {
InetUtils inetUtils = ApplicationContextHolder.getBean(InetUtils.class);
InetUtils.HostInfo loopBackHostInfo = inetUtils.findFirstNonLoopBackHostInfo();
Assert.notNull(loopBackHostInfo, "Unable to get the application IP address");
ipSegment = loopBackHostInfo.getIpAddress().split(SPOT);
}
@EventListener(WebServerInitializedEvent.class)
public void webServerInitializedListener(WebServerInitializedEvent event) {
port = String.valueOf(event.getWebServer().getPort());
String ip = loopBackHostInfo.getIpAddress();
WebThreadPoolHandlerChoose webThreadPoolHandlerChoose = ApplicationContextHolder.getBean(WebThreadPoolHandlerChoose.class);
WebThreadPoolService webThreadPoolService = webThreadPoolHandlerChoose.choose();
// When get the port at startup, can get the message: "port xxx was already in use" or use two ports
String port = String.valueOf(webThreadPoolService.getWebServer().getPort());
return new WebIpAndPortInfo(ip, port);
}
/**
@ -81,6 +82,9 @@ public abstract class AbstractRefreshListener<M> implements RefreshListener<Hipp
*/
@Override
public boolean match(M properties) {
if (webIpAndPort == null) {
initIpAndPort();
}
String nodes = getNodes(properties);
if (StringUtil.isEmpty(nodes) || ALL.equals(nodes)) {
return true;
@ -88,13 +92,13 @@ public abstract class AbstractRefreshListener<M> implements RefreshListener<Hipp
String[] splitNodes = nodes.split(SEPARATOR);
return Arrays.stream(splitNodes)
.distinct()
.map(IpAndPort::build)
.map(WebIpAndPortInfo::build)
.filter(Objects::nonNull)
.anyMatch(i -> i.check(ipSegment, port));
.anyMatch(each -> each.check(webIpAndPort.getIpSegment(), webIpAndPort.getPort()));
}
/**
* get nodes in new properties
* Get nodes in new properties.
*
* @param properties new properties
* @return nodes in properties
@ -102,80 +106,4 @@ public abstract class AbstractRefreshListener<M> implements RefreshListener<Hipp
protected String getNodes(M properties) {
return ALL;
}
/**
* ip + port
*/
@Data
protected static class IpAndPort {
private String ip;
private String port;
private String[] propIpSegment;
private IpAndPort(String ip, String port) {
this.ip = ip;
this.port = port;
this.propIpSegment = ip.split(SPOT);
}
public static IpAndPort build(String node) {
if (ALL.equals(node)) {
return new IpAndPort(ALL, ALL);
}
String[] ipPort = node.split(COLON);
if (ipPort.length != 2) {
log.error("The IP address format is error : {}", node);
return null;
}
return new IpAndPort(ipPort[0], ipPort[1]);
}
/**
* check
*
* @param appIpSegment application ip segment
* @param port application port
*/
public boolean check(String[] appIpSegment, String port) {
return checkPort(port) && checkIp(appIpSegment);
}
/**
* check ip
*
* @param appIpSegment application ip segment
*/
protected boolean checkIp(String[] appIpSegment) {
if (ALL.equals(this.ip)) {
return true;
}
boolean flag = true;
for (int i = 0; i < propIpSegment.length && flag; i++) {
String propIp = propIpSegment[i];
String appIp = appIpSegment[i];
flag = contrastSegment(appIp, propIp);
}
return flag;
}
/**
* check port
*
* @param port application port
*/
protected boolean checkPort(String port) {
return contrastSegment(port, this.port);
}
/**
* Check whether the strings are the same
*
* @param appIp appIp
* @param propIp propIp
*/
protected boolean contrastSegment(String appIp, String propIp) {
return ALL.equals(propIp) || appIp.equals(propIp);
}
}
}

@ -60,7 +60,7 @@ public class AdapterExecutorsRefreshListener extends AbstractRefreshListener<Ada
continue;
}
if (!Objects.equals(adapterExecutorProperties.getCorePoolSize(), each.getCorePoolSize())
|| !Objects.equals(adapterExecutorProperties.getMaximumPoolSize(), each.getMaximumPoolSize())) {
|| !Objects.equals(adapterExecutorProperties.getMaximumPoolSize(), each.getMaximumPoolSize())) {
threadPoolAdapterMap.forEach((key, val) -> {
if (Objects.equals(val.mark(), each.getMark())) {
val.updateThreadPool(BeanUtil.toBean(each, ThreadPoolAdapterParameter.class));

@ -1 +1 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.hippo4j.config.springboot.starter.config.DynamicThreadPoolCoreAutoConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.hippo4j.config.springboot.starter.config.DynamicThreadPoolAutoConfiguration

@ -153,20 +153,19 @@ public final class DynamicThreadPoolPostProcessor implements BeanPostProcessor {
.allowCoreThreadTimeOut(EnableEnum.getBool(threadPoolParameterInfo.getAllowCoreThreadTimeOut()))
.build();
// Set dynamic thread pool enhancement parameters.
ThreadPoolExecutor customDynamicThreadPool;
if ((customDynamicThreadPool = executor) instanceof AbstractDynamicExecutorSupport) {
if (executor instanceof AbstractDynamicExecutorSupport) {
ThreadPoolNotifyAlarm threadPoolNotifyAlarm = new ThreadPoolNotifyAlarm(
BooleanUtil.toBoolean(threadPoolParameterInfo.getIsAlarm().toString()),
threadPoolParameterInfo.getCapacityAlarm(),
threadPoolParameterInfo.getLivenessAlarm());
GlobalNotifyAlarmManage.put(threadPoolId, threadPoolNotifyAlarm);
TaskDecorator taskDecorator = ((DynamicThreadPoolExecutor) customDynamicThreadPool).getTaskDecorator();
TaskDecorator taskDecorator = ((DynamicThreadPoolExecutor) executor).getTaskDecorator();
((DynamicThreadPoolExecutor) newDynamicThreadPoolExecutor).setTaskDecorator(taskDecorator);
long awaitTerminationMillis = ((DynamicThreadPoolExecutor) customDynamicThreadPool).awaitTerminationMillis;
boolean waitForTasksToCompleteOnShutdown = ((DynamicThreadPoolExecutor) customDynamicThreadPool).waitForTasksToCompleteOnShutdown;
long awaitTerminationMillis = ((DynamicThreadPoolExecutor) executor).awaitTerminationMillis;
boolean waitForTasksToCompleteOnShutdown = ((DynamicThreadPoolExecutor) executor).waitForTasksToCompleteOnShutdown;
((DynamicThreadPoolExecutor) newDynamicThreadPoolExecutor).setSupportParam(awaitTerminationMillis, waitForTasksToCompleteOnShutdown);
long executeTimeOut = Optional.ofNullable(threadPoolParameterInfo.getExecuteTimeOut())
.orElse(((DynamicThreadPoolExecutor) customDynamicThreadPool).getExecuteTimeOut());
.orElse(((DynamicThreadPoolExecutor) executor).getExecuteTimeOut());
((DynamicThreadPoolExecutor) newDynamicThreadPoolExecutor).setExecuteTimeOut(executeTimeOut);
}
dynamicThreadPoolWrapper.setExecutor(newDynamicThreadPoolExecutor);

Loading…
Cancel
Save