@Async失效之谜

作者: 迦叶_金色的人生_荣耀而又辉煌 | 来源:发表于2020-11-11 18:59 被阅读0次

    @Async如何使用

    • 异步的方法上加上@Async异步注解
    • 启动类中需要加上@EnableAsync才有效
      使用时类似于下列函数:
    new Thread(()-> System.out.println("hello world !"))
    

    @Async线程池

    • 默认线程池
      无论重复多少次,都默认8个左右的线程在跑
      异步线程:task-1执行成功
      异步线程:task-2执行成功
      异步线程:task-3执行成功
      异步线程:task-4执行成功
      异步线程:task-5执行成功
      异步线程:task-6执行成功
      异步线程:task-7执行成功
      异步线程:task-1执行成功
      异步线程:task-2执行成功
      异步线程:task-8执行成功
      异步线程:task-3执行成功
      异步线程:task-8执行成功
      异步线程:task-6执行成功
      异步线程:task-8执行成功
      异步线程:task-5执行成功
      异步线程:task-3执行成功
      异步线程:task-2执行成功
      异步线程:task-1执行成功
    • 自定义线程池配置
    /**
     * 配置类实现AsyncConfigurer接口并重写getAsyncExcutor方法,并返回一个ThreadPoolTaskExevutor
     * 这样我们就给Async配置自定义线程池
     */
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(CORE_POOL_SIZE);
        taskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
        taskExecutor.setQueueCapacity(QUEUE_CAPACITY);
        taskExecutor.initialize();
        return taskExecutor;
    }
    

    异步线程:ThreadPoolTaskExecutor-2执行成功
    异步线程:ThreadPoolTaskExecutor-1执行成功
    异步线程:ThreadPoolTaskExecutor-3执行成功
    异步线程:ThreadPoolTaskExecutor-1执行成功
    异步线程:ThreadPoolTaskExecutor-3执行成功
    异步线程:ThreadPoolTaskExecutor-2执行成功
    异步线程:ThreadPoolTaskExecutor-1执行成功
    异步线程:ThreadPoolTaskExecutor-3执行成功

    @Async和@Controller同时使用存在异常

    AbstractHandlerMethodMapping初始bean时,在afterPropertiesSet方法中initHandlerMethods()关联我们的SpringMVCBean

    // 类型判断
    if (beanType != null && isHandler(beanType)) {
            // url处理
        detectHandlerMethods(beanName);
    }
    
    // Controller和RequestMapping注解判断
    protected boolean isHandler(Class<?> beanType) {
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
                AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }
    

    a、@Controller不使用@Async注解时

    @RestController
    @Slf4j
    public class MemberServiceImpl1 {
    
        @GetMapping("/addUser1")
        public String addUser() {
            log.info(">>>流程1");
            log.info(">>>流程2");
            return "success";
        }
    }
    
    image.png

    b、@Controller使用@Async注解,但不继承接口时,异步失效

    @RestController
    @Slf4j
    public class MemberServiceImpl3 {
    
        @GetMapping("/addUser3")
        public String addUser() {
            log.info(">>>流程1");
            addUserLog();
            log.info(">>>流程3");
            return "success";
        }
    
        @Async()
        public String addUserLog() {
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
    
            }
            log.info(">>>流程2");
            return "success";
        }
    }
    
    image.png
    异步失效

    c、@Controller使用@Async注解,同时继承接口

    @RestController
    @Slf4j
    public class MemberServiceImpl4 implements MemberService {
    
        @Override
        @GetMapping("/addUser4")
        public String addUser() {
            log.info(">>>流程1");
            addUserLog();
            log.info(">>>流程3");
            return "success";
        }
    
        @Async()
        public String addUserLog() {
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
    
            }
            log.info(">>>流程2");
            return "success";
        }
    }
    
    image.png
    访问404

    @Async使用建议

    • a、异步执行的建议单独开启一个类实现,或者从容器中直接获取到该代理类后执行
    /** 
    * 异步代码写到别的地方,不要和Controller注解同时使用
    */
    @RestController
    @Slf4j
    public class ResolveServiceImpl {
    
        @Autowired
        private MemberServiceManage memberServiceManage;
    
        @GetMapping("/resolve2")
        public String addUser() {
            log.info(">>>流程1");
            memberServiceManage.addUserLog();
            log.info(">>>流程3");
            return "success";
        }
    }
    @Component
    @Slf4j
    public class MemberServiceManage {
        @Async
        public String addUserLog() {
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
    
            }
            log.info(">>>流程2");
            return "success";
        }
    }
    
    /** 
    * 使用SpringUtils获得bean后调用,不要使用this操作
    */
    @GetMapping("/resolve1")
    public String addUser() {
        log.info(">>>流程1");
        //把直接调用改为从容器中取一次
        ResolveServiceImpl bean = SpringUtils.getBean(ResolveServiceImpl.class);
        bean.addUserLog();
        log.info(">>>流程3");
        return "success";
    }
    
    • b、异步的方法上不要加static,加了static就不走AOP了

    相关文章

      网友评论

        本文标题:@Async失效之谜

        本文链接:https://www.haomeiwen.com/subject/akfsbktx.html