The Springboot version is 2.6.13.
I have Class Data, it looks like this:
package com.example.asynctest;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
@lombok.Data
@Async
public class Data {
public class MyData{
int age;
String name = "";
}
private MyData myData = new MyData();
}
And when I try to get it autowired, the myData field is null.
package com.example.asynctest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@Async
class CmmandLine implements CommandLineRunner{
@Autowired
private Data data;
@Override
public void run(String... args) throws Exception {
log.info(data.toString());
}
}
The data field looks like this in IDEA:
debug picture
And when I remove the @Async annotation, the autowired data.myData is correct.I traced this by myself, and the bean was modified by postProcessAfterInitialization of AsyncAnnotationBeanPostProcessor.And I have added @EnableAsync on the entrypoint class.
So, why this happened? And how should I do to use @Async and @Autowired together?
The problem with your code is not that the
dataobject is not getting injected. In fact it does. To be absolutely sure you can change your code to have injection by constructor:If the
dataobject was not injected correctly, you would get an exceptionParameter 0 of constructor in industries.atende. Tester required a bean of type 'com.example.asynctest.Data' that could not be found.. Moreover, even (theoretically) if you didn't get this exception, thedata.toString()would yield aNullPointerException. Notice that neither of these exceptions occurs. So the code works (almost) correctly. You're looking for the error in the wrong place.The real problem is that your
toString()method inDataclass returnsnull. The object itself is not null,but it appears to be null in IDEA debug, because the Intellij Idea also uses methodtoString()to picture the object for you. And the IDEA getsnullfrom thetoString()method.So why the
toString()returns null? Because you made it@Async. Every@Asyncmethod should return values wrapped by a class capable of dealing with asynchronous responses. For example you should always returnCompletableFuture<String>, not justStringif the method is@Async. Why? Because the method is run on another thread and, without this wrapper, you have no way of blocking it to get result (in another words: You have no way to "wait" for the result).So my advice is to remove the
@Asyncannotation from the top level (type), and use it only on methods that you really need to be async. Because otherwise you have no way of fixing the issue. ThetoString()is inherited from theObjectclass, so it cannot returnCompletableFuture<String>- it has to returnString. So making the method async, you would always end up with null instead of real value.