2020-04-24

Asynchronous processing with @Async in Spring

Asynchronous processing with @Async in Spring

1.Overview Overview

In this article, we will look at asynchronous execution support and @Async annotation in Spring . Simply put, if you put the @Async annotation in an empty bean , it will be executed in a separate thread. For example, the caller does not have to wait for the called method to complete.

2. Turn on Async function  Enable Async Support

Java settings Java configuration asynchronous processing by enabling asynchronous processing Just add the @EnableAsync to simply set the class to write :

@Configuration
@EnableAsync
public class SpringAsyncConfig { ... }
The above annotation is sufficient, but you can also set some options you need:

annotation  – default, @EnableAsync  detectsSpring's Async annotations and EJB 3.1 javax.ejb.Asynchronous ; Other annotations customized with this option can also be detected.
mode  – indicatesthe type of advice to use-based on JDK proxy or AspectJ weaving.
proxyTargetClass  -indicates the type of proxy to use-CGLIB or JDK; This property value is valid only when mode is set to AdviceMode.PROXY .
order  – sets the order in which  AsyncAnnotationBeanPostProcessor  should apply; It isrun from the end by default toonly  consider all existing proxies  .
Asynchronous processing can also be enabled via XML configuration using the task namespace :

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

3.  The  @Async  Annotation

Let's look at the rules  first-@Async  has two limitations:

1. Apply only to public methods
2. Self-invocation self invocation – call the async method in the same class  – does not work

The reason for this is simple, because the method must be public to become a proxy, and self-calling does not work because it bypasses the proxy and calls the method directly .

There is no return type Method  Methods with void Return Type

A method with a return type of void works asynchronously with the following simple configuration:

@Async
public void asyncMethodWithVoidReturnType() {
    System.out.println("Execute method asynchronously. " + Thread.currentThread().getName());
}

Methods that have a return type  Methods with Return Type

@Async  can be applied to a method with return type: by putting the actual return value in the Future object.

@Async
public Future<String> asyncMethodWithReturnType() {
    System.out.println("Execute method asynchronously - " + Thread.currentThread().getName());
    try {
        Thread.sleep(5000);
        return new AsyncResult<String>("hello world !!!!");
    } catch (InterruptedException e) {
        //
    }
    return null;
}
Spring also  provides an AsyncResult class that implements Future ,  which is used to get the results of asynchronous method execution.

Now let's call the above method and use the Future object to get the result of the asynchronous processing .

public void testAsyncAnnotationForMethodsWithReturnType()
    throws InterruptedException, ExecutionException {
    System.out.println("Invoking an asynchronous method. "
      + Thread.currentThread().getName());
    Future<String> future = asyncAnnotationExample.asyncMethodWithReturnType();

    while (true) {
        if (future.isDone()) {
            System.out.println("Result from asynchronous process - " + future.get());
            break;
        }
        System.out.println("Continue doing something else. ");
        Thread.sleep(1000);
    }
}

4.  The Executor

Spring uses SimpleAsyncTaskExecutor  by default to execute real methods asynchronously. The default setting can be overridden in two levels-application level or private method level.

To override a method-level practitioners Override the Executor at the Method Level

You need to declare the necessary executors in your configuration class:


@Configuration
@EnableAsync
public class SpringAsyncConfig {
   
    @Bean(name = "threadPoolTaskExecutor")
    public Executor threadPoolTaskExecutor() {
        return new ThreadPoolTaskExecutor();
    }
}
After that, you must provide the executor name as an attribute value in @Async :

@Async("threadPoolTaskExecutor")
public void asyncMethodWithConfiguredExecutor() {
    System.out.println("Execute method with configured executor - "  + Thread.currentThread().getName());
}

To override the application level practitioners to  Override the Executor at the Application Level
In this case, the configuration class  must implement the AsyncConfigurer interface-which  means that it must implement the getAsyncExecutor () method. Here we will return the executor for the entire application-this is now the default executor for executing methods annotated with @Async.

@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {
   
    @Override
    public Executor getAsyncExecutor() {
        return new ThreadPoolTaskExecutor();
    }
   
}

5. Exception Handling

If the method's return type is Future, exception handling is easy-the Future.get () method throws an exception.

However, when the return type is void, the exception will not be delivered to the calling thread. Therefore, we need additional settings for exception handling.

We will  create a custom asynchronous exception handler by implementing the AsyncUncaughtExceptionHandler interface. The handleUncaughtException ()  method is  called when an uncaught asynchronous exception is caught :

public class CustomAsyncExceptionHandler  implements AsyncUncaughtExceptionHandler {

    @Override
    public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
        System.out.println("Exception message - " + throwable.getMessage());
        System.out.println("Method name - " + method.getName());
        for (Object param : obj) {
            System.out.println("Parameter value - " + param);
        }
    }
   
}
In the previous section, we  saw the AsyncConfigurer interface implemented by the configuration class  . As part of that, we also need to override the getAsyncUncaughtExceptionHandler () method, which returns our custom asynchronous exception handler  :

@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
    return new CustomAsyncExceptionHandler();
}

6.  Conclusion

In this tutorial, we looked at how to run asynchronous code in Spring. Not only did it work with very basic settings and annotations, we also looked at more advanced settings such as the executor we set, or the exception handling strategy.

No comments:

Post a Comment