Spring中@Async用法

引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的;但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring 3.x之后,就已经内置了@Async来完美解决这个问题,本文将完成介绍@Async的用法。

1.  何为异步调用?

在解释异步调用之前,我们先来看同步调用的定义;同步就是整个处理过程顺序执行,当各个过程都执行完毕,并返回结果。 异步调用则是只是发送了调用的指令,调用者无需等待被调用的方法完全执行完毕;而是继续执行下面的流程。

例如, 在某个调用中,需要顺序调用 A, B, C三个过程方法;如他们都是同步调用,则需要将他们都顺序执行完毕之后,方算作过程执行完毕; 如B为一个异步的调用方法,则在执行完A之后,调用B,并不等待B完成,而是执行开始调用C,待C执行完毕之后,就意味着这个过程执行完毕了。

2.  常规的异步调用处理方式

在Java中,一般在处理类似的场景之时,都是基于创建独立的线程去完成相应的异步调用逻辑,通过主线程和不同的线程之间的执行流程,从而在启动独立的线程之后,主线程继续执行而不会产生停滞等待的情况。

3. @Async介绍

在Spring中,基于@Async标注的方法,称之为异步方法;这些方法将在执行的时候,将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作。

如何在Spring中启用@Async

基于Java配置的启用方式:

?
    1. @Configuration
      1. @EnableAsync
        1. public class SpringAsyncConfig { ... }
      1.  

      基于XML配置文件的启用方式,配置如下:

        1. <task:executor id="myexecutor"pool-size="5"/>
          1. <task:annotation-driven executor="myexecutor"/>
        1.  

        以上是两种配置方式

        4. 基于@Async无返回值调用

        示例如下:

          1. @Async//标注使用
            1. public void asyncMethodWithVoidReturnType() {
              1. System.out.println("Execute method asynchronously. "
                1. + Thread.currentThread().getName());
                  1. }
                1.  
                ?

                使用的方式非常简单,一个标注即可解决所有的问题。

                5. 基于@Async返回值的调用

                示例如下:

                  1. @Async
                    1. public Future<String> asyncMethodWithReturnType() {
                      1. System.out.println("Execute method asynchronously - "
                        1. + Thread.currentThread().getName());
                          1. try{
                            1. Thread.sleep(5000);
                              1. returnnew AsyncResult<String>("hello world !!!!");
                                1. }catch(InterruptedException e) {
                                  1. //
                                    1. }
                                        1. return null;
                                          1. }
                                        1.  
                                        ?

                                        以上示例可以发现,返回的数据类型为Future类型,其为一个接口。具体的结果类型为AsyncResult,这个是需要注意的地方。

                                        调用返回结果的异步方法示例:

                                          1. public void testAsyncAnnotationForMethodsWithReturnType()
                                            1. throws InterruptedException, ExecutionException {
                                              1. System.out.println("Invoking an asynchronous method. "
                                                1. + Thread.currentThread().getName());
                                                  1. Future<String> future = asyncAnnotationExample.asyncMethodWithReturnType();
                                                      1. while(true) { ///这里使用了循环判断,等待获取结果信息
                                                        1. if(future.isDone()) { //判断是否执行完毕
                                                          1. System.out.println("Result from asynchronous process - " + future.get());
                                                            1. break;
                                                              1. }
                                                                1. System.out.println("Continue doing something else. ");
                                                                  1. Thread.sleep(1000);
                                                                    1. }
                                                                      1. }
                                                                    1.  
                                                                    ?

                                                                    分析: 这些获取异步方法的结果信息,是通过不停的检查Future的状态来获取当前的异步方法是否执行完毕来实现的。

                                                                    6. 基于@Async调用中的异常处理机制

                                                                    在异步方法中,如果出现异常,对于调用者caller而言,是无法感知的。如果确实需要进行异常处理,则按照如下方法来进行处理:

                                                                    1.  自定义实现AsyncTaskExecutor的任务执行器

                                                                    在这里定义处理具体异常的逻辑和方式。

                                                                    2.  配置由自定义的TaskExecutor替代内置的任务执行器

                                                                    示例步骤1,自定义的TaskExecutor

                                                                      1. public class ExceptionHandlingAsyncTaskExecutor implements AsyncTaskExecutor {
                                                                        1. private AsyncTaskExecutor executor;
                                                                          1. public ExceptionHandlingAsyncTaskExecutor(AsyncTaskExecutor executor) {
                                                                            1. this.executor = executor;
                                                                              1. }
                                                                                1. ////用独立的线程来包装,@Async其本质就是如此
                                                                                  1. public void execute(Runnable task) {
                                                                                    1. executor.execute(createWrappedRunnable(task));
                                                                                      1. }
                                                                                        1. public void execute(Runnable task, longstartTimeout) {
                                                                                          1. /用独立的线程来包装,@Async其本质就是如此
                                                                                            1. executor.execute(createWrappedRunnable(task), startTimeout);
                                                                                              1. }
                                                                                                1. public Future submit(Runnable task) { returnexecutor.submit(createWrappedRunnable(task));
                                                                                                  1. //用独立的线程来包装,@Async其本质就是如此。
                                                                                                    1. }
                                                                                                      1. public Future submit(finalCallable task) {
                                                                                                        1. //用独立的线程来包装,@Async其本质就是如此。
                                                                                                          1. return executor.submit(createCallable(task));
                                                                                                            1. }
                                                                                                                1. private Callable createCallable(finalCallable task) {
                                                                                                                  1. retur nnew Callable() {
                                                                                                                    1. public T call() throwsException {
                                                                                                                      1. try{
                                                                                                                        1. return task.call();
                                                                                                                          1. }catch(Exception ex) {
                                                                                                                            1. handle(ex);
                                                                                                                              1. throwex;
                                                                                                                                1. }
                                                                                                                                  1. }
                                                                                                                                    1. };
                                                                                                                                      1. }
                                                                                                                                          1. private Runnable createWrappedRunnable(finalRunnable task) {
                                                                                                                                            1. return new Runnable() {
                                                                                                                                              1. public void run() {
                                                                                                                                                1. try{
                                                                                                                                                  1. task.run();
                                                                                                                                                    1. }catch(Exception ex) {
                                                                                                                                                      1. handle(ex);
                                                                                                                                                        1. }
                                                                                                                                                          1. }
                                                                                                                                                            1. };
                                                                                                                                                              1. }
                                                                                                                                                                1. private void handle(Exception ex) {
                                                                                                                                                                  1. //具体的异常逻辑处理的地方
                                                                                                                                                                    1. System.err.println("Error during @Async execution: " + ex);
                                                                                                                                                                      1. }
                                                                                                                                                                        1. }
                                                                                                                                                                      1.  
                                                                                                                                                                      ?

                                                                                                                                                                      分析: 可以发现其是实现了AsyncTaskExecutor, 用独立的线程来执行具体的每个方法操作。在createCallable和createWrapperRunnable中,定义了异常的处理方式和机制。

                                                                                                                                                                      handle()就是未来我们需要关注的异常处理的地方。

                                                                                                                                                                      配置文件中的内容:

                                                                                                                                                                        1. <task:annotation-driven executor="exceptionHandlingTaskExecutor"scheduler="defaultTaskScheduler"/>
                                                                                                                                                                          1. <bean id="exceptionHandlingTaskExecutor"class="nl.jborsje.blog.examples.ExceptionHandlingAsyncTaskExecutor">
                                                                                                                                                                            1. <constructor-arg ref="defaultTaskExecutor"/>
                                                                                                                                                                              1. </bean>
                                                                                                                                                                                1. <task:executor id="defaultTaskExecutor"pool-size="5"/>
                                                                                                                                                                                  1. <task:scheduler id="defaultTaskScheduler"pool-size="1"/>
                                                                                                                                                                                1.  
                                                                                                                                                                                ?

                                                                                                                                                                                分析: 这里的配置使用自定义的taskExecutor来替代缺省的TaskExecutor。

                                                                                                                                                                                7. @Async调用中的事务处理机制

                                                                                                                                                                                在@Async标注的方法,同时也适用了@Transactional进行了标注;在其调用数据库操作之时,将无法产生事务管理的控制,原因就在于其是基于异步处理的操作。

                                                                                                                                                                                那该如何给这些操作添加事务管理呢?可以将需要事务管理操作的方法放置到异步方法内部,在内部被调用的方法上添加@Transactional.

                                                                                                                                                                                例如:  方法A,使用了@Async/@Transactional来标注,但是无法产生事务控制的目的。

                                                                                                                                                                                方法B,使用了@Async来标注,  B中调用了C、D,C/D分别使用@Transactional做了标注,则可实现事务控制的目的。

                                                                                                                                                                                8. 总结

                                                                                                                                                                                通过以上的描述,应该对@Async使用的方法和注意事项了。

                                                                                                                                                                                Spring中@Async用法详解及简单实例的更多相关文章

                                                                                                                                                                                1. AngularJS select中ngOptions用法详解

                                                                                                                                                                                  AngularJS select中ngOptions用法详解   一.用法 ngOption针对不同类型的数据源有不同的用法,主要体现在数组和对象上. 数组: label for value in a ...

                                                                                                                                                                                2. C++中的STL中map用法详解(转)

                                                                                                                                                                                  原文地址: https://www.cnblogs.com/fnlingnzb-learner/p/5833051.html C++中的STL中map用法详解   Map是STL的一个关联容器,它提供 ...

                                                                                                                                                                                3. Spring中的BeanPostProcessor详解

                                                                                                                                                                                  Spring中的BeanPostProcessor详解 概述 BeanPostProcessor也称为Bean后置处理器,它是Spring中定义的接口,在Spring容器的创建过程中(具体为Bean初 ...

                                                                                                                                                                                4. JSP 注释的详解及简单实例

                                                                                                                                                                                  转自:https://www.jb51.net/article/124727.htm JSP 注释的详解及简单实例 一 三种格式 二 举例 ? 1 2 3 4 5 6 7 8 9 10 11 12 1 ...

                                                                                                                                                                                5. Spring中@Async用法总结

                                                                                                                                                                                  引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在Spring 3. ...

                                                                                                                                                                                6. spring中的scope详解

                                                                                                                                                                                  spring容器中的bean默认是单例模式的,改成非单例模式需要在类上加上@Scope("prototype") 1. scope概论 spring中scope是一个非常关键的概念 ...

                                                                                                                                                                                7. (转)Spring中@Async用法总结

                                                                                                                                                                                   原文:http://blog.csdn.net/blueheart20/article/details/44648667 引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的: ...

                                                                                                                                                                                8. C++中const用法详解

                                                                                                                                                                                  本文主要内容来自CSDN论坛: http://bbs.csdn.net/topics/310007610 我做了下面几点补充. 补充: 1. 用const声明全局变量时, 该变量仅在本文件内可见, 类 ...

                                                                                                                                                                                9. c/c++中define用法详解及代码示例

                                                                                                                                                                                  https://blog.csdn.net/u012611878/article/details/52534622   版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog. ...

                                                                                                                                                                                随机推荐

                                                                                                                                                                                1. Java基础学习总结(21)——常用正则表达式列表

                                                                                                                                                                                  很多不太懂正则的朋友,在遇到需要用正则校验数据时,往往是在网上去找很久,结果找来的还是不很符合要求.所以我最近把开发中常用的一些正则表达式整理了一下,包括校验数字.字符.一些特殊的需求等等.给自己留个 ...

                                                                                                                                                                                2. oracle取随机结果测试

                                                                                                                                                                                  http://www.2cto.com/database/201307/227524.html

                                                                                                                                                                                3. Excel VBA简单使用——数据缺失处理

                                                                                                                                                                                  VBA(Visual Basic for Applications)是VB的一种宏语言.用来扩展应用程式的功能.特别是Microsoft Office软件. 转载请注明原文地址:http://blog ...

                                                                                                                                                                                4. android 自己定义控件属性(TypedArray以及attrs解释)

                                                                                                                                                                                  近期在捣鼓android 自己定义控件属性,学到了TypedArray以及attrs.在这当中看了一篇大神博客Android 深入理解Android中的自己定义属性.我就更加深入学习力一番.我就沿着这 ...

                                                                                                                                                                                5. 火狐—火狐浏览器中的“HttpWatch”

                                                                                                                                                                                  在IE下通过HttpWatch能够查看HTTP请求的相关细节.这对我们分析程序的运行效率很有帮助,但是在火狐浏览器中的难道就没有相似的工具了吗?答案是否定的--火狐浏览器中也有.在火狐浏览器中该工具叫 ...

                                                                                                                                                                                6. Linux下基于LDAP统一用户认证的研究

                                                                                                                                                                                  Linux下基于LDAP统一用户认证的研究                   本文出自 "李晨光原创技术博客" 博客,谢绝转载!

                                                                                                                                                                                7. Maven用法

                                                                                                                                                                                  Maven 的使用教程   1.什么是 Maven? Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具.   2.下载 Maven? ①.官网下载 ...

                                                                                                                                                                                8. JavaScript--Module模式

                                                                                                                                                                                  //module: Module模式是JavaScript编程中一个非常通用的模式 window.onload = function() { //1.基本使用: var MyFn = function ...

                                                                                                                                                                                9. BZOJ4372: 烁烁的游戏(动态点分治)

                                                                                                                                                                                  Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮 ...

                                                                                                                                                                                10. 【Good Bye 2017 A】New Year and Counting Cards

                                                                                                                                                                                  [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 是元音字母或者是奇数就递增. [代码] #include <bits/stdc++.h> using namespace ...