================================
©Copyright 蕃薯耀 2022-01-19
https://www.cnblogs.com/fanshuyao/
一、Springboot異步線程Executor配置
Springboot 版本:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.7</version> <relativePath/> </parent>
注意:方式一和方式二只能選其一,建議使用方式一,可以打印錯誤日志
方式一:AsyncConfigurer接口實現
不能在此類中通過@Resource或者@Autowired注入其它bean對象,否則會導致【異步】功能失效變成[同步]
import java.lang.reflect.Method; import java.util.concurrent.Executor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.AsyncConfigurer; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import com.zj31mep.utils.ContextUtil; import cn.hutool.json.JSONUtil; /** * 不能通過@Resource或者@Autowired注入其它bean對象,否則會導致[異步]功能失效變成[同步] * * @author islee * */ @EnableAsync @Configuration public class AsyncConfig implements AsyncConfigurer { private static final Logger log = LoggerFactory.getLogger(AsyncConfig.class); /** * 線程池配置,繼承AsyncConfigurer,不需要聲明成bean對象 */ @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //核心線程數:線程池創建時候初始化的線程數,方法: 返回可用處理器的Java虛擬機的數量。 executor.setCorePoolSize(Runtime.getRuntime().availableProcessors()); //最大線程數:線程池最大的線程數,只有在緩沖隊列滿了之后才會申請超過核心線程數的線程 //默認是:Integer.MAX_VALUE //executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors()*5); //線程池的隊列容量,用來緩沖執行任務的隊列 //默認是:Integer.MAX_VALUE //executor.setQueueCapacity(Runtime.getRuntime().availableProcessors()*2); //線程池名的前綴:設置好了之后可以方便我們定位處理任務所在的線程池 executor.setThreadNamePrefix("async-executor-"); //允許線程的空閑時間N秒:當超過了核心線程出之外的線程在空閑時間到達之后會被銷毀 //默認是60秒 //executor.setKeepAliveSeconds(120); //線程池對拒絕任務的處理策略:這里采用了CallerRunsPolicy策略 //當線程池沒有處理能力的時候,該策略會直接在 execute 方法調用的線程中運行被拒絕的任務; //如果執行程序已關閉,則會丟棄該任務 //executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } /** * 異步任務中異常處理 */ @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return (Throwable ex, Method method, Object... params) -> { //異步方法異常處理 String className = method.getDeclaringClass().getName(); String methodName = method.getName(); StringBuffer sb = new StringBuffer(""); sb.append("Async執行的請求路徑").append(":").append(ContextUtil.HTTP_REQUEST.get() == null ? null : ContextUtil.HTTP_REQUEST.get().getRequestURI()); sb.append(",").append("Async執行的方法").append(":").append(className + "." + methodName); sb.append(",").append("Async執行的方法參數").append(":").append(JSONUtil.toJsonStr(params)); sb.append(",").append("Async執行的用戶信息").append(":").append(JSONUtil.toJsonStr(ContextUtil.SYS_USER.get())); sb.append(",").append("Async執行的異常信息").append(":").append(JSONUtil.toJsonStr(ex)); log.error(sb.toString()); }; } }
失效的示例:本來想着在錯誤的時候也記錄一下,但結果一直失效(變成同步)
方式二:配置Executor的bean對象
返回的Executor對象必須是TaskExecutor的bean對象,或者bean名稱是:taskExecutor,如果沒有,默認是:SimpleAsyncTaskExecutor
import java.util.concurrent.Executor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @EnableAsync @Configuration public class AsyncExecutorConfig{ /** * 線程池配置 * * 必須是TaskExecutor的bean對象,或者bean名稱是:taskExecutor * 如果沒有,默認是:SimpleAsyncTaskExecutor * {@link org.springframework.core.task.SimpleAsyncTaskExecutor} * * 這里是不需要初始化的:executor.initialize(),bean創建完后會自動初始化 */ @Bean public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //核心線程數:線程池創建時候初始化的線程數,方法: 返回可用處理器的Java虛擬機的數量。 executor.setCorePoolSize(Runtime.getRuntime().availableProcessors()); //線程池最大的線程數,默認是:Integer.MAX_VALUE //只有在緩沖隊列滿了之后才會申請超過核心線程數的線程 //executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors()*5); //線程池的隊列容量,用來緩沖執行任務的隊列 //默認是:Integer.MAX_VALUE //executor.setQueueCapacity(Runtime.getRuntime().availableProcessors()*2); //線程池名的前綴:設置好了之后可以方便我們定位處理任務所在的線程池 executor.setThreadNamePrefix("async-executor-"); //允許線程的空閑時間N秒:當超過了核心線程出之外的線程在空閑時間到達之后會被銷毀 //默認是60秒 //executor.setKeepAliveSeconds(120); //線程池對拒絕任務的處理策略:這里采用了CallerRunsPolicy策略 //當線程池沒有處理能力的時候,該策略會直接在 execute 方法調用的線程中運行被拒絕的任務; //如果執行程序已關閉,則會丟棄該任務 //executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); return executor; } }
二、異步操作類
異步操作類必須新建立獨立的類,在方法添加注解:@Async
import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.zj31mep.biz.system.dao.SysLogDao; import com.zj31mep.biz.system.entity.SysLog; import com.zj31mep.biz.system.service.SysLogService; /** * <p> * 服務實現類 * </p> * * @author root * @since 2022-01-17 */ @Service public class SysLogServiceImpl extends ServiceImpl<SysLogDao, SysLog> implements SysLogService { @Async @Override public void save(xxxx) { this.save(sysLog); } }
三、SpringBoot異步方法調用
1、先注入對象
@Resource private SysLogService sysLogService;
2、調用
log.info(Thread.currentThread().getName() + "========start ========"); //日志審計,異步調用 sysLogService.save(xxxxxx); log.info(Thread.currentThread().getName() + "========end========");
(時間寶貴,分享不易,捐贈回饋,^_^)
================================
©Copyright 蕃薯耀 2022-01-19
https://www.cnblogs.com/fanshuyao/