什么情况下会导致@Async异步方法会失效?
a.调用同一个类下注有@Async异步方法:在spring中像@Async和@Transactional、cache等注解本质使用的是动态代理,其实Spring容器在初始化的时候Spring容器会将含有AOP注解的类对象“替换”为代理对象(简单这么理解),那么注解失效的原因就很明显了,就是因为调用方法的是对象本身而不是代理对象,因为没有经过Spring容器,那么解决方法也会沿着这个思路来解决。
b.调用的是静态(static )方法
c.调用(private)私有化方法
解决4中问题1的方式(其它2,3两个问题自己注意下就可以了)
将要异步执行的方法单独抽取成一个类,原理就是当你把执行异步的方法单独抽取成一个类的时候,这个类肯定是被Spring管理的,其他Spring组件需要调用的时候肯定会注入进去,这时候实际上注入进去的就是代理类了。
其实我们的注入对象都是从Spring容器中给当前Spring组件进行成员变量的赋值,由于某些类使用了AOP注解,那么实际上在Spring容器中实际存在的是它的代理对象。那么我们就可以通过上下文获取自己的代理对象调用异步方法。
@Controller
@RequestMapping("/app")
public class EmailController {//获取ApplicationContext对象方式有多种,这种最简单,其它的大家自行了解一下@Autowiredprivate ApplicationContext applicationContext;@RequestMapping(value = "/email/asyncCall", method = GET)@ResponseBodypublic Map<String, Object> asyncCall () {Map<String, Object> resMap = new HashMap<String, Object>();try{//这样调用同类下的异步方法是不起作用的//this.testAsyncTask();//通过上下文获取自己的代理对象调用异步方法EmailController emailController = (EmailController)applicationContext.getBean(EmailController.class);emailController.testAsyncTask();resMap.put("code",200);}catch (Exception e) {resMap.put("code",400);logger.error("error!",e);}return resMap;}//注意一定是public,且是非static方法@Asyncpublic void testAsyncTask() throws InterruptedException {Thread.sleep(10000);System.out.println("异步任务执行完成!");}}