springboot and @Async examples
Introduction
This post would demo springboot and @Async examples, include:
- springboot with @Async hello world example
- springboot @Async with specific thread pool example
- springboot @Async with return value example
Environments
- SpringBoot 1.5.12
- Java 1.8
The Pom.xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.12.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
What is the @Async annotation
The @Async annotation can be provided on a method so that invocation of that method will occur asynchronously. In other words, the caller will return immediately upon invocation and the actual execution of the method will occur in a task that has been submitted to a Spring TaskExecutor.
In short words, @Async let you do the threading more easily in springboot applications. You don’t need to create a thread to execute the task anymore.
1. springboot with @Async hello world example
1.1 Enable the async with @EnableAsync on @SpringBootApplication
You must enable the async on SpringBootApplication like this:
@SpringBootApplication
@EnableAsync // The most import part
public class MainApp {
public static void main(String[] args) {
SpringApplication.run(MainApp.class, args);
}
}
As the following code shows, the @EnableAsync is just a class annotation with some configuration for async tasks.
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AsyncConfigurationSelector.class})
public @interface EnableAsync {
...
1.2 Use the @Async in code
The @Async usage example code:
@Component
public class AsyncTester {
private static Log log = LogFactory.getLog(AsyncTester.class);
@Async
public void asyncHelloWorld() {
log.info("hi,springboot async,"
+Thread.currentThread().getName());
}
...
As the code shows, you just need to add the @Async annotation to a method,then everything is done.
1.3 Test the @Async code
and the test code is:
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestAsync {
@Autowired
private AsyncTester asyncTester;
@Test
public void testAsyncHello() {
asyncTester.asyncHello();
}
....
1.4 Run the Testcase
Run the springboot application ,and we get this result:
2018-04-29 20:50:22.970 INFO 33263 --- [ cTaskExecutor-1] java8.learn.async.AsyncTester : hi,springboot async hello,SimpleAsyncTaskExecutor-1
Here, we notice that the thread’s name is SimpleAsyncTaskExecutor, which is the default thread pool executor of the @Async task:
SimpleAsyncTaskExecutor This implementation does not reuse any threads, rather it starts up a new thread for each invocation. However, it does support a concurrency limit which will block any invocations that are over the limit until a slot has been freed up. If you are looking for true pooling, see the discussions of SimpleThreadPoolTaskExecutor and ThreadPoolTaskExecutor below.
By default when specifying @Async on a method, the executor that will be used is the one supplied to the ‘annotation-driven’ element as described above. However, the value attribute of the @Async annotation can be used when needing to indicate that an executor other than the default should be used when executing a given method.
2. springboot @Async with specific thread pool example
If we want the @Async task to run in a specified thread pool, we can define as follows:
@Configuration
public class ExecutorServiceConfig {
@Bean
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(1);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(5);
executor.setThreadNamePrefix("MyAsync-");
executor.initialize();
return executor;
}
}
Rerun the same testcase code, we get this:
2018-04-29 20:50:22.970 INFO 33263 --- [ MyAsync-1] java8.learn.async.AsyncTester : hi,springboot async hello,MyAsync-1
The thread name changed according to the Executor we defined.
we can also customize the name of the Executor like this:
@Configuration
public class ExecutorServiceConfig {
//define an ExecutorService with fixed thread pool,and with a name of customFixedThreadPool
@Bean("customFixedThreadPool")
public ExecutorService customFixedThreadPool() {
return Executors.newFixedThreadPool(2,new CustomizableThreadFactory("customFixedThreadPool"));
}
}
//Use custom Executor named customFixedThreadPool
@Async("customFixedThreadPool")
public void async1() {
log.info("hi,springboot async,"
+Thread.currentThread().getName());
}
And run the same testcase code ,we get this:
2018-04-29 21:04:06.772 INFO 33282 --- [ixedThreadPool1] java8.learn.async.AsyncTester : hi,springboot async,customFixedThreadPool1
As we can see, the name of the thread has changed to customFixedThreadPool1
3. springboot @Async with return value example
Sometimes, we want to execute a task with return value, we can use Future to achieve this:
@Async("customFixedThreadPool")
public Future<String> asyncWithResult() {
try {
Thread.sleep(2*1000);
log.info("hi,springboot async with return value,"
+Thread.currentThread().getName());
return new AsyncResult<String>("hi springboot async");
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
Explanation:
- This async methos has a return type **@Future
**, means that this method must do a task and return a String - This method sleep for a while and return a **AsyncResult
**, this is a holder of the future value.
The AsyncValue definition:
public class AsyncResult<V>
extends java.lang.Object
implements ListenableFuture<V>
...
And the testcase is:
@Test
public void testAsyncWithFuture() {
Future<String> result = asyncTester.asyncWithResult();
try {
assertTrue(result.get().equals("hi springboot async"));
} catch (Exception e) {
e.printStackTrace();
assertTrue(false);
}
}
In this testcase, we call the async method and make sure the returned value is hi springboot async
run the code, we get the green bar and the output:
2018-04-29 21:10:32.869 INFO 33291 --- [fixedThreadPool1] java8.learn.async.AsyncTester : hi,springboot async with return value,customFixedThreadPool1
It’s so easy, do you think so? You can find the complete code on github repo
You can find detail documents about the springboot and unit testing here: