Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring @Async ignored

Tags:

java

spring

I am having troubles invoking a method asynchronously in Spring, when the invoker is an embedded library receiving notifications from an external system. The code looks as below:

@Service
public class DefaultNotificationProcessor implements NotificationProcessor {

    private NotificationClient client;


    @Override
    public void process(Notification notification) {
        processAsync(notification);
    }

    @PostConstruct
    public void startClient() {
        client = new NotificationClient(this, clientPort);
        client.start(); 
    }

    @PreDestroy
    public void stopClient() {
        client.stop();
    }

    @Async
    private void processAsync(Notification notification) {
        // Heavy processing
    }
}

The NotificationClient internally has a thread in which it receives notifications from another system. It accepts a NotificationProcessor in its constructor which is basically the object that will do the actual processing of notifications.

In the above code, I have given the Spring bean as the processor and attempted to process the notification asynchronously by using @Async annotation. However, it appears the notification is processed in the same thread as the one used by NotificationClient. Effectively, @Async is ignored.

What am I missing here?

like image 522
Ariod Avatar asked Mar 21 '14 14:03

Ariod


People also ask

What will happen if you specify @async over a public method of a Spring bean?

Simply put, annotating a method of a bean with @Async will make it execute in a separate thread. In other words, the caller will not wait for the completion of the called method. One interesting aspect in Spring is that the event support in the framework also has support for async processing if necessary.

What does @async do Spring?

The @EnableAsync annotation switches on Spring's ability to run @Async methods in a background thread pool. This class also customizes the Executor by defining a new bean. Here, the method is named taskExecutor , since this is the specific method name for which Spring searches.

What is the use of @async in Spring boot?

Here @EnableAsync is used for enabling asynchronous processing with Java Spring Boot Configuration and switches Spring's ability to run @Async methods. The @Async Methods run in the background thread pool without interruption other parallel processes.

Does @async work on private methods?

Never use @Async on top of a private method. In runtime, it will not able to create a proxy and, therefore, not work.


1 Answers

@Async (as well as @Transactional and other similar annotations) will not work when the method is invoked via this (on when @Async is used for private methods*), as long as you do not use real AspectJ compiletime or runtime weaving.

*the private method thing is: when the method is private, then it must been invoked via this - so this is more the consequence then the cause

So change your code:

@Service
public class DefaultNotificationProcessor implements NotificationProcessor {


    @Resource
    private DefaultNotificationProcessor selfReference;


    @Override
    public void process(Notification notification) {
        selfReference.processAsync(notification);
    }


    //the method must not been private
    //the method must been invoked via a bean reference
    @Async
    void processAsync(Notification notification) {
        // Heavy processing
    }
}

See also the answers for: Does Spring @Transactional attribute work on a private method? -- this is the same problem

like image 145
Ralph Avatar answered Oct 13 '22 19:10

Ralph