Spring

AUTOWIRING IN SPRING FRAMEWORK

Autowiring in spring framework: it’s a feature of spring framework by which spring automatically injects one dependency into the another dependency or in a more formal way we can say implicitly wires the two dependencies.BENEFITS/NON

There are 4 modes of Autowiring supported by spring:

byName
byType
constructor
no
Let’s understand the above description of autowiring through a simple example by comparing an example of dependency injection without autowiring and with autowiring.

Example:

Dependency injection without autowiring: I will use the same example from my previous tutorial on “Dependency injection with spring” where we injected an object as a dependency into a dependent class.

Phone.java

package com.geekslab.device;

public interface Phone {

public void openApp(int number);

}

BasicPhone.java

package com.codegeekslab.type;

import com.geekslab.os.Phone;

public class BasicPhone implements Phone {

@Override
public void openApp(int number) {
System.out.println("calling via simcard... " + number);
}

}

SmartPhone.java

package com.codegeekslab.type;

import com.geekslab.device.Phone;

public class SmartPhone implements Phone {

@Override
public void openApp(int number) {
System.out.println("calling via whatsapp..." + number);
}

}

CallingApp.java

package com.codegeekslab.app;

import com.geekslab.device.Phone;

public class CallingApp {
private Phone phone;

// for setter injection

public void setPhone(Phone phone) {
this.phone = phone;
}

public Phone getPhone() {
return phone;
}

public void makeCall(int number) {
phone.openApp(number);
}

}

beans.xml
<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-2.5.xsd">

<bean id="BasicPhone" class="com.codegeekslab.type.BasicPhone"/>
<bean id="SmartPhone" class="com.codegeekslab.type.SmartPhone"/>

<bean id="CallingApp" class="com.codegeekslab.app.CallingApp">
<property name="phone" ref="BasicPhone"/>
</bean>

</beans> 

Test.java
package com.codegeekslab.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

import com.codegeekslab.app.CallingApp;
public class Test {

public static void main(String[] args) {
ApplicationContext context = new GenericXmlApplicationContext("beans.xml");
CallingApp callingApp = (CallingApp) context.getBean("CallingApp");
callingApp.makeCall(77777777);

}
}

Output


Feb 28, 2017 12:44:04 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [beans.xml]
Feb 28, 2017 12:44:04 PM org.springframework.context.support.GenericXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.GenericXmlApplicationContext@5e9f23b4: startup date [Tue Feb 28 12:44:04 IST 2017]; root of context hierarchy
calling via simcard...777777777

So in this example, we are injecting a dependency Smartphone into the CallingApp and to achieve this we have defined the dependency of SmartPhone and CallingApp class in beans.xml and used a ref tag <property name=”phone” ref=”SmartPhone”/> inside the bean creation tag of CallingApp class.

So by this, we are telling spring explicitly to inject the dependency SmartPhone into the CallingApp class.But if we use autowiring feature we don’t have to use this ref tag <property name=”phone” ref=”SmartPhone”/> and spring will automatically/implicitly inject the dependency SmartPhone into the CallingApp class.

Let’s understand implement the all 4 modes of autowiring one by one.

Autowiring by byName: Our requirement is to inject the dependency SmartPhone into CallingApp, So to do it using autowiring byName way we should have the id of the SmartPhone bean and the name of property into which we want to inject SmartPhone in the CallingApp should be same and an autowire=”byName in the end of the Dependent class bean tag”

So In this mode, the id of the bean and name of the property of the dependent class which we want to inject must be same to achieve autowiring.

Let’s understand the above description with an example, we will implement the same above example with autowiring and all files will remain same from the above example except beans.xml.

beans.xml


<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-2.5.xsd">

<bean id="phone" class="com.codegeekslab.type.BasicPhone" />

<bean id="SmartPhone" class="com.codegeekslab.type.SmartPhone" />

<bean id="CallingApp" class="com.codegeekslab.app.CallingApp" autowire="byName"/>

</beans>

output

calling via simcard... 777

As you can see this below tag from bean.xml in which
<bean id=”CallingApp” class=”com.codegeekslab.app.CallingApp” autowire=”byName”/>
we have not used any ref tag like before to inject the dependency of BasicPhone into CallingApp instead we have used autowire=”byName” which enables the autowiring feature into our application.So now spring will search whose bean id is same as the CallingApp’s property name which is “phone”.

As the id of the bean which is “phone” for BasicPhone class
<bean id=”phone” class=”com.codegeekslab.type.BasicPhone” />
is same as the property name “phone” in CallingApp class “private Phone phone”, So spring implicitly injects the BasicPhone dependency into CallingApp class as both have same names.

Autowiring by byType: As like before our requirement is to inject the dependency BasicPhone into CallingApp, So to do it using autowiring byType way, the BasicPhone class must implement(or extend if the property is class) the property into which we want to inject BasicPhone in the CallingApp or we can say both should be of same type or hierarchy and an autowire=”byName in the end of the Dependent class bean tag”.

There should be only one type of bean present in the beans.xml of the property of the dependent class else you will get an UnsatisfiedDependencyException.

Note: Autowiring By byType is a bit confusing concept, I recommend you to run the below example and then re-read the above description of Autowiring by byType.

