- 为什么要使用
- 在我们的日常开发中,我们偶尔会遇到在业务层中我们需要同时修改多张表的数据并且需要有序的执行,如果我们用往常的同步的方式,也就是单线程的方式来执行的话,可能会出现执行超时等异常造成请求结果失败,即使成功,前端也需要等待较长时间来获取响应结果,这样不但造成了用户体验差,而且会经常出现请求执行失败的问题
- 在解释异步调用之前,我们先来看同步调用的定义;
- 同步就是整个处理过程顺序执行,当各个过程都执行完毕,并返回结果。
- 异步调用则是只是发送了调用的指令,调用者无需等待被调用的方法完全执行完毕;而是继续执行下面的流程。
- 什么时候使用
- 在某个调用中,需要顺序调用 A, B, C三个过程方法;如他们都是同步调用,则需要将他们都顺序执行完毕之后,才算作过程执行完毕; 如B为一个异步的调用方法,则在执行完A之后,调用B,并不等待B完成,而是执行开始调用C,待C执行完毕之后,就意味着这个过程执行完毕了。
- 在生成订单的时候给用户发送短信,生成订单的结果不应该被发送短信的成功与否所左右,也就是说生成订单这个主操作是不依赖于发送短信这个操作,所以我们就可以把发送短信这个操作置为异步操作。
- 实现异步的方式:
- 使用线程池的方式来实现
我们发现在主线程中使用线程池中的线程来实现,程序的执行结果表明,主线程直接将结果进行了返回,然后才是线程池在执行业务逻辑,减少了请求响应时长。
2. 使用消息队列(mq)来实现
当我们涉及的请求在业务逻辑中一次性操作很多很多的数据,例如:一个请求执行相关业务操作后,将操作日志插入到数据库中,我们可以使用@Async来实现,但是这样增加了业务和非业务关系的冗余性(同时如何并发量很大,我们使用@Async处理,无法提升我们系统的整体系统,这样很容易造成服务器宕机),所以我们对于这种情况,我们会采用mq来实现,将业务逻辑和非业务逻辑进行隔离执行,互不影响,非业务逻辑不会影响到执行业务逻辑的结果和主机性能。
3. 使用注解@EnableAsync和@Async来实现
虽然这样实现了我们想要的结果,但是,但是我们发现如果我们在多个请求中都需要这种异步请求,每次都写这么冗余的线程池配置会不会,这种问题当然会被我们强大的spring所观察到,所以spring为了提升开发人员的开发效率,使用@EnableAsync来开启异步的支持,使用@Async来对某个方法进行异步执行。
4. 使用规范
- 自定义线程池的配置类,并在类上添加@EnableAsync 注解,然后在需要异步的方法上使用@Async("线程池名称") 该方法就可以异步执行了。
- @Async调用中的事务处理机制
- 在@Async标注的方法,同时也适用了@Transactional进行了标注;在其调用数据库操作之时,将无法产生事务管理的控制,原因就在于其是基于异步处理的操作。
- 那该如何给这些操作添加事务管理呢?可以将需要事务管理操作的方法放置到异步方法内部,在内部被调用的方法上添加@Transactional.
- @Async调用中的事务处理机制
例如:
方法A:使用了@Async/@Transactional来标注,但是无法产生事务控 制的目的。
方法B:使用了@Async来标注,B中调用了C、D,C/D分别使用 @Transactional做了标注,则可实现事务控制的目的。
5.@Async注解使用细节
-
- @Async注解一般用在方法上,如果用在类上,那么这个类所有的方法都是异步执行的;
- @Async可以放在任何方法上,哪怕你是private的(若是同类调用,请务必注意注解失效的情况~~~)
- 所使用的@Async注解方法的类对象应该是Spring容器管理的bean对象
- @Async可以放在接口处(或者接口方法上)。但是只有使用的是JDK的动态代理时才有效,CGLIB会失效。因此建议:统一写在实现类的方法上
- 需要注解@EnableAsync来开启异步注解的支持
- 若你希望得到异步调用的返回值,请你的返回值用Futrue变量包装起来
- 需要额外导入哪些Jar包?
- 它的依赖包非常简单,只依赖一些Spring的核心包外加spring-aop,但是如果你已经导入了spring-webmvc这个jar,那就什么不需要额外导入了,因为都有了: