🔨 线程池配置化.

This commit is contained in:
lijiahangmax
2025-10-07 00:28:49 +08:00
parent cb20d56a7b
commit 25082b9ea1
31 changed files with 720 additions and 287 deletions

View File

@@ -48,8 +48,7 @@ public class PushMessageEventListener implements ApplicationListener<PushMessage
this.pushServiceMap = pushServiceMap;
}
// FIXME
@Async("asyncExecutor")
@Async("pushExecutor")
@Override
public void onApplicationEvent(PushMessageEvent event) {
try {
@@ -68,4 +67,4 @@ public class PushMessageEventListener implements ApplicationListener<PushMessage
return (IPushService<T>) pushServiceMap.get(message.getChannel());
}
}
}

View File

@@ -0,0 +1,27 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-framework</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>orion-visor-spring-boot-starter-executor</artifactId>
<name>${project.artifactId}</name>
<packaging>jar</packaging>
<description>项目线程池配置包</description>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<!-- common -->
<dependency>
<groupId>org.dromara.visor</groupId>
<artifactId>orion-visor-common</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed 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 org.dromara.visor.framework.executor.configuration;
import org.dromara.visor.common.constant.AutoConfigureOrderConst;
import org.dromara.visor.framework.executor.configuration.config.ExecutorsConfig;
import org.dromara.visor.framework.executor.core.context.ExecutorContext;
import org.dromara.visor.framework.executor.core.utils.ExecutorUtils;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.Map;
/**
* 项目线程池配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025/9/16 14:34
*/
@EnableAsync
@AutoConfiguration
@EnableConfigurationProperties({ExecutorsConfig.class})
@AutoConfigureOrder(AutoConfigureOrderConst.FRAMEWORK_EXECUTOR)
public class OrionExecutorAutoConfiguration {
/**
* 创建线程池上下文
*
* @param executorsConfig executorsConfig
* @param beanFactory beanFactory
* @return 线程池上下文
*/
@Bean
public ExecutorContext executorContext(ExecutorsConfig executorsConfig,
ConfigurableBeanFactory beanFactory) {
// 创建上下文
ExecutorContext context = new ExecutorContext(executorsConfig, beanFactory);
Map<String, ThreadPoolTaskExecutor> executorMap = context.init();
// 获取线程池列表
ExecutorUtils.setExecutors(executorMap);
return context;
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed 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 org.dromara.visor.framework.executor.configuration.config;
import cn.orionsec.kit.lang.define.thread.RejectPolicy;
import cn.orionsec.kit.lang.utils.Systems;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
/**
* 线程池配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025/9/16 10:51
*/
@Data
@Builder
@AllArgsConstructor
public class ExecutorConfig {
/**
* 是否启用
*/
private boolean enabled;
/**
* 是否使用 MDC
*/
private boolean mdc;
/**
* 核心线程数
*/
private int corePoolSize;
/**
* 最大线程数
*/
private int maxPoolSize;
/**
* 队列容量
*/
private int queueCapacity;
/**
* 空闲线程存活时间
*/
private int keepAliveSeconds;
/**
* 是否允许核心线程超时
*/
private boolean allowCoreTimeout;
/**
* 是否使用同步队列
*/
private boolean synchronousQueue;
/**
* 线程名称前缀
*/
private String threadNamePrefix;
/**
* 拒绝策略
*/
private RejectPolicy rejectPolicy;
public ExecutorConfig() {
this.enabled = true;
this.corePoolSize = Systems.PROCESS_NUM;
this.maxPoolSize = Systems.PROCESS_NUM;
this.queueCapacity = 100;
this.keepAliveSeconds = 300;
this.rejectPolicy = RejectPolicy.CALLER_RUNS;
}
}

View File

@@ -20,47 +20,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.framework.job.configuration.config;
package org.dromara.visor.framework.executor.configuration.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.Map;
/**
* 线程池配置
* 线程池配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/10 15:49
* @since 2025/9/16 16:21
*/
@Data
@ConfigurationProperties(prefix = "orion.async.executor")
public class AsyncExecutorConfig {
@ConfigurationProperties(prefix = "app")
public class ExecutorsConfig {
/**
* 核心线程数量
* 线程池配置
*/
private int corePoolSize;
/**
* 最大线程数量
*/
private int maxPoolSize;
/**
* 队列容量
*/
private int queueCapacity;
/**
* 活跃时间
*/
private int keepAliveSeconds;
public AsyncExecutorConfig() {
this.corePoolSize = 8;
this.maxPoolSize = 16;
this.queueCapacity = 200;
this.keepAliveSeconds = 300;
}
private Map<String, ExecutorConfig> executors;
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed 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 org.dromara.visor.framework.executor.core.context;
import cn.orionsec.kit.lang.define.thread.RejectPolicy;
import cn.orionsec.kit.lang.utils.Strings;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.common.thread.ThreadPoolMdcTaskExecutor;
import org.dromara.visor.framework.executor.configuration.config.ExecutorConfig;
import org.dromara.visor.framework.executor.configuration.config.ExecutorsConfig;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.HashMap;
import java.util.Map;
/**
* 执行器上下文
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025/9/16 16:28
*/
@Slf4j
public class ExecutorContext {
private final ExecutorsConfig executorsConfig;
private final ConfigurableBeanFactory beanFactory;
public ExecutorContext(ExecutorsConfig executorsConfig, ConfigurableBeanFactory beanFactory) {
this.executorsConfig = executorsConfig;
this.beanFactory = beanFactory;
}
/**
* 初始化
*
* @return executorMap
*/
public Map<String, ThreadPoolTaskExecutor> init() {
log.info("--------- Executors init start --------- ");
Map<String, ThreadPoolTaskExecutor> executorMap = new HashMap<>();
executorsConfig.getExecutors().forEach((beanName, config) -> {
String executorName = Strings.leftPad(beanName, 30);
// 是否启用
if (!config.isEnabled()) {
log.info("Executor [{}] is disabled.", executorName);
return;
}
// 创建线程池
ThreadPoolTaskExecutor executor = this.createTaskExecutor(config);
// 注册到容器中
beanFactory.registerSingleton(beanName, executor);
executorMap.put(beanName, executor);
log.info("Executor [{}] init success. {}", executorName, JSON.toJSONString(config));
});
log.info("--------- Executors init end --------- ");
return executorMap;
}
/**
* 创建线程池
*
* @param config config
*/
private ThreadPoolTaskExecutor createTaskExecutor(ExecutorConfig config) {
// 创建线程池
ThreadPoolTaskExecutor executor;
if (config.isMdc()) {
executor = new ThreadPoolMdcTaskExecutor();
} else {
executor = new ThreadPoolTaskExecutor();
}
// 同步队列
if (config.isSynchronousQueue()) {
config.setCorePoolSize(0);
config.setMaxPoolSize(Integer.MAX_VALUE);
config.setQueueCapacity(0);
config.setRejectPolicy(RejectPolicy.ABORT);
}
// 设置参数
executor.setCorePoolSize(config.getCorePoolSize());
executor.setMaxPoolSize(config.getMaxPoolSize());
executor.setQueueCapacity(config.getQueueCapacity());
executor.setThreadNamePrefix(config.getThreadNamePrefix());
executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
executor.setAllowCoreThreadTimeOut(config.isAllowCoreTimeout());
executor.setRejectedExecutionHandler(config.getRejectPolicy().getHandler());
// 设置等待所有任务执行结束再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
// 初始化
executor.initialize();
return executor;
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed 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 org.dromara.visor.framework.executor.core.utils;
import cn.orionsec.kit.lang.able.Executable;
import cn.orionsec.kit.lang.utils.Exceptions;
import cn.orionsec.kit.lang.utils.collect.Maps;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.Map;
/**
* 线程池工具类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025/9/16 16:34
*/
public class ExecutorUtils {
private static Map<String, ThreadPoolTaskExecutor> executorMap;
private ExecutorUtils() {
}
/**
* 获取线程池
*
* @param name name
* @return executor
*/
public static ThreadPoolTaskExecutor getExecutor(String name) {
return executorMap.get(name);
}
/**
* 执行
*
* @param name name
* @param runnable runnable
*/
public static void execute(String name, Runnable runnable) {
getExecutor(name).execute(runnable);
}
/**
* 执行
*
* @param name name
* @param executable executable
*/
public static void execute(String name, Executable executable) {
getExecutor(name).execute(executable::exec);
}
public static void setExecutors(Map<String, ThreadPoolTaskExecutor> executorMap) {
if (ExecutorUtils.executorMap != null) {
// unmodified
throw Exceptions.state();
}
ExecutorUtils.executorMap = Maps.unmodified(executorMap);
}
}

View File

@@ -0,0 +1,77 @@
{
"groups": [
{
"name": "orion.executors.*",
"type": "org.dromara.visor.framework.executor.configuration.config.ExecutorConfig",
"sourceType": "org.dromara.visor.framework.executor.configuration.config.ExecutorConfig",
"description": "线程池配置项."
}
],
"properties": [
{
"name": "orion.executors",
"type": "java.util.Map<java.lang.String,org.dromara.visor.framework.executor.configuration.config.ExecutorConfig>",
"description": "线程池配置.",
"defaultValue": "{}"
},
{
"name": "orion.executors.*.enabled",
"type": "java.lang.Boolean",
"description": "是否启用.",
"defaultValue": false
},
{
"name": "orion.executors.*.corePoolSize",
"type": "java.lang.Integer",
"description": "核心线程数.",
"defaultValue": "CPU_NUM"
},
{
"name": "orion.executors.*.maxPoolSize",
"type": "java.lang.Integer",
"description": "最大线程数.",
"defaultValue": "CPU_NUM"
},
{
"name": "orion.executors.*.queueCapacity",
"type": "java.lang.Integer",
"description": "任务队列容量.",
"defaultValue": 100
},
{
"name": "orion.executors.*.keepAliveSeconds",
"type": "java.lang.Integer",
"description": "空闲线程存活时间.",
"defaultValue": 60
},
{
"name": "orion.executors.*.allowCoreTimeout",
"type": "java.lang.Boolean",
"description": "是否允许核心线程超时回收.",
"defaultValue": false
},
{
"name": "orion.executors.*.synchronousQueue",
"type": "java.lang.Boolean",
"description": "是否启用同步队列模式.",
"defaultValue": false
},
{
"name": "orion.executors.*.mdc",
"type": "java.lang.Boolean",
"description": "是否启用 MDC 上下文传递.",
"defaultValue": false
},
{
"name": "orion.executors.*.threadNamePrefix",
"type": "java.lang.String",
"description": "线程名称前缀."
},
{
"name": "orion.executors.*.rejectPolicy",
"type": "cn.orionsec.kit.lang.define.thread.RejectPolicy",
"description": "拒绝策略.",
"defaultValue": "CALLER_RUNS"
}
]
}

View File

@@ -0,0 +1 @@
org.dromara.visor.framework.executor.configuration.OrionExecutorAutoConfiguration

View File

@@ -1,96 +0,0 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed 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 org.dromara.visor.framework.job.configuration;
import org.dromara.visor.common.constant.AutoConfigureOrderConst;
import org.dromara.visor.common.constant.Const;
import org.dromara.visor.common.thread.ThreadPoolMdcTaskExecutor;
import org.dromara.visor.framework.job.configuration.config.AsyncExecutorConfig;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import java.util.concurrent.ThreadPoolExecutor;
/**
* async 异步任务
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/20 10:34
*/
@EnableAsync
@AutoConfiguration
@AutoConfigureOrder(AutoConfigureOrderConst.FRAMEWORK_JOB_ASYNC)
@EnableConfigurationProperties(AsyncExecutorConfig.class)
public class OrionAsyncAutoConfiguration {
/**
* {@code @Async("asyncExecutor")}
*
* @return 支持 MDC 的异步线程池
*/
@Bean(name = "asyncExecutor")
public TaskExecutor asyncExecutor(AsyncExecutorConfig config) {
ThreadPoolMdcTaskExecutor executor = new ThreadPoolMdcTaskExecutor();
executor.setCorePoolSize(config.getCorePoolSize());
executor.setMaxPoolSize(config.getMaxPoolSize());
executor.setQueueCapacity(config.getQueueCapacity());
executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
executor.setAllowCoreThreadTimeOut(true);
executor.setThreadNamePrefix("async-task-");
// 设置等待所有任务执行结束再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
// 以确保应用最后能够被关闭
executor.setAwaitTerminationSeconds(60);
// 调用者调用拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
/**
* {@code @Async("metricsExecutor")}
*
* @return 指标线程池
*/
@Bean(name = "metricsExecutor")
public TaskExecutor metricsExecutor() {
ThreadPoolMdcTaskExecutor executor = new ThreadPoolMdcTaskExecutor();
executor.setCorePoolSize(4);
executor.setMaxPoolSize(8);
executor.setQueueCapacity(1000);
executor.setKeepAliveSeconds(Const.MS_S_60);
executor.setAllowCoreThreadTimeOut(true);
executor.setThreadNamePrefix("metrics-task-");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}

View File

@@ -25,6 +25,8 @@ package org.dromara.visor.framework.job.configuration;
import org.dromara.visor.common.constant.AutoConfigureOrderConst;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.task.TaskSchedulingProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
@@ -40,17 +42,18 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
@EnableScheduling
@AutoConfiguration
@AutoConfigureOrder(AutoConfigureOrderConst.FRAMEWORK_JOB)
@EnableConfigurationProperties(TaskSchedulingProperties.class)
public class OrionSchedulerAutoConfiguration {
/**
* @return 任务调度器
*/
@Bean
public TaskScheduler taskScheduler() {
public TaskScheduler taskScheduler(TaskSchedulingProperties properties) {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(4);
scheduler.setRemoveOnCancelPolicy(true);
scheduler.setThreadNamePrefix("scheduling-task-");
scheduler.setPoolSize(properties.getPool().getSize());
scheduler.setThreadNamePrefix(properties.getThreadNamePrefix());
return scheduler;
}

View File

@@ -1,35 +0,0 @@
{
"groups": [
{
"name": "orion.async.executor",
"type": "org.dromara.visor.framework.job.configuration.config.AsyncExecutorConfig",
"sourceType": "org.dromara.visor.framework.job.configuration.config.AsyncExecutorConfig"
}
],
"properties": [
{
"name": "orion.async.executor.core-pool-size",
"type": "java.lang.Integer",
"description": "核心线程数量.",
"defaultValue": "8"
},
{
"name": "orion.async.executor.max-pool-size",
"type": "java.lang.Integer",
"description": "最大线程数量.",
"defaultValue": "16"
},
{
"name": "orion.async.executor.queue-capacity",
"type": "java.lang.Integer",
"description": "队列容量.",
"defaultValue": "200"
},
{
"name": "orion.async.executor.keep-alive-seconds",
"type": "java.lang.Integer",
"description": "活跃时间.",
"defaultValue": "300"
}
]
}

View File

@@ -1,3 +1,2 @@
org.dromara.visor.framework.job.configuration.OrionSchedulerAutoConfiguration
org.dromara.visor.framework.job.configuration.OrionQuartzAutoConfiguration
org.dromara.visor.framework.job.configuration.OrionAsyncAutoConfiguration

View File

@@ -42,6 +42,7 @@ import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;
import org.springframework.http.MediaType;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
@@ -67,6 +68,7 @@ import java.util.List;
* @version 1.0.0
* @since 2023/6/16 16:26
*/
@DependsOn({"executorContext"})
@AutoConfiguration
@AutoConfigureOrder(AutoConfigureOrderConst.FRAMEWORK_WEB)
@EnableConfigurationProperties(ExposeApiConfig.class)

View File

@@ -24,6 +24,7 @@
<module>orion-visor-spring-boot-starter-cipher</module>
<module>orion-visor-spring-boot-starter-config</module>
<module>orion-visor-spring-boot-starter-job</module>
<module>orion-visor-spring-boot-starter-executor</module>
<module>orion-visor-spring-boot-starter-websocket</module>
<module>orion-visor-spring-boot-starter-redis</module>
<module>orion-visor-spring-boot-starter-desensitize</module>
@@ -37,4 +38,4 @@
<module>orion-visor-spring-boot-starter-biz-operator-log</module>
</modules>
</project>
</project>