springboot @EnableAsync 異步,springboot @Async不生效


 

================================

©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/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM