Spring framework provides an option to autowire the beans. In that case you don't need to explicitly wire the bean properties (using ref attribute) but Spring will do it automatically by using the "autowire" attribute.
In Spring you can autowire dependencies using XML configuration or use the annotations to autowire the dependencies. This post talks about autowiring in Spring using XML configuration.
Autowiring modes in Spring
Spring provides four kind of autowiring modes (updated as per Spring 4.x where autodetect option has been removed).
no- The traditional Spring default. No automagical wiring. Bean references must be defined in the XML file via the <ref/> element (or "ref" attribute). autowire=”default” is same as autowire=”no”
byName- Autowiring by name means properties of the autowired bean will be wired by searching for bean with same name/id in the configuration file. If such a bean is found it is injected, properties for which no matching bean is found will remain unwired which may later result in error.
byType- Autowiring by type means properties of the autowired bean will be wired by searching for bean whose type is compatible with the property's type. If such a bean is found it is injected, properties for which no matching bean is found will remain unwired which may later result in error.
constructor- In this case wiring will be done using the constructor of the autowired bean by looking for the bean whose type is compatible with the constructor argument.
- autodetect- In case of autodetect auto wiring using constructor will be tried first, if default constructor only is there and autowiring using constructor can't be done then autowiring byType is used. Note that this option was available till Spring 3.x (deprecated) or older versions. In Spring 4.x it is removed and this option is not available anymore. In this post autodetect example is not there.
Autowiring in Spring - XML configuration
First thing to note here is that by default Spring doesn't autowire and you have to provide explicit wiring using ref attribute for the properties or for constructor-args which are to be dependency injected.
- Refer Setter-based dependency injection in Spring to see an example of setter based dependency injection. and
- Refer Constructor-based dependency injection in Spring to see an example of constructor based dependency injection.
Let's see examples of autowiring using XML configuration in Spring with all the autowiring modes as stated above.
Autowiring in Spring using byName
When you are autowiring by name the auto wired bean will look for the bean with the same name/id in the configuration file.
Let's see it with an example-
- Refer Spring example program using XML configuration to see how to set up classes for spring example using xml config.
Here we have a class PayServiceImpl which has a field payment of type IPayment which we have to autowire.
interface IPayService
public interface IPayService { void performPayment(); }
PayServiceImpl class
public class PayServiceImpl implements IPayService { private IPayment payment; private int amount; public void performPayment() { // calling payment class executePayment method payment.executePayment(amount); } public IPayment getPayment() { return payment; } public void setPayment(IPayment payment) { this.payment = payment; } public int getAmount() { return amount; } public void setAmount(int amount) { this.amount = amount; } }
interface IPayment
public interface IPayment { void executePayment(int amount); }
CashPayment class
public class CashPayment implements IPayment{ public void executePayment(int amount) { System.out.println("Perform Cash Payment for amount ... " + amount); } }
Configuration file
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <!-- defining CashPayment bean --> <bean id="payment" class="org.netjs.springexp.prog.CashPayment" /> <!-- Defining PayServiceImpl bean and injecting payment bean --> <bean id="payServiceBean" class="org.netjs.springexp.prog.PayServiceImpl" autowire="byName"> <property name="amount" value="20" /> </bean> </beans>
Here notice that for the bean PayServiceImpl autowire=byName is used. In that case Spring will see that PayServiceImpl has one property named as payment so it will look for the bean with same name/id in the config file. Since there is a bean with id as payment so that bean will be injected.
You can run it using the following program-
public class App { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext ("appcontext.xml"); IPayService bean = (IPayService) context.getBean("payServiceBean"); bean.performPayment(); context.close(); } }
Output
Perform Cash Payment for amount ... 20
Autowiring in Spring using byType
When you are autowring by type the property's type in auto wired bean will be used for searching the bean with the compatible type in the configuration file.
You can use the same example as above only change will be in the configuration file to change the autowire=byType.
<bean id="payServiceBean" class="org.netjs.springexp.prog.PayServiceImpl" autowire="byType"> <property name="amount" value="20" /> </bean>
In the config file there is a bean of type Payment which matches the type of the payment field in the PayServiceImpl class. Thus autowiring by type will work.
Limitation with autowire="byType"
There is one problem with using autowiring as byType. What if there are more than one bean in the configuration file whose type is compatible with the autowired property. In that case Spring won't be able to decide which bean to use, it will throw an exception instead. To see an example of this problem you need to create one more class which implements IPayment interface. Let's say with CashPayment there is also an option for CreditPayment.
CreditPayment class
public class CreditPayment implements IPayment { public void executePayment(int amount) { System.out.println("Perform Credit Payment for amount ... " + amount); } }
In the config file also the definition is added.
<!-- defining CreditPayment bean --> <bean id="creditPayment" class="org.netjs.springexp.prog.CreditPayment" />
Now there are two beans of type IPayment in the config file. In that case if we run the program Spring won't be able to decide which one to inject either CashPayment or CreditPayment so it will throw UnsatisfiedDependencyException instead.
Output
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'payServiceBean' defined in class path resource [appcontext.xml]: Unsatisfied dependency expressed through bean property 'payment': : No qualifying bean of type [org.netjs.springexp.prog.IPayment] is defined: expected single matching bean but found 2: payment,creditPayment; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.netjs.springexp.prog.IPayment] is defined: expected single matching bean but found 2: payment,creditPayment at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType (AbstractAutowireCapableBeanFactory.java:1307)
Solving UnsatisfiedDependencyException with Spring autowiring
To overcome this problem there are two options-
- primary candidate- Identify a primary candidate for auto wiring bean and set that as primary="true"
<bean id="payment" class="org.netjs.springexp.prog.CashPayment" primary="true"/>
- Exclude a bean from autowiring- You can exclude a bean from being autowired. For that set
the autowire-candidate attribute of <bean> tag to false.
<bean id="creditPayment" class="org.netjs.springexp.prog.CreditPayment" autowire-candidate="false" />
Autowiring in Spring by constructor
Autowiring by constructor is same like byType in this case type of the constructor argument in the auto wired bean is used to search the bean with the same type.
If you change the PayServiceImpl class to have a constructor which has a IPayment type as a parameter.
public class PayServiceImpl implements IPayService { private IPayment payment; private int amount; // Constructor PayServiceImpl(IPayment payment){ this.payment = payment; } public void performPayment() { // calling payment class executePayment method payment.executePayment(amount); } public int getAmount() { return amount; } public void setAmount(int amount) { this.amount = amount; } }
And change the configuration file as-
<bean id="payServiceBean" class="org.netjs.springexp.prog.PayServiceImpl" autowire="constructor"> <property name="amount" value="20" /> </bean>
default-autowire attribute
If you are using the same autowire attribute with most of the bean in your config file, you can define that autowire attribute as default for all the beans with in the config file. That can be done by adding a default-autowire attribute to the root </beans> element.
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd" default-autowire="byType">
Here default auto wiring is set to byType which means all the beans in this config file will use auto wiring as byType by default. Note that by default default-autowire is set to none.
You can still set autowire attribute for individual beans which will override the default-autowire attribute.
That's all for this topic Autowiring in Spring Using XML Configuration. If you have any doubt or any suggestions to make please drop a comment. Thanks!
>>>Return to Spring Tutorial Page
Related Topics
You may also like-
Please post some more topics on Spring
ReplyDelete