springboot @EnableAsync asynchronous, springboot @Async does not take effect

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

©Copyright Sweet Potato Yao 2022-01-17

​​Sweet Potato Yao's Blog - CSDN Blog

1. Springboot asynchronous thread Executor configuration

Springboot version:

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.5.7</version>
		<relativePath/>
	</parent>

Note: Method 1 and Method 2 can only be selected. It is recommended to use Method 1, which can print the error log

Method 1: AsyncConfigurer interface implementation

You cannot inject other bean objects through @Resource or @Autowired in this class, otherwise it will cause the [asynchronous] function to fail and become [synchronous]


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());
			
        };
    }
 
}

Example of failure: I originally thought of recording it when it was wrong, but the result has been invalid (becoming synchronous)

Method 2: Configure the bean object of the Executor

The returned Executor object must be the bean object of TaskExecutor, or the bean name is: taskExecutor, if not, the default is: 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;
    }
    
}

2. Asynchronous operation class

The asynchronous operation class must create a new independent class and add an annotation to the method: @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);
	}
	
}

Three, SpringBoot asynchronous method call

1. Inject the object first

@Resource
private SysLogService sysLogService;

2, call

log.info(Thread.currentThread().getName() + "========start ========");

//日志审计,异步调用
sysLogService.save(xxxxxx);

log.info(Thread.currentThread().getName() + "========end========");

(Time is precious, sharing is not easy, donate and give back, ^_^)

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

©Copyright Sweet Potato Yao 2022-01-17

​​Sweet Potato Yao's Blog - CSDN Blog

Guess you like

Origin blog.csdn.net/w995223851/article/details/122543197