当前位置: 代码网 > it编程>编程语言>Java > SpringBoot中使用@Async注解失效场景及说明

SpringBoot中使用@Async注解失效场景及说明

2024年07月24日 Java 我要评论
场景一:调用者与被调用者在同一个类中当调用 @async 注解的方法的类和被调用的方法在同一个类中时,@async 注解不会生效。因为 spring 的 aop 代理是基于接口的,对于同一个类中的方法

场景一:调用者与被调用者在同一个类中

当调用 @async 注解的方法的类和被调用的方法在同一个类中时,@async 注解不会生效。因为 spring 的 aop 代理是基于接口的,对于同一个类中的方法调用,不会经过代理,因此 @async 注解不会被处理。

例如:

@service  
public class myservice {  
  
    @async  
    public void asyncmethod() {  
        // 模拟耗时操作  
        try {  
            system.out.println("开始异步执行");  
            thread.sleep(5000);  
        } catch (interruptedexception e) {  
            e.printstacktrace();  
        }  
        system.out.println("async method executed.");  
    }  
  
    public void callasyncmethod() {  
        asyncmethod(); // 直接调用,不会异步执行  
    }  
}

场景二:配置类未启用异步支持

如果配置类中没有启用异步支持,即没有使用 @enableasync 注解,那么 @async 注解同样不会生效。

例如:

// 没有使用 @enableasync 注解,因此不会启用异步支持  
@configuration  
public class asyncconfig {  
    // ... 其他配置 ...  
}  
  
@service  
public class myservice {  
  
    @async  
    public void asyncmethod() {  
        // 模拟耗时操作  
        try {  
            thread.sleep(5000);  
        } catch (interruptedexception e) {  
            e.printstacktrace();  
        }  
        system.out.println("async method executed.");  
    }  
}

场景三:方法不是 public 的

@async 注解的方法必须是 public 的,否则不会被 spring aop 代理捕获,导致异步执行不生效。

例如:

@service  
public class myservice {  
  
    @async // 但这个方法不是 public 的,所以 @async 不会生效  
    protected void asyncmethod() {  
        // 模拟耗时操作  
        try {  
            thread.sleep(5000);  
        } catch (interruptedexception e) {  
            e.printstacktrace();  
        }  
        system.out.println("async method executed.");  
    }  
  
    public void callasyncmethod() {  
        asyncmethod(); // 直接调用,但由于 asyncmethod 不是 public 的,因此不会异步执行  
    }  
}

场景四:线程池未正确配置

在使用 @async 注解时,如果没有正确配置线程池,可能会遇到异步任务没有按预期执行的情况。例如,线程池被配置为只有一个线程,且该线程一直被占用,那么新的异步任务就无法执行。

例如:

@configuration  
@enableasync  
public class asyncconfig implements asyncconfigurer {  
  
    @override  
    public executor getasyncexecutor() {  
        // 创建一个只有一个线程的线程池,这会导致并发问题  
        threadpooltaskexecutor executor = new threadpooltaskexecutor();  
        executor.setcorepoolsize(1);  
        executor.setmaxpoolsize(1);  
        executor.setqueuecapacity(10);  
        executor.setthreadnameprefix("async-");  
        executor.initialize();  
        return executor;  
    }  
  
    // ... 其他配置 ...  
}
  
@service  
public class myservice {  
  
    @async  
    public void asyncmethod() {  
        // 模拟耗时操作  
        try {  
            thread.sleep(5000);  
        } catch (interruptedexception e) {  
            e.printstacktrace();  
        }  
        system.out.println("async method executed.");  
    }  
}

场景五:异常处理不当

如果在异步方法中抛出了异常,并且没有妥善处理,那么这个异常可能会导致任务失败,而调用者可能无法感知到异常的发生。

例如:

@service  
public class myservice {  
  
    @async  
    public void asyncmethod() {  
        // 模拟一个可能会抛出异常的耗时操作  
        throw new runtimeexception("async method exception");  
    }  
}
// 调用者  
@service  
public class callerservice {  
  
    @autowired  
    private myservice myservice;  
  
    public void callasyncmethod() {  
        myservice.asyncmethod(); // 调用异步方法,但如果该方法抛出异常,调用者不会立即感知到  
    }  
}

场景六:spring代理未生效

如果通过 new 关键字直接创建了服务类的实例,而不是通过 spring 容器来获取,那么 spring 的 aop 代理将不会生效,导致 @async 注解无效。

例如:

@service  
public class myservice {  
  
    @async  
    public void asyncmethod() {  
        // 模拟耗时操作  
        try {  
            thread.sleep(5000);  
        } catch (interruptedexception e) {  
            e.printstacktrace();  
        }  
        system.out.println("async method executed.");  
    }  
}  
  
public class somenonspringclass {  
  
    public void somemethod() {  
        myservice myservice = new myservice(); // 直接通过 new 创建 myservice 实例,不会经过 spring 代理  
        myservice.asyncmethod(); // 这里 @async 不会生效  
    }  
}

场景七:使用 @transactional 与 @async 同时注解方法,导致事务失效

在同一个方法上同时使用 @transactional 和 @async 注解可能会导致问题。由于 @async 会导致方法在一个新的线程中执行,而 @transactional 通常需要在一个由 spring 管理的事务代理中执行,这两个注解的结合使用可能会导致事务管理失效或行为不可预测。此种场景不会导致@async注解失效,但是会导致@transactional注解失效,也就是事务失效。

例如:

@service  
public class myservice {  
  
    @autowired  
    private myrepository myrepository;  
  
    // 错误的用法:同时使用了 @transactional 和 @async  
    @transactional  
    @async  
    public void asynctransactionalmethod() {  
        // 模拟一个数据库操作  
        myrepository.save(new myentity());  
          
        // 模拟可能抛出异常的代码  
        if (true) {  
            throw new runtimeexception("database operation failed!");  
        }  
    }  
}  
  
@repository  
public interface myrepository extends jparepository<myentity, long> {  
    // ...  
}  
  
@entity  
public class myentity {  
    // ... 实体类的属性和映射 ...  
}

总结一下 :

绝大多数人会遇到的坑点主要会集中在没有配置自定义线程池、异步方法在同一个类中调用、事务不起作用这几个问题上。所以,万金油的写法还是专门定义一个asyncservice,将异步方法都写在里面,需要使用的时候,就在其他类将其注入即可。

以上就是springboot中使用@async注解失效场景及说明的详细内容,更多关于springboot @async注解失效的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com