Let’s understand the above description with an example, we will implement the same above example with autowiring and all files will remain same from the above example except beans.xml.

beans.xml


<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-2.5.xsd">

<bean id="BasicPhone " class="com.codegeekslab.type.BasicPhone " />
<bean id="CallingApp" class="com.codegeekslab.app.CallingApp" autowire="byType"/>

</beans>


Output
calling via simcard... 777

As you can see this below tag from bean.xml in which

<bean id=”CallingApp” class=”com.codegeekslab.app.CallingApp” autowire=”byType”/>
like in our example of autowiring byName we have not used any ref tag to inject the dependency of BasicPhone into CallingApp. Instead, we have used autowire=”byType” which enables the autowiring feature into our application.So now spring will search the class who has implemented the Phone interface and in our bean.xml there is only one bean which is of BasicPhone

<bean id=”BasicPhone” class=”com.codegeekslab.type.BasicPhone” />

and as it implements Phone interface it satisfies the condition of autowire byType as class BasicPhone is of Type Phone interface.

The next question arises is , what if keep other beans of the same type of Phone interface or we can say other beans which implements the phone interface apart from BasicPhone like in our previous examples.

Let’s keep the SmartPhone bean also in the beans.xml and see what happens.

beans.xml


<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-2.5.xsd">

<bean id="SmartPhone" class="com.codegeekslab.type.SmartPhone" />
<bean id="BasicPhone" class="com.codegeekslab.type.BasicPhone" />
<bean id="CallingApp" class="com.codegeekslab.app.CallingApp" autowire="byType"/>

</beans>

output


Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'CallingApp' defined in class path resource [beans.xml]: Unsatisfied dependency expressed through bean property 'phone': No qualifying bean of type [com.codegeekslab.device.Phone] is defined: expected single matching bean but found 2: SmartPhone,BasicPhone; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.codegeekslab.device.Phone] is defined: expected single matching bean but found 2: SmartPhone,BasicPhone
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1307)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1199)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:861)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541)
at org.springframework.context.support.GenericXmlApplicationContext.<init>(GenericXmlApplicationContext.java:70)
at com.codegeekslab.test.Test.main(Test.java:11)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.codegeekslab.device.Phone] is defined: expected single matching bean but found 2: SmartPhone,BasicPhone
at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:172)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1065)

We have been thrown a NoUniqueBeanDefinitionException .which says expected single matching bean but found 2: SmartPhone,BasicPhone.Because we have beans present in single beans.xml which implements the phone interface and by that it satisfy the condition of autowiring byType and because of that spring gets confused which one to inject into phone interface.

To overcome this problem we have to tell spring explicitly which bean out of these two we want to inject and to do that spring provides primary=”true” attribute which we can place in the tag of the bean which we want to inject into the dependent class

So here we want BasicPhone to get injected into CallingApp class so we will place the primary=”true” attribute into the bean of BasicPhone like this.

beans.xml


<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-2.5.xsd">

<bean id="SmartPhone" class="com.codegeekslab.type.SmartPhone" />
<bean id="BasicPhone" class="com.codegeekslab.type.BasicPhone" primary="true" />
<bean id="CallingApp" class="com.codegeekslab.app.CallingApp" autowire="byType"/>

</beans>

output


calling via simcard... 777

As you can see from the output even though there are two beans present of the same type only one is getting injected.

Autowiring by constructor: it’s kind of same as autowiring byType but instead of a set method there should be a constructor present in the dependent class which takes the dependency as an argument.

So if we want to inject dependency of BasicPhone into CallingApp class we have to define a bean of BasicPhone and a bean of CallingApp with an attribute autowire=”constructor” in the bean tag like below

beans.xml


<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-2.5.xsd">

<bean id="BasicPhone" class="com.codegeekslab.type.BasicPhone" />
<bean id="CallingApp" class="com.codegeekslab.app.CallingApp" autowire="constructor"/>

</beans>

A constructor must be present in CallingApp class.

CallingApp.java


package com.codegeekslab.app;

import com.codegeekslab.device.Phone;

public class CallingApp {

private Phone phone;

public CallingApp(Phone phone) {
this.phone = phone;
}

public void makeCall(int number) {
phone.openApp(number);
}

}

Output

[java]

calling via simcard… 777

[java]

In case of Autowiring by constructor if we place two compatible bean in a single file like below


<bean id="SmartPhone" class="com.codegeekslab.type.SmartPhone" />
<bean id="BasicPhone" class="com.codegeekslab.type.BasicPhone" />
<bean id="CallingApp" class="com.codegeekslab.app.CallingApp" autowire="constructor"/>

we will get a null pointer exception unlike unsatisfied dependency which we used to get incase of autowiring byType.

The process is same to overcome this problem just place the primary=”true” attribute into the tag of bean which you want to inject.


<bean id="SmartPhone" class="com.codegeekslab.type.SmartPhone" />
<bean id="BasicPhone" class="com.codegeekslab.type.BasicPhone" primary="true" />
<bean id="CallingApp" class="com.codegeekslab.app.CallingApp" autowire="constructor"/>

Autowiring by no:if you add autowire=”no” in any of your bean tag then you must wire the dependency explicitly and that bean won’t be able to participate in any of the autowiring mode.

Leave a Reply

Your email address will not be published. Required fields are marked *