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

  • 相关阅读:
    rake db:migrate学会的一些tips
    不提拔你,就因为你只想把工作做好
    jira4r:使用Ruby操作JIRA
    <当下的力量>读书笔记
    Your template was not saved as valid UTF8. 解决方法
    lxml.etree 教程3:Elements carry attributes as a dict
    Ruby目录及文件操作
    体验最火的敏捷SCRUM!(网络直播课程 免费)
    UMLonline技术沙龙:体验一把SCRUM(20121027 广州 免费)
    视频分享:挨踢项目求生法则(1)——团队建设篇
  • 原文地址:https://www.cnblogs.com/fanshuyao/p/15822189.html
Copyright © 2020-2023  润新知