SoFunction
Updated on 2025-03-08

@Async annotation method to execute asynchronous tasks in Spring

introduction

In business processing, some businesses use asynchronous methods more reasonable. For example, in a certain business logic, some data is stored in the redis cache. The cache is just an auxiliary function. Success or failure will not have a fundamental impact on the main business. This process can be carried out through an asynchronous method.

In Spring, the method can be called asynchronously by setting the @Async annotation on the method. That is to say, the method will return immediately upon invocation, and the actual execution of this method is handed over to Spring's TaskExecutor to complete.

Code Example

The project is a normal Spring project, Spring configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="/schema/beans"
  xmlns:xsi="http:///2001/XMLSchema-instance"
  xmlns:context="/schema/context"
  xmlns:task="/schema/task"
  xsi:schemaLocation="/schema/beans
  /schema/beans/spring-beans-4.
  /schema/context
  /schema/context/
  /schema/task
  /schema/task/">

 <!-- Packet Scan -->
 <context:component-scan base-package=""/>

 <!-- Thread pool for performing asynchronous tasksTaskExecutor -->
 <task:executor  pool-size="5" />
 <task:annotation-driven executor="myexecutor"/>

</beans>

Two Service classes:

package ;
import org.;
import org.;
import ;
import ;

import ;
import ;

/**
  * Service
  */
@Service
public class BusinessService {

 private static final Logger log = ();

 @Autowired
 private CacheService cacheService;


 public void doBusiness() {
  ("start to deal with our business");
  ();
  ("comlete service operation");
 }

 /**
   * Get the return value of the asynchronous method execution
   */
 public void doBusinessWithAsyncReturn() throws ExecutionException, InterruptedException {
  ("start to deal with our business");
  Future<String> future = ();
  (()); //() method will block  ("comlete service operation");
 }
}
package ;

import org.;
import org.;
import ;
import ;
import ;

import ;
import ;

/**
  * Cache service
  */
@Service
public class CacheService {

 private static final Logger log = ();


 @Async(value = "myexecutor") //Specify the TaskExecutor to execute the task public void cacheData() {
  try {
   (3L);
  } catch (InterruptedException e) {
   ();
  }
  ("success store the result to cache");
 }


 @Async
 public Future<String> cacheDataWithReturn() {
  try {
   (3L);
  } catch (InterruptedException e) {
   ();
  }
  ("success store the result to cache");
  //The returned result needs to be wrapped by AsyncResult.  return new AsyncResult<>("Async operation success");
 }
}

Test class:

package ;

import ;
import ;
import ;
import ;
import ;
import .junit4.SpringJUnit4ClassRunner;

import ;

@RunWith()
@ContextConfiguration(locations = {"classpath:"})
public class MainTest {


 @Autowired
 private BusinessService businessService;


 @Test
 public void test() throws InterruptedException {
  ();
  //Don't let the main thread end too early, otherwise the console will not see the output content in the asynchronous method  (5L);  
 }

 @Test
 public void testAsyncReturn() throws Exception {
  ();
  (5L);
 }

}

The result of executing the test() method:

22:20:33,207  INFO main :260 - Loaded default TestExecutionListener class names from location [META-INF/]: [, , , , , ]
22:20:33,226  INFO main :209 - Could not instantiate TestExecutionListener []. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [javax/servlet/ServletContext]
22:20:33,227  INFO main :187 - Using TestExecutionListeners: [@100fc185, @643b1d11, @2ef5e5e3, @36d4b5c, @6d00a15d]22:20:33,324  INFO main :317 - Loading XML bean definitions from class path resource []
22:20:33,585  INFO main :583 - Refreshing @4f7d0008: startup date [Wed May 30 22:20:33 CST 2018]; root of context hierarchy
22:20:33,763  INFO main :165 - Initializing ExecutorService
22:20:33,766  INFO main $BeanPostProcessorChecker:325 - Bean 'myexecutor' of type [] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
22:20:33,767  INFO main $BeanPostProcessorChecker:325 - Bean 'myexecutor' of type [] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
22:20:34,107 ERROR main :24 - start to deal with our business
22:20:34,113 ERROR main :26 - comlete service operation
22:20:37,166 ERROR myexecutor-1 :28 - success store the result to cache
22:20:39,117  INFO Thread-0 :984 - Closing @4f7d0008: startup date [Wed May 30 22:20:33 CST 2018]; root of context hierarchy
22:20:39,118  INFO Thread-0 :203 - Shutting down ExecutorService

The result of executing the testAsyncReturn() method:

21:38:16,908  INFO main :260 - Loaded default TestExecutionListener class names from location [META-INF/]: [, , , , , ]
21:38:16,926  INFO main :209 - Could not instantiate TestExecutionListener []. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [javax/servlet/ServletContext]
21:38:16,927  INFO main :187 - Using TestExecutionListeners: [@100fc185, @643b1d11, @2ef5e5e3, @36d4b5c, @6d00a15d]21:38:17,025  INFO main :317 - Loading XML bean definitions from class path resource []
21:38:17,263  INFO main :583 - Refreshing @4f7d0008: startup date [Wed May 30 21:38:17 CST 2018]; root of context hierarchy
21:38:17,405  INFO main :165 - Initializing ExecutorService
21:38:17,407  INFO main $BeanPostProcessorChecker:325 - Bean 'myexecutor' of type [] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
21:38:17,407  INFO main $BeanPostProcessorChecker:325 - Bean 'myexecutor' of type [] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
21:38:17,692 ERROR main :35 - start to deal with our business
21:38:20,833 ERROR myexecutor-1 :39 - success store the result to cache
21:38:20,834 ERROR main :37 - Async operation success
21:38:20,835 ERROR main :38 - comlete service operation
21:38:25,838  INFO Thread-0 :984 - Closing @4f7d0008: startup date [Wed May 30 21:38:17 CST 2018]; root of context hierarchy
21:38:25,839  INFO Thread-0 :203 - Shutting down ExecutorService

@Async's usage points

  1. Return value: Do not return value directly void; use AsyncResult or CompletableFuture to return value
  2. Customize the executor and specify for example: @Async("otherExecutor")
  3. @Async must be called between different classes: Class A—> Class B.C method() (@Async annotation is in Class B/Method). If it is called in the same class, it will be executed synchronously, for example: Class A.B()—> Class A.@Async C().
  4. @Async can also be added to the class, indicating that all methods of this class are executed asynchronously, and the annotations on the method will override the annotations on the class. But it is not usually used like this!

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.