I'm having trouble getting @Autowired to work in a class annotated by @Service, the autowired variable always is null. Let me explain:
@Service
public class Searcher extends Thread implements ISearcher {
@Autowired
protected ISessionProvider sessionProvider; <-- always null
...
public Searcher() {
sessionProvider.doSomeStuff();
}
sessionProvider here is always null.
The strange thing is that the same autowire in a @Controller does work:
@Controller
@RequestMapping("/search")
@Secured({ "ROLE_USER" })
public class SearchController extends BaseController {
@Autowired
protected ISessionProvider sessionProvider; <-- does work
@Autowired
protected ISearcher searcher;
The last line throws exception because the constructor of Searcher (implementing ISearcher) tries to access sessionProvider, which is null.
I am not sure what i might be doing wrong, it looks like spring doesn't autowire the ISessionProvider in Searcher.
It might be that spring first autowires the Searcher in SearchController, but it should first autowire SessionProvider in Searcher and next autowire Searcher in SearchController. Cause searcher cannot be autowired without a valid SessionProvider. Puzzles my brain ;-)
Can somebody offer a helping brain?
[edit]
If you want properly use @Autowired in your spring-boot application, you must do next steps: Add @SpringBootApplication to your main class. Add @Service or @Component annotation to class you want inject. Use one of two ways that you describe in question, to autowire.
You can use @Autowired annotation on setter methods to get rid of the <property> element in XML configuration file. When Spring finds an @Autowired annotation used with setter methods, it tries to perform byType autowiring on the method.
In Spring, you can use @Autowired annotation to auto-wire bean on the setter method, constructor , or a field . Moreover, it can autowire the property in a particular bean. We must first enable the annotation using below configuration in the configuration file.
Suppose I have a bean named HelloWorld which has a member attribute points to another bean User. With annotation @Autowired, as long as getBean is called in the runtime, the returned HelloWorld instance will automatically have user attribute injected with User instance.
Spring will first create the bean instance, then inject the beans. You're trying to access to the injected bean when the current bean is created, thus the bean will be null
. That's default behavior.
If you want/need to execute any logic after creating the bean, use @PostConstruct
decorated method, which is invoked after the bean has been created and all the dependencies injected. Here's a sample:
@Service
public class Searcher extends Thread implements ISearcher {
@Autowired
protected ISessionProvider sessionProvider;
public Searcher() {
//nothing should be here...
}
@PostConstruct
public void init() {
sessionProvider.doSomeStuff();
}
}
Spring can only do dependeny injection after the bean has been constructed. You are calling the method in the constructor and at that point the ISessionProvider
hasn't been injected yet and hence it is null
which in turn leads to a nice NullPointerException
.
You have 2 solutions
@PostConstruct
@Autowired field
.Solution 1: move that code to a method annotated with @PostConstruct
.
@Service
public class Searcher extends Thread implements ISearcher {
@Autowired
protected ISessionProvider sessionProvider;
...
public Searcher() {}
@PostConstruct
public void init() {
sessionProvider.doSomeStuff();
}
Solution 2: Use constructor based dependency injection.
@Service
public class Searcher extends Thread implements ISearcher {
protected final ISessionProvider sessionProvider;
@Autowired
public Searcher(ISessionProvider sessionProvider) {
this.sessionProvider=sessionProvider;
sessionProvider.doSomeStuff();
}
}
I didn't do test, but I think the problem is, in class Searcher
, you created a no-argument constructor, and there you used the "autowired" bean. I guess there you would get NPE. Since spring would instantiate your Searcher
using default constructor (by reflection) if you didn't specify one, that is, it will use the no-argument constructor you created, but at this moment, the "autowired" bean was not yet injected.
If you want to do something immediately after the bean was instantiated, you can wrap the logic code in a method, and annotate it with @PostConstruct
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With