mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-09 08:57:17 +08:00
feat: 新增线程池自动配置
This commit is contained in:
@@ -43,6 +43,9 @@ import top.charles7c.continew.starter.core.constant.StringConsts;
|
||||
@EnableConfigurationProperties(CorsProperties.class)
|
||||
public class CorsAutoConfiguration {
|
||||
|
||||
/**
|
||||
* 跨域过滤器
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public CorsFilter corsFilter(CorsProperties properties) {
|
||||
@@ -67,7 +70,7 @@ public class CorsAutoConfiguration {
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", config);
|
||||
CorsFilter corsFilter = new CorsFilter(source);
|
||||
log.info("[ContiNew Starter] - Auto Configuration 'Cors' completed initialization.");
|
||||
log.info("[ContiNew Starter] - Auto Configuration 'CorsFilter' completed initialization.");
|
||||
return corsFilter;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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 top.charles7c.continew.starter.core.autoconfigure.threadpool;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.scheduling.annotation.AsyncConfigurer;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import top.charles7c.continew.starter.core.exception.BaseException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
/**
|
||||
* 异步任务自动配置
|
||||
*
|
||||
* @author Charles7c
|
||||
* @author Lion Li(RuoYi-Vue-Plus)
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Lazy
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true")
|
||||
@EnableAsync(proxyTargetClass = true)
|
||||
public class AsyncAutoConfiguration implements AsyncConfigurer {
|
||||
|
||||
private final ScheduledExecutorService scheduledExecutorService;
|
||||
|
||||
public AsyncAutoConfiguration(ScheduledExecutorService scheduledExecutorService) {
|
||||
this.scheduledExecutorService = scheduledExecutorService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步任务 @Async 执行时,使用 Java 内置线程池
|
||||
*/
|
||||
@Override
|
||||
public Executor getAsyncExecutor() {
|
||||
log.info("[ContiNew Starter] - Auto Configuration 'AsyncConfigurer' completed initialization.");
|
||||
return scheduledExecutorService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步任务执行时的异常处理
|
||||
*/
|
||||
@Override
|
||||
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
|
||||
return (throwable, method, objects) -> {
|
||||
throwable.printStackTrace();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Exception message: ").append(throwable.getMessage()).append(", Method name: ")
|
||||
.append(method.getName());
|
||||
if (ArrayUtil.isNotEmpty(objects)) {
|
||||
sb.append(", Parameter value: ").append(Arrays.toString(objects));
|
||||
}
|
||||
throw new BaseException(sb.toString());
|
||||
};
|
||||
}
|
||||
}
|
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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 top.charles7c.continew.starter.core.autoconfigure.threadpool;
|
||||
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import top.charles7c.continew.starter.core.util.ExceptionUtils;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* 线程池自动配置
|
||||
*
|
||||
* @author Charles7c
|
||||
* @author Lion Li(RuoYi-Vue-Plus)
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Lazy
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true")
|
||||
@EnableConfigurationProperties(ThreadPoolProperties.class)
|
||||
public class ThreadPoolAutoConfiguration {
|
||||
|
||||
/** 核心(最小)线程数 = CPU 核心数 + 1 */
|
||||
private final int corePoolSize = Runtime.getRuntime().availableProcessors() + 1;
|
||||
|
||||
/**
|
||||
* Spring 内置线程池:ThreadPoolTaskExecutor
|
||||
*/
|
||||
@Bean
|
||||
public ThreadPoolTaskExecutor threadPoolTaskExecutor(ThreadPoolProperties properties) {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
// 核心(最小)线程数
|
||||
executor.setCorePoolSize(ObjectUtil.defaultIfNull(properties.getCorePoolSize(), corePoolSize));
|
||||
// 最大线程数
|
||||
executor.setMaxPoolSize(ObjectUtil.defaultIfNull(properties.getMaxPoolSize(), corePoolSize * 2));
|
||||
// 队列容量
|
||||
executor.setQueueCapacity(properties.getQueueCapacity());
|
||||
// 活跃时间
|
||||
executor.setKeepAliveSeconds(properties.getKeepAliveSeconds());
|
||||
// 配置当池内线程数已达到上限的时候,该如何处理新任务:不在新线程中执行任务,而是由调用者所在的线程来执行
|
||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
log.info("[ContiNew Starter] - Auto Configuration 'ThreadPoolTaskExecutor' completed initialization.");
|
||||
return executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Java 内置线程池:ScheduledExecutorService(适用于执行周期性或定时任务)
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ScheduledExecutorService scheduledExecutorService(ThreadPoolProperties properties) {
|
||||
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(ObjectUtil.defaultIfNull(properties.getCorePoolSize(), corePoolSize),
|
||||
ThreadUtil.newNamedThreadFactory("schedule-pool-%d", true),
|
||||
new ThreadPoolExecutor.CallerRunsPolicy()) {
|
||||
@Override
|
||||
protected void afterExecute(Runnable runnable, Throwable throwable) {
|
||||
super.afterExecute(runnable, throwable);
|
||||
ExceptionUtils.printException(runnable, throwable);
|
||||
}
|
||||
};
|
||||
log.info("[ContiNew Starter] - Auto Configuration 'ScheduledExecutorService' completed initialization.");
|
||||
return executor;
|
||||
}
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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 top.charles7c.continew.starter.core.autoconfigure.threadpool;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* 线程池配置属性
|
||||
*
|
||||
* @author Charles7c
|
||||
* @author Lion Li(RuoYi-Vue-Plus)
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "thread-pool")
|
||||
public class ThreadPoolProperties {
|
||||
|
||||
/**
|
||||
* 是否启用
|
||||
*/
|
||||
private boolean enabled = false;
|
||||
|
||||
/**
|
||||
* 核心/最小线程数(默认:CPU 核心数 + 1)
|
||||
*/
|
||||
private Integer corePoolSize;
|
||||
|
||||
/**
|
||||
* 最大线程数(默认:(CPU 核心数 + 1) * 2)
|
||||
*/
|
||||
private Integer maxPoolSize;
|
||||
|
||||
/**
|
||||
* 队列容量
|
||||
*/
|
||||
private int queueCapacity = 128;
|
||||
|
||||
/**
|
||||
* 活跃时间(单位:秒)
|
||||
*/
|
||||
private int keepAliveSeconds = 300;
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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 top.charles7c.continew.starter.core.exception;
|
||||
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 自定义异常基类
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
public class BaseException extends RuntimeException {
|
||||
|
||||
public BaseException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* 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 top.charles7c.continew.starter.core.util;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import top.charles7c.continew.starter.core.constant.StringConsts;
|
||||
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* 异常工具类
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Slf4j
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class ExceptionUtils {
|
||||
|
||||
/**
|
||||
* 打印线程异常信息
|
||||
*
|
||||
* @param runnable
|
||||
* 线程执行内容
|
||||
* @param throwable
|
||||
* 异常
|
||||
*/
|
||||
public static void printException(Runnable runnable, Throwable throwable) {
|
||||
if (null == throwable && runnable instanceof Future<?> future) {
|
||||
try {
|
||||
if (future.isDone()) {
|
||||
future.get();
|
||||
}
|
||||
} catch (CancellationException e) {
|
||||
throwable = e;
|
||||
} catch (ExecutionException e) {
|
||||
throwable = e.getCause();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
if (null != throwable) {
|
||||
log.error(throwable.getMessage(), throwable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果有异常,返回 null
|
||||
*
|
||||
* @param exSupplier
|
||||
* 可能会出现异常的方法执行
|
||||
* @param <T>
|
||||
* /
|
||||
* @return /
|
||||
*/
|
||||
public static <T> T exToNull(ExSupplier<T> exSupplier) {
|
||||
return exToDefault(exSupplier, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果有异常,执行异常处理
|
||||
*
|
||||
* @param supplier
|
||||
* 可能会出现异常的方法执行
|
||||
* @param exConsumer
|
||||
* 异常处理
|
||||
* @param <T>
|
||||
* /
|
||||
* @return /
|
||||
*/
|
||||
public static <T> T exToNull(ExSupplier<T> supplier, Consumer<Exception> exConsumer) {
|
||||
return exToDefault(supplier, null, exConsumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果有异常,返回空字符串
|
||||
*
|
||||
* @param exSupplier
|
||||
* 可能会出现异常的方法执行
|
||||
* @return /
|
||||
*/
|
||||
public static String exToBlank(ExSupplier<String> exSupplier) {
|
||||
return exToDefault(exSupplier, StringConsts.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果有异常,返回默认值
|
||||
*
|
||||
* @param exSupplier
|
||||
* 可能会出现异常的方法执行
|
||||
* @param defaultValue
|
||||
* 默认值
|
||||
* @param <T>
|
||||
* /
|
||||
* @return /
|
||||
*/
|
||||
public static <T> T exToDefault(ExSupplier<T> exSupplier, T defaultValue) {
|
||||
return exToDefault(exSupplier, defaultValue, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果有异常,执行异常处理,返回默认值
|
||||
*
|
||||
* @param exSupplier
|
||||
* 可能会出现异常的方法执行
|
||||
* @param defaultValue
|
||||
* 默认值
|
||||
* @param exConsumer
|
||||
* 异常处理
|
||||
* @param <T>
|
||||
* /
|
||||
* @return /
|
||||
*/
|
||||
public static <T> T exToDefault(ExSupplier<T> exSupplier, T defaultValue, Consumer<Exception> exConsumer) {
|
||||
try {
|
||||
return exSupplier.get();
|
||||
} catch (Exception e) {
|
||||
if (null != exConsumer) {
|
||||
exConsumer.accept(e);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 异常提供者
|
||||
*
|
||||
* @param <T>
|
||||
* /
|
||||
*/
|
||||
public interface ExSupplier<T> {
|
||||
/**
|
||||
* 获取返回值
|
||||
*
|
||||
* @return /
|
||||
* @throws Exception
|
||||
* /
|
||||
*/
|
||||
T get() throws Exception;
|
||||
}
|
||||
}
|
@@ -1 +1,3 @@
|
||||
top.charles7c.continew.starter.core.autoconfigure.cors.CorsAutoConfiguration
|
||||
top.charles7c.continew.starter.core.autoconfigure.threadpool.ThreadPoolAutoConfiguration
|
||||
top.charles7c.continew.starter.core.autoconfigure.threadpool.AsyncAutoConfiguration
|
Reference in New Issue
Block a user