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