Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@Autowired in @Service?

Tags:

java

spring

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]

  • component-scan includes my services, controllers and everything, just checked.
  • the I before interfaces is indeed not very nice (old habits)
  • not sure if this is a "duplicate" question, mainly because i'm not doing anything with "new", i let do spring do all the hard work, but i'll take a better peek.
like image 639
TinusSky Avatar asked May 07 '14 14:05

TinusSky


People also ask

Can we Autowired a service?

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.

Where @autowired can be used?

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.

Can we Autowire service class in spring?

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.

How does @autowired works internally?

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.


3 Answers

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();
    }
}
like image 147
Luiggi Mendoza Avatar answered Oct 01 '22 20:10

Luiggi Mendoza


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

  1. Move the code from the constructor to a method annotated with @PostConstruct
  2. Change the default no-arg constructor to take an argument and use that to do dependeny injection instead of the @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();
    }
}
like image 33
M. Deinum Avatar answered Oct 01 '22 20:10

M. Deinum


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.

like image 44
Kent Avatar answered Oct 01 '22 21:10

Kent