Meaning of Autowiring
Autowiring means initializing objects contained in a class automatically. Suppose you have a class which contains reference of another class as a member field. Now in order to initialize the member field you create an object of member field type and assign it manually (when not using Autowiring).
Consider an example where you have a class Computer which has a field of class KeyBoard as shown below :
class Computer {
Keyboard keyBoard;
//call this method somewhere to initialize keyBoard field
void setKeyBoard(KeyBoard kb){
keyBoard = kb;
}
}
In above example, to initialize keyBoard
field of Computer class, you need to call setKeyBoard()
method with an instance of KeyBoard or assign an instance of KeyBoard directly tokeyBoard
field . What if you don’t need to do any of these and keyBoard
field is initialized automatically. This automatic initialization of fields is called Autowiring.
Autowiring only assigns an object to a class field, it does NOT create the object. In order for a field to be autowired, an object of matching type (or name) should exist in Spring context. When Spring container finds that a field is to be Autowired, it searches for the matching object and assigns the object to this field.
Autowiring can be done using XML configuration and annotation. This post is focused on Autowiring using annotations (@Autowired).
How to Autowire beans ?
Taking the above example, suppose you have two bean definitions in Spring configuration XML :
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:context=”http://www.springframework.org/schema/context”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd”>
<context:annotation-config/>
<bean class=”com.codippa.Computer”></bean>
<bean class=”com.codippa.KeyBoard”></bean>
</beans>
Now to Autowire keyBoard
field of Computer class, just put @Autowired
annotation using any of the three methods below:
Autowiring at Field Level : Directly put @Autowired
annotation over the field which you want to Autowire or initialize. Spring container will automatically find the suitable bean and will inject it into the @Autowired
field. Note that setter method of the field is optional when annotating the field with @Autowired.
class Computer {
@Autowired
Keyboard keyBoard;
//This method is not required
void setKeyBoard(KeyBoard kb){
keyBoard = kb;
}
}
Autowiring at method level : Annotate the setter method of the field which you want to Autowire.
class Computer {
Keyboard keyBoard;
@Autowired
void setKeyBoard(KeyBoard kb){
keyBoard = kb;
}
}
Autowiring at Constructor level : Annotate the constructor of the class which accepts the field to be Autowired as an argument.
class Computer {
Keyboard keyBoard;
@Autowired
public Computer(KeyBoard kb){
this.keyBoard = kb;
}
}
Enabling Autowiring Support
For Autowiring to take place, some configuration is required so that the Spring container knows what you want and enables its support for Autowiring. There are three ways to do enable Autowiring.
1. Add <context:annotation-config> element to Spring configuration
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:context=“http://www.springframework.org/schema/context”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd“>
<context:annotation-config/>
<bean class=”com.codippa.Computer”></bean>
<bean class=”com.codippa.KeyBoard”></bean>
</beans>
In your Spring configuration, add the items highlighted above. <context:annotation-config>
tag enables the support for some pre-defined annotations (such as @Autowired
, @PreDestroy
, @PostConstruct
etc.) in a Spring application. As a result, Spring starts reading @Autowired
annotation and takes appropriate actions. Besides adding this element you also need to add context schema declaration at the root of configuration file (highlighted above).
2. Include AutowiredAnnotationBeanPostProcessor
as a bean in Spring configuration
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd”>
<bean class=”org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor”/>
<bean class=”com.codippa.Computer”></bean>
<bean class=”com.codippa.KeyBoard”></bean>
</beans>
This class enables Spring’s support to autowire fields annotated with @Autowired
, @Inject
and @Value
annotations.
3. Add <context:component-scan> element to Spring configuration
Similar to method 1 above but instead of adding a <context:annotation-config>
element here we add a <context:component-scan>
element to Spring configuration file.
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:context=“http://www.springframework.org/schema/context”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd“>
<context:component-scan base-package=”com.codippa”/>
<bean class=”com.codippa.Computer”></bean>
<bean class=”com.codippa.KeyBoard”></bean>
</beans>
<context:component-scan>
also enables the support for annotations. It instructs the Spring container to look for classes annotated with @Service
,@Repository
, @Component
etc., annotations and register them as beans in its context. In simple words, it instantiates the beans annotated with above annotations.This tag also adds-on the effect of <context:annotation-config>
tag, that is, it also adds support for annotations that are supported by <context:annotation-config>
element.
As with <context:annotation-config>
element, you also need to add context schema declaration at the root of configuration file (highlighted above) when using this element.
Resolving Conflicts in Autowiring
By default @Autowired
annotations assigns beans byType which means it matches the class types of beans and assigns them to references. It may happen at times that there are more than one bean which may be autowired to a field. Consider the following bean declarations :
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:context=”http://www.springframework.org/schema/context”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd”>
<context:annotation-config/>
<bean class=”com.codippa.Computer”></bean>
<bean id=”spanishKb” class=”com.codippa.KeyBoard”></bean>
<bean id=”englishKb” class=”com.codippa.KeyBoard”></bean>
</beans>
In above example, there are two beans which are of type KeyBoard which creates obvious confusion as to which bean to autowire. In such situations, Spring throws an error of the form :
org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.codippa.KeyBoard com.codippa.Computer.bean; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.codippa.KeyBoard] is defined: expected single matching bean but found 2: spanishKb,englishKb
To resolve such situations, you need to tell Spring about which bean should be autowired when an ambiguity arises. This is done by using @Qualifier annotation alongwith @Autowired
. Id of the bean used to declare it in configuration file is provided with @Qualifier annotation. To initialize keyBoard
field of our earlier example with Spanish keyboard, autowire it as below :
class Computer {
@Autowired
@Qualifier("spanishKb")
Keyboard keyBoard;
//This method may be removed when Autowired is placed above field name
void setKeyBoard(KeyBoard kb){
keyBoard = kb;
}
}
Let’s tweak in:
- <context:component-scan> and <context:annotation-config> also register a
AutowiredAnnotationBeanPostProcessor
behind the scenes. - Autowiring only works when the parent class (whose fields are being Autowired) is also created by Spring either by XML declaration or using other class level annotations (such as
@Component
,@Repository
) and not usingnew
operator. @Autowiring
can be applied over fields, methods and constructors. It can not be applied on a class.- An instance of a class type being Autowired should exist in Spring context (that is an object of matching type) otherwise following exception will be thrown :
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.codippa.KeyBoard] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
If you want that Spring should not throw an error if it cannot find a bean to autowire, then provide
required
option with@Autowired
annotation set to false as @Autowired(required=false). - If the field being autowired is an interface type then its implementor class instance is autowired to it.
- The terms Autowired and dependency injection are used interchangeably.
@Autowired
will also autowire a field which is declared private.
Have any feedback, queries, complaints. Kindly use the space below.