Spring boot如何实现异步调用
异步调用:一个可以无需等待被调用函数的返回值就让操作继续进行的方法
举个例子
异步调用就是你 喊 你朋友吃饭 ,你朋友说知道了 ,待会忙完去找你 ,你就去做别的了。同步调用就是你 喊 你朋友吃饭 ,你朋友在忙 ,你就一直在那等,等你朋友忙完了 ,你们一起去。
我想大家都了解了,但是怎么在代码中实现,我们以往的代码都是一步步执行下去的,现在我们要求某个耗时方法,让他单独执行不考虑结果。
题目
classGzhApplicationTests{ @Autowired privateAsyncTestasyncTest; @Test voidcontextLoads()throwsException{ System.out.println("---执行主线---"); asyncTest.test1(); System.out.println("---主线结束---"); } }@SpringBootTest
publicclassAsyncTest{ publicvoidtest1(){ System.out.println("---执行副本---"); for(inti=0;i5;i++){ try{ Thread.sleep(1000); }catch(InterruptedExceptione){ e.printStackTrace(); } System.out.println("---副本ing---"); } System.out.println("---副本结束---"); } }@Component
运行结果
---执行副本--- ---副本ing--- ---副本ing--- ---副本ing--- ---副本ing--- ---副本ing--- ---副本结束--- ---主线结束------执行主线---
这边的结果看到了,他是先执行完副本,然后主线才结束,我们想要的是不管副本如何我们都要继续往下走,专业术语异步执行
。
有同学说简单,new Thread()
,把副本放进去就可以了。
voidcontextLoads()throwsException{ System.out.println("---执行主线---"); newThread(()->asyncTest.test1()).start(); System.out.println("---主线结束---"); } //---执行主线--- //---主线结束--- //---执行副本---@Test
有人会问副本为什么没有执行完,你用的是单元测试,主程序跑完就项目就停止了,你要是不用单元测试的话,他会执行完。
当然用new Thread()
可以解决,但是今天要用注解方式解决。@Async
这个注解就可以解决。
@SpringBootApplication publicclassGzhApplication{ publicstaticvoidmain(String[]args){ SpringApplication.run(GzhApplication.class,args); } }@EnableAsync
publicclassAsyncTest{ @Async publicvoidtest1(){ System.out.println("---执行副本---"); for(inti=0;i5;i++){ try{ Thread.sleep(1000); }catch(InterruptedExceptione){ e.printStackTrace(); } System.out.println("---副本ing---"); } System.out.println("---副本结束---"); } }@Component
classGzhApplicationTests{ @Autowired privateAsyncTestasyncTest; @Test voidcontextLoads()throwsException{ System.out.println("---执行主线---"); asyncTest.test1(); System.out.println("---主线结束---"); } }@SpringBootTest
---主线结束--- ---执行副本------执行主线---
但是有同学会说不我添加了注解不行啊。这地方我们就要去来说说要注意的事项。
失效原因
1.没有在@SpringBootApplication启动类当中添加注解@EnableAsync注解。2.异步方法使用注解@Async的返回值只能为void或者Future。3.没有走Spring的代理类。因为@Transactional和@Async注解的实现都是基于Spring的AOP,而AOP的实现是基于动态代理模式实现的。那么注解失效的原因就很明显了,有可能因为调用方法的是对象本身而不是代理对象,因为没有经过Spring容器。第一个和第二个的意思很清楚,第三个的意思就是类的内部调用是无效的。方法一定要从另一个类中调用,也就是从类的外部调用。如果你想内部调用就获取其代理对象。