0

I am testing out @Async in a spring boot 2, and i followed some online tutorial

My Config Class:

@Configuration
@EnableAsync
public class AsyncConfig {

    @Bean
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(500);
        executor.setThreadNamePrefix("Async Process-");
        executor.initialize();
        return executor;
    }
}

Snippet of My Controller:

@GetMapping("/test/async")
public void testAsync() {
    System.err.println("Thread in controller: " + Thread.currentThread().getName());
    TestAsyncClazz clazz = new TestAsyncClazz();
    clazz.testAsyncMethod();
}

My TestAsyncClass:

public class TestAsyncClazz {

    @Async
    public void testAsyncMethod(){
        System.err.println("Running async: "+ Thread.currentThread().getName());
    }
}

When i check the print line, it shows that both of my method running on the same thread, and it didn't use the threadNamePrefix Async Process-:

Thread in controller: http-nio-8080-exec-2
Running async: http-nio-8080-exec-2

What i did wrong? Did i misunderstand something?

1 Answer 1

5

This happens because you are calling the async method on a class that you instantiate yourself using new:

TestAsyncClazz clazz = new TestAsyncClazz();
clazz.testAsyncMethod();

If you do it this way, Spring does not have a chance to decorate the instance with the necessary proxy class that provides the actual functionality to run the method asynchronously.

This will only work the way you expect on Spring beans - in other words, do not instantiate TestAsyncClazz yourself; define a Spring bean instance of the class, autowire that bean into your controller and then call the method on the bean.

Example:

@Configuration
@EnableAsync
public class AsyncConfig {

    @Bean
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(500);
        executor.setThreadNamePrefix("Async Process-");
        executor.initialize();
        return executor;
    }

    // Define a Spring bean of type TestAsyncClazz
    @Bean
    public TestAsyncClazz testAsyncClazz() {
        return new TestAsyncClazz();
    }
}

@Controller
public class MyController {

    // Inject the bean here
    @Autowired 
    private TestAsyncClazz testAsyncClass;

    @GetMapping("/test/async")
    public void testAsync() {
        System.err.println("Thread in controller: " +
                Thread.currentThread().getName());

        // Use the bean instead of instantiating the class yourself
        testAsyncClass.testAsyncMethod();
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

so other than @Bean, i can actually autowired @Service, or @Repository classes too right, and the @Async will works?
Yes, @Service and @Repository classes are also Spring beans.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.