1. Introduction:
In the last blog I have explained the
Dependency Injection. DI helps in injecting the dependencies using either the
<property> or <constructor-arg> elements .And hence whenever there
is a new bean defined one needs to go and change the spring configuration file
(servlet xml). Just to avoid this, spring offers AutoWiring. AutoWiring helps
in reducing configuration overhead by not using the property and constructor
arg elements. How?
Let’s first understand the AutoWiring.
Bookish
Definition:
The Spring container is able to autowire
relationships between collaborating beans. This means that it is possible to
automatically let Spring resolve collaborators (other beans) for your bean by
inspecting the contents of the BeanFactory.
Simple Definition:
Autowiring let spring container decide which bean to inject into a controller.
It helps in avoiding the explicit wiring of bean properties.
It helps in avoiding the explicit wiring of bean properties.
Example: To display the
results from Database, A controller needs a DataSource bean.
Now in Dependency
Injection what we do is, we inject the datasoure bean to the controller by
setter or constructor
dependency injection in the xml configuration file. Autowiring lets Spring to
decide how to wire dependency and hence we do not need to explicitly wire bean
properties.
2. Types of AutoWiring:
- byName: Based on the name of a property.
- byType: Based on a type of class on a setter.
- constructors: Based on a constructor argument's class types.
- autodetect : Chooses constructor or byType through introspection of the bean class.
Code examples:
Class
1:
package
com.sk.autowiring;
public class Player {
private Game game;
public
void setGame(Game game) {
this.game = game;
}
//Some logic...
}
Class2:
package
com.sk.autowiring;
public class Game {
private String gameName;
// Some logic ..
}
Class3:
package
com.sk.autowiring;
public class Batsman {
private String batsmanType;
//...
}
2.1 ByName:
Autowiring
by property name. This option will inspect the container and look for a bean
named exactly the same as the property which needs to be autowired. This uses
the setter method.
In Dependency Injection, we have done
explicit wiring for beans. For ex.
<bean id="player"
class="com.sk.autowiring.Player" >
<property
name="game" ref="game" />
</bean>
<bean id="game"
class="com.sk.autowiring.Game" >
<property
name="gameName" value="cricket" />
</bean>
But using autowiring , there is no
need to declare the property tag . As long as the “game” bean has same name as
the property of “player” bean, which is “game”, spring will wire it
automatically.
<bean id="player"
class="com.sk.autowiring.Player" autowire="byName"/>
<bean id="game"
class="com.sk.autowiring.Game" >
<property
name="gameName" value="cricket" />
</bean>
2.2 ByType :
When attempting to autowire a property
by type, Spring will look for beans whose type is assignable to the property’s
type.
<bean
id="player" class="com.sk.autowiring.Player" >
<property
name="batsman" ref="batsman" />
</bean>
<bean
id="batsman" class="com.sk.autowiring.Batsman" >
<property
name="batsmanType" value="opening" />
</bean>
With autowire by type, properties need
not to be set. Spring will find the same data type and wire it automatically.
<bean
id="player" class="com.sk.autowiring.Player"
autowire="byType" />
<bean
id="batsman" class="com.sk.autowiring.Batsman" >
<property
name="batsmanType" value="opening" />
</bean>
There can be a lot of beans which are
of the same type and hence in that case spring will throw exception. There are
2 options using which We can avoid
a)
primary attribute : Bean element’s primary
attribute helps in identifying a primary
candidate for autowiring. If its value is true, then that particular bean will
be chosen in favor of others.
<bean
id="batsman" class="com.sk.autowiring.Batsman” primary=”false”/>
b)
autowire-candidate attribute : Bean elements’s
is used to identify a preferred autowire candidate among al of them. This
attribute actually eliminates beans from considerations of autowiring when the
value is set to false.
<bean
id="batsman" class="com.sk.autowiring.Batsman” autowire-candidate=”false”/>
2.3 constructor:
Based on a constructor argument's
class types .If the bean is configured using constructor injection, we do not
need to define <constructor-arg> elements and let Spring automatically choose constructor elements
from beans in the spring context.
When bean property is
wired explicitly:
<bean id="player"
class="com.sk.autowiring.Player" >
<constructor-arg>
<ref bean="batsman" />
</constructor-arg>
</bean>
<bean id="batsman"
class="com.sk.autowiring.Batsman" >
<property name="batsmanType"
value="openning" />
</bean>
With autowire by type,
constructor arg elements need not to be set.Spring will find the same data type
and wire it automatically.
<bean id="player"
class="com.sk.autowiring.Player" autowire="constructor"
/>
<bean id="batsman" class="com.sk.autowiring.Batsman"
>
<property name="batsmanType"
value="openning" />
</bean>
2.4 autodetect:
In Spring, "Autowiring by
AutoDetect", means chooses "autowire by constructor". If default
constructor (argument with any data type), otherwise uses "autowire by type".
<bean
id="player" class="com.sk.autowiring.player"
autowire="autodetect" />
<bean id="game"
class="com.sk.autowiring.Game" />
3. Autowiring of beans with @Autowired annotations
Autowiring of beans with @Autowired
annotations feature started from Spring 2.5 version. @Autowired annotation can be used to auto wire bean on the setter
method, constructor or a field. Spring checks the property on which this is
being defined and then it will try to perform ‘byType’ autowiring on that
property. You don’t need a setter method to use it. Since Annotation wiring is not turned on by
default and hence we need to enable it.
3.1 Enable autowiring:
<context:annotation-config />
In the Spring’s context configuration namespace (servlet.xml)
<beans xmlns="http://www.springframework.org/schema/beans"
.....................
<context:annotation-config />
</beans>
3.2 @Autowired property Examples:
1. @Autowired setter method
package
com.sk.autowiring;
import
org.springframework.beans.factory.annotation.Autowired;
public
class Player {
private Game game;
//Autowiring
setter
@Autowired
public void setGame(Game game) {
this.game = game;
}
}
2. @Autowired construtor
package
com.sk.autowiring;
import org.springframework.beans.factory.annotation.Autowired;
public
class Player {
private
Game game;
// Autowiring
Constructor
@Autowired
public Player(Game game) {
this.game = game;
}
}
3. @Autowired field
package
com.sk.autowiring;
import
org.springframework.beans.factory.annotation.Autowired;
public
class Player {
//Autowiring field
@Autowired
private Game game;
}
4. @Qualifier
There can be a case when more than one
bean is defined of the same name or type. In that event, there is no way for
@Autowired to choose which one should really be selected. To help @Autowired
figure out which bean you want, you can accompany it with Spring's @Qualifier
annotation. The @Qualifier annotation used to control which bean should be autowire
on a field.
For example,
bean configuration file with two similar game beans.
<beans
xmlns="http://www.springframework.org/schema/beans"
.............
<context:annotation-config />
<bean id="Player"
class="com.sk.autowiring.Player">
<property
name="name" value="Sushant" />
</bean>
<bean id="Game1"
class="com.sk.autowiring.Game">
<property
name="gameName" value="Cricket" />
</bean>
<bean
id="Game2" class="com.sk.autowiring.Game">
<property
name="gameName" value="Football" />
</bean>
</beans>
Now how will
Spring decide which bean it should wire? To fix it, you can use @Qualifier to
auto wire a particular bean, for example,
package com.sk.autowiring;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.beans.factory.annotation.Qualifier;
public
class Player {
@Autowired
@Qualifier("Game1")
private Game game;
}
In this
case, Game1 is autowired.This is how
the Autowiring works.
5. Pros\Cons of Autowiring
As there are pros and
cons of each approach, with this also there are few. Defining everything explicitly
in the xml obviously is easier to understand by everybody and even to new
people who joins the team at a later stage. But then maintaining an xml file
for each and everything will be a big overhead. Annotations are easier to use
and maintain.
Now even Spring
autowiring also increases the complexity for the servlet xml file and hence
better to use the @Autowired annotations.
So which ever approach will be used all are at
last Dependency Injection only.