From 916127e7415099012dd26415ad1a541d2d6c9c16 Mon Sep 17 00:00:00 2001 From: Charles7c Date: Mon, 20 Nov 2023 22:15:43 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E7=BA=BF=E7=A8=8B?= =?UTF-8?q?=E6=B1=A0=E8=87=AA=E5=8A=A8=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cors/CorsAutoConfiguration.java | 5 +- .../threadpool/AsyncAutoConfiguration.java | 78 +++++++++ .../ThreadPoolAutoConfiguration.java | 90 ++++++++++ .../threadpool/ThreadPoolProperties.java | 57 +++++++ .../starter/core/exception/BaseException.java | 33 ++++ .../starter/core/util/ExceptionUtils.java | 160 ++++++++++++++++++ ...ot.autoconfigure.AutoConfiguration.imports | 2 + 7 files changed, 424 insertions(+), 1 deletion(-) create mode 100644 continew-starter-core/src/main/java/top/charles7c/continew/starter/core/autoconfigure/threadpool/AsyncAutoConfiguration.java create mode 100644 continew-starter-core/src/main/java/top/charles7c/continew/starter/core/autoconfigure/threadpool/ThreadPoolAutoConfiguration.java create mode 100644 continew-starter-core/src/main/java/top/charles7c/continew/starter/core/autoconfigure/threadpool/ThreadPoolProperties.java create mode 100644 continew-starter-core/src/main/java/top/charles7c/continew/starter/core/exception/BaseException.java create mode 100644 continew-starter-core/src/main/java/top/charles7c/continew/starter/core/util/ExceptionUtils.java diff --git a/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/autoconfigure/cors/CorsAutoConfiguration.java b/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/autoconfigure/cors/CorsAutoConfiguration.java index 9574b0f5..b416ff8c 100644 --- a/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/autoconfigure/cors/CorsAutoConfiguration.java +++ b/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/autoconfigure/cors/CorsAutoConfiguration.java @@ -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; } } diff --git a/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/autoconfigure/threadpool/AsyncAutoConfiguration.java b/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/autoconfigure/threadpool/AsyncAutoConfiguration.java new file mode 100644 index 00000000..c63a328b --- /dev/null +++ b/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/autoconfigure/threadpool/AsyncAutoConfiguration.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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()); + }; + } +} diff --git a/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/autoconfigure/threadpool/ThreadPoolAutoConfiguration.java b/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/autoconfigure/threadpool/ThreadPoolAutoConfiguration.java new file mode 100644 index 00000000..f4954714 --- /dev/null +++ b/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/autoconfigure/threadpool/ThreadPoolAutoConfiguration.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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; + } +} diff --git a/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/autoconfigure/threadpool/ThreadPoolProperties.java b/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/autoconfigure/threadpool/ThreadPoolProperties.java new file mode 100644 index 00000000..21ee87b1 --- /dev/null +++ b/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/autoconfigure/threadpool/ThreadPoolProperties.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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; +} diff --git a/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/exception/BaseException.java b/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/exception/BaseException.java new file mode 100644 index 00000000..bd3b2836 --- /dev/null +++ b/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/exception/BaseException.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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); + } +} diff --git a/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/util/ExceptionUtils.java b/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/util/ExceptionUtils.java new file mode 100644 index 00000000..da06d061 --- /dev/null +++ b/continew-starter-core/src/main/java/top/charles7c/continew/starter/core/util/ExceptionUtils.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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 + * / + * @return / + */ + public static T exToNull(ExSupplier exSupplier) { + return exToDefault(exSupplier, null); + } + + /** + * 如果有异常,执行异常处理 + * + * @param supplier + * 可能会出现异常的方法执行 + * @param exConsumer + * 异常处理 + * @param + * / + * @return / + */ + public static T exToNull(ExSupplier supplier, Consumer exConsumer) { + return exToDefault(supplier, null, exConsumer); + } + + /** + * 如果有异常,返回空字符串 + * + * @param exSupplier + * 可能会出现异常的方法执行 + * @return / + */ + public static String exToBlank(ExSupplier exSupplier) { + return exToDefault(exSupplier, StringConsts.EMPTY); + } + + /** + * 如果有异常,返回默认值 + * + * @param exSupplier + * 可能会出现异常的方法执行 + * @param defaultValue + * 默认值 + * @param + * / + * @return / + */ + public static T exToDefault(ExSupplier exSupplier, T defaultValue) { + return exToDefault(exSupplier, defaultValue, null); + } + + /** + * 如果有异常,执行异常处理,返回默认值 + * + * @param exSupplier + * 可能会出现异常的方法执行 + * @param defaultValue + * 默认值 + * @param exConsumer + * 异常处理 + * @param + * / + * @return / + */ + public static T exToDefault(ExSupplier exSupplier, T defaultValue, Consumer exConsumer) { + try { + return exSupplier.get(); + } catch (Exception e) { + if (null != exConsumer) { + exConsumer.accept(e); + } + return defaultValue; + } + } + + /** + * 异常提供者 + * + * @param + * / + */ + public interface ExSupplier { + /** + * 获取返回值 + * + * @return / + * @throws Exception + * / + */ + T get() throws Exception; + } +} diff --git a/continew-starter-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/continew-starter-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 65bae9d0..9887d7eb 100644 --- a/continew-starter-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/continew-starter-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -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 \ No newline at end of file