What is autowiring?
The Spring
container can autowire relationships between collaborating
beans without using <constructor-arg> and <property> elements which
helps cut down on the amount of XML configuration you write for a big Spring
based application.
There are TWO ways
to provide autowiring to your beans
1)
Through XML based configuration file (applicationContext.xml)
2)
With Annotations in beans directly.(Spring 2.5 and above)
Lets see how we
can use autowiring through xml configuration file.
Before that lets find out what are different
type of autowiring is possible in Spring.
|
Mode
|
Description
|
|
No
|
This is default setting which
means no autowiring and you should use explicit bean reference for
wiring. You have nothing to do special for this wiring.
|
|
Autowiring by property name.
Spring container looks at the properties of the beans on which autowire attribute is set to byName in the XML configuration file. It
then tries to match and wire its properties with the beans defined by the
same names in the configuration file.
|
|
|
Autowiring by property datatype.
Spring container looks at the properties of the beans on which autowire attribute is set to byType in the XML configuration file. It
then tries to match and wire a property if its typematches with exactly one
of the beans name in configuration file. If more than one such beans exists,
a fatal exception is thrown.
|
|
|
Similar to byType, but type
applies to constructor arguments. If there is not exactly one bean of the
constructor argument type in the container, a fatal error is raised.
|
|
|
autodetect
|
Spring first tries to wire using
autowire by constructor,
if it does not work, Spring tries to autowire by byType.
|
You should
consider the limitations and disadvantages of autowiring before using them.
|
Limitations
|
Description
|
|
Overriding possibility
|
You can still specify
dependencies using <constructor-arg> and <property> settings
which will always override autowiring.
|
|
Primitive data types
|
You cannot autowire so-called
simple properties such as primitives, Strings, and Classes.
|
|
Confusing nature
|
Autowiring is less exact than
explicit wiring, so if possible prefer using explicit wiring.
|
Lets discuss those 5 types of auto wiring in detail with
examples.
1) Default “No”
This is the default mode, you need to wire
your bean via ‘ref’ attribute.
<bean id="customer" class="com.common.Customer">
<property name="person" ref="person" /> </bean>
<bean id="person" class="com.common.Person" />
2) Auto-Wiring ‘byName’
Auto-wire a bean by property name. If the name of
a bean is same as the name of other bean property, auto wire it. For example,
if a “customer” bean exposes an “address” property, Spring will find the
“address” bean in current container and wire it automatically. And if no
matching found, just do nothing.
<bean id="customer" class="com.common.Customer" autowire="byName" /> <bean id="address" class="com.common.Address" > <property name="fulladdress" value="Vasant Vihar, Mumbai" /> </bean>
//Customer bean package com.common;
public class Customer { private Address address; //... }
//Address bean package com.common;
public class Address{ private String fulladdress; //... }
Normally, you wire the bean explicitly (without
autowiring), via ref attribute like this :
<bean id="customer" class="com.common.Customer" > <property name="address" ref="address" /> </bean>
<bean id="address" class="com.common.Address" > <property name="fulladdress" value="Vasant Vihar, Mumbai" /> </bean>
With autowire by name enabled, you do not
need to declare the property tag anymore. As long as the “address” bean is same
name as the property of “customer” bean, which is “address”, Spring will wire
it automatically.
<bean id="customer" class="com.common.Customer" autowire="byName" /> <bean id="address" class="com.common.Address" > <property name="fulladdress" value="Vasant Vihar, Mumbai" /> </bean>
Output
Customer [address=Address [fulladdress=Vasant Vihar, Mumbai]]
See another example, this time, the wiring
will failed, caused the bean “addressABC” is not match the property name of
bean “customer”.
<bean id="customer" class="com.common.Customer" autowire="byName" /> <bean id="addressABC" class="com.common.Address" > <property name="fulladdress" value="Vasant Vihar, Mumbai" /> </bean>
Output
Customer [address=null]
3) Auto-Wiring ‘byType’
Auto-wire
a bean by data type. If data type of a bean is
compatible with the data type of other bean property, auto wire it.
For example, a “person” bean exposes a property with data
type of “ability” class, Spring will find the bean with same data type of class
“ability” and wire it automatically. And if no matching found, just do nothing.
package com.common; public class Person { private Ability ability; //... }
package com.common; public class Ability{
private String skill; //... }
Normally, you wire the bean explicitly: (without
autowiring), via ref attribute like this :
<bean id="person" class="com.common.Person"> <property name="ability" ref="invisible" /> </bean> <bean id="invisible" class="com.common.Ability" > <property name="skill" value="Invisible" /> </bean>
Output
Person [ability=Ability [skill=Invisible]]
With autowire by type enabled, you can
leave the ability property unset. Spring will find the same data type and wire
it automatcailly.
<bean id="person" class="com.common.Person" autowire="byType" /> <bean id="invisible" class="com.common.Ability" > <property name="skill" value="Invisible" /> </bean>
Output
Person [ability=Ability [skill=Invisible]]
Wait, what if you have two beans with same
data type of class “ability”?
<bean id="person" class="com.common.Person" autowire="byType" /> <bean id="steal" class="com.common.Ability" > <property name="skill" value="Steal" /> </bean> <bean id="invisible" class="com.common.Ability" > <property name="skill" value="Invisible" /> </bean>
Output
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException:
...
No unique bean of type [com.common.Ability] is defined:
expected single matching bean but found 2: [steal, invisible]; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No unique bean of type [com.common.Ability] is defined:
expected single matching bean but found 2: [steal, invisible]
In this case, you will hits the
UnsatisfiedDependencyException error message.
4) Auto-Wiring ‘constructor’
Auto-wire a bean by property data type in constructor
argument. It means, if data type of a bean is same as the data type of other
bean constructor argument, auto wire it.
<bean id="developer" class="com.common.Developer" autowire="constructor" /> <bean id="language" class="com.common.Language" > <property name="name" value="Java" /> </bean>
package com.common; public class Developer { private Language language; //autowire by constructor
public Developer(Language language) { this.language = language; } //... }
package com.common;
public class Language { private String name; //... }
Normally, you wire the bean via constructor like this (without autowiring).
Normally, you wire the bean via constructor
like this :
<bean id="developer" class="com.common.Developer"> <constructor-arg> <ref bean="language" /> </constructor-arg> </bean> <bean id="language" class="com.common.Language" > <property name="name" value="Java" /> </bean>
With autowire by constructor enabled, you
can leave the constructor property unset. Spring will find the compatible data
type and wire it automatically.
<bean id="developer" class="com.common.Developer" autowire="constructor" /> <bean id="language" class="com.common.Language" > <property name="name" value="Java" /> </bean>
5) Auto-Wiring ‘autodetect’
If
a default constructor is found, uses “constructor”; Otherwise, uses “byType”
please refer above example for more reference how constructor or byType
autowiring is used.
Conclusion
In my view, Spring ‘auto-wiring’ make
development faster with great costs – it added complexity for the entire bean
configuration file, and you don’t even know which bean will auto wired in which
bean.
In practice, I rather wire it manually, it is
always clean and work perfectly, or better uses @Autowired annotation,
which is more flexible and recommended.
Now let’s see some examples and details about
Autowiring through annotations.
In Spring, you can use @Autowired annotation to auto wire bean on the
setter method, constructor or a field. Moreover, it can autowired property in a
particular bean.
The @Autowired annotation is auto wire the bean by matching data type.
The @Autowired annotation is auto wire the bean by matching data type.
Before you start using
annotation or @autowired you need to register AutowiredAnnotationBeanPostProcessor and you can do it
in two ways.
1. Include <context:annotation-config
/>
Add Spring context and
<context:annotation-config /> in bean configuration file.
e.g. <beans //... xmlns:context=http://www.springframework.org/schema/context //... http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> //... <context:annotation-config /> //... </beans>
2. Include
AutowiredAnnotationBeanPostProcessor
Include ‘AutowiredAnnotationBeanPostProcessor’
directly in bean configuration file.
e.g. <beans //... xmlns:context=http://www.springframework.org/schema/context //... http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> //... <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
//... </beans>
@Autowired Examples
Now, you can autowired bean via @Autowired,
and it can be applied on setter method, constructor or a field.
1. @Autowired setter
method
package com.common; import org.springframework.beans.factory.annotation.Autowired; public class Customer { private Person person; private int type; private String action; //getter and setter method
@Autowired public void setPerson(Person person) { this.person = person; } }
2. @Autowired construtor
package com.common; import org.springframework.beans.factory.annotation.Autowired; public class Customer { private Person person; private int type; private String action;
//getter and setter methods @Autowired public Customer(Person person) { this.person = person; } }
3. @Autowired field
package com.common; import org.springframework.beans.factory.annotation.Autowired; public class Customer{
@Autowired private Person person; private int type; private String action;
//getter and setter methods }
The above example will autowired ‘PersonBean’
into Customer’s person property.
package com.common; import org.springframework.context.ApplicationContext import org.springframework.context.support.ClassPathXmlApplicationContext; public class App {
public static void main( String[] args ){
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"SpringBeans.xml"}); Customer cust = (Customer)context.getBean("CustomerBean"); System.out.println(cust); } }
Hope this small article help to understand the autowiring concepts in Spring. Please leave your comment/suggestion in comments I would appreciate and do any changes if required.