mirror of
				https://github.com/continew-org/continew-starter.git
				synced 2025-10-26 19:00:53 +08:00 
			
		
		
		
	feat: 新增线程池自动配置
This commit is contained in:
		| @@ -43,6 +43,9 @@ import top.charles7c.continew.starter.core.constant.StringConsts; | |||||||
| @EnableConfigurationProperties(CorsProperties.class) | @EnableConfigurationProperties(CorsProperties.class) | ||||||
| public class CorsAutoConfiguration { | public class CorsAutoConfiguration { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 跨域过滤器 | ||||||
|  |      */ | ||||||
|     @Bean |     @Bean | ||||||
|     @ConditionalOnMissingBean |     @ConditionalOnMissingBean | ||||||
|     public CorsFilter corsFilter(CorsProperties properties) { |     public CorsFilter corsFilter(CorsProperties properties) { | ||||||
| @@ -67,7 +70,7 @@ public class CorsAutoConfiguration { | |||||||
|         UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); |         UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); | ||||||
|         source.registerCorsConfiguration("/**", config); |         source.registerCorsConfiguration("/**", config); | ||||||
|         CorsFilter corsFilter = new CorsFilter(source); |         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; |         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.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