Spring is a powerful framework, but it requires some skill to use efficiently. When I started working with Spring a while ago (actually Spring Boot to develop microservices) I encountered some challenges related to dependency injection and using the @Autowired annotation. In this blog I’ll explain the issues and possible solutions. Do note that since I do not have a long history with Spring, the provided solutions might not be the best ones.
Introduction @Autowired
In Spring 2.5 (2007), a new feature became available, namely the @Autowired annotation. What this annotation basically does is provide an instance of a class when you request it in for example an instance variable of another class. You can do things like:
@Autowired MyClass myClass;
This causes myClass to automagically be assigned an instance of MyClass if certain requirements are met.
How does it know which classes can provide instances? The Spring Framework does this by performing a scan of components when the application starts. In Spring Boot the @SpringBootApplication provides this functionality. You can use the @ComponentScan annotation to tweak this behavior if you need to. Read more here.
The classes of which instances are acquired, also have to be known to the Spring framework (to be picked up by the ComponentScan) so they require some Spring annotation such as @Component, @Repository, @Service, @Controller, @Configuration. Spring manages the life-cycle of instances of those classes. They are known in the Spring context and can be used for injection.
Order of execution
When a constructor of a class is called, the @Autowired instance variables do not contain their values yet. If you are dependent on them for the execution of specific logic, I suggest you use the @PostConstruct annotation. This annotation allows a specific method to be executed after construction of the instance and also after all the @Autowired instances have been injected.
Multiple classes which fit the @Autowired bill
If you create an instance of a class implementing an interface and there are multiple classes implementing that interface, you can use different techniques to let it determine the correct one. Read here.
You can indicate a @Primary candidate for @Autowired. This sets a default class to be wired. Some other alternatives are to use @Resource, @Qualifier or @Inject. Read more here. @Autowired is Spring specific. The others are not.
You can for example name a @Component like:
@Component("beanName1") public class MyClass1 implements InterfaceName { } @Component("beanName2") public class MyClass2 implements InterfaceName { }
And use it in an @Autowired like
@Autowired @Qualifier("beanName1") InterfaceName myImpl;
MyImpl will get an instance of MyClass1
When @Autowired doesn’t work
There are several reasons @Autowired might not work.
When a new instance is created not by Spring but by for example manually calling a constructor, the instance of the class will not be registered in the Spring context and thus not available for dependency injection. Also when you use @Autowired in the class of which you created a new instance, the Spring context will not be known to it and thus most likely this will also fail.
Another reason can be that the class you want to use @Autowired in, is not picked up by the ComponentScan. This can basically be because of two reasons.
- The package is outside the ComponentScan search path. Move the package to a scanned location or configure the ComponentScan to fix this.
- The class in which you want to use @Autowired does not have a Spring annotation. Add one of the following annotatons to the class: @Component, @Repository, @Service, @Controller, @Configuration. They have different behaviors so choose carefully! Read more here.
Instances created not by Spring
Autowired is cool! It makes certain things very easy. Instances created not by Spring are a challenge and stand between you and @Autowired. How do you deal with this?
Do not create your own instances; let Spring handle it
If you can do this (refactor), it is the easiest way to go. If you need to deal with instances created not by Spring, there are some workarounds available below, but most likely, they will have unexpected side-effects. It is easy to add Spring annotations, have the class be picked up by the ComponentScan and let instances be @Autowired when you need it. This avoids you having to create new instances regularly or having to forward them through a call stack.
Not like this
//Autowired annotations will not work inside MyClass. Other classes who want to use MyClass have to create their own instances or you have to forward this one. public class MyClass { } public class MyParentClass { MyClass myClass = new MyClass(); }
But like this
Below how you can refactor this in order to Springify it.
//@Component makes sure it is picked up by the ComponentScan (if it is in the right package). This allows @Autowired to work in other classes for instances of this class @Component public class MyClass { } //@Service makes sure the @Autowired annotation is processed @Service public class MyParentClass { //myClass is assigned an instance of MyClass @Autowired MyClass myClass; }
Manually force Autowired to be processed
If you want to manually create a new instance and force the @Autowired annotation used inside it to be processed, you can obtain the SpringApplicationContext (see here) and do the following (from here):
B bean = new B(); AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory(); factory.autowireBean( bean ); factory.initializeBean( bean, "bean" );
initializeBean processes the PostConstruct annotation. There is some discussion though if this does not break the inversion of control principle. Read for example here.
Manually add the bean to the Spring context
If you not only want the Autowired annotation to be processed inside the bean, but also make the new instance available to be autowired to other instances, it needs to be present in the SpringApplicationContext. You can obtain the SpringApplicationContext by implementing ApplicationContextAware (see here) and use that to register the bean. A nice example of such a ‘dynamic Spring bean’ can be found here and here. There are other flavors which provide pretty similar functionality. For example here.
Thank you so much you helped me solve a issue which nobody in my team was able to figure it out. We were creating the instance manually that is why the autowiring was not working. Thanks a lot.
Big thanks this really helped me!
Thanks for this; this helped me figure out the problem with my code.
After performed mentioned step still getting error
Field userRepo in com.helpmydesk.springboot.JpaConfig.ServiceClass required a bean of type ‘com.helpmydesk.springboot.JpaConfig.UserRepo’ that could not be found.
The injection point has the following annotations:
– @org.springframework.beans.factory.annotation.Autowired(required=true)
———————————————————————————————–this is my Jpa extends class————
@Component(“beanName1”)
public interface UserRepo extends JpaRepository {
}
—————————————–this is my service class———————————————————
@Service
public class ServiceClass implements InterfaceClass {
@Autowired
@Qualifier(“beanName1”)
private UserRepo userRepo;
@Override
public User addUser(User user) {
this.userRepo.save(user);
return user;
}
}
JpaRepository most likely has a @Repositorey annotation. Since UserRepo extends that class, it has no need for the @Component annotation. Take off the @Component and see if this helps. Once you do that, the @Qualifier annotation in Service class wont be needed too.
Swapnil, I am also getting the same error…. How you solved it… Pls help… Its Urgent
Thank you sooo much. This article helped me out of NPE hell. bravo.
Hi , is there any error in my code
@Component
public class SampleBean {
@Inject
private Bean1 anotherBean1;
@Inject
private Bean2 anotherBean2;
private String property;
public SampleBean(Bean1 anotherBean1, Bean2 anotherBean2) {
this.anotherBean1 = anotherBean1;
this.anotherBean2 = anotherBean2;
}
public void method1() {
// use all member variables
}
}
Great Article. very Helpful.
Nice article, indeed!! But I’ve got Spring Data use case, in which Spring framework would autowire interfaces building all the classes it needs behind the scenes (in simpler use case). Well I keep getting “NoSuchBeanDefinitionException: No qualifying bean of type….”, it’s two days now and I googled everywhere…
Any pointers?
TIA
These are some things you could check:
– Is the class you want to be autowired annotated with (one of) @Component, @Repository, @Service, @Controller, @Configuration?
– Is the package in which the class resides part of the ComponentScan path?
– Does the class you want to have autowired have a no argument public constructor?
Nice article!
You really covered all the important aspects of Autowiring.
Autowiring was one of the few things I struggled with during my early days with spring 🙂