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:

  1. byName
  2. byType
  3. constructor
  4. 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 post on “Dependency injection with spring” where we injected an object as a dependency into a dependent class.

Download this application–>Download

CellPhone.java


package com.codegeekslab.device;

public interface CellPhone {

public void makeCall(int number);

}

BasicPhone.java


package com.codegeekslab.type;

import com.codegeekslab.device.CellPhone;

public class BasicPhone implements CellPhone {

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

}

SmartPhone.java


package com.codegeekslab.type;

import com.codegeekslab.device.CellPhone;

public class SmartPhone implements CellPhone {

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

}

CallingApp.java


package com.codegeekslab.app;

import com.codegeekslab.device.CellPhone;

public class CallingApp {

private CellPhone phone;

// for setter injection
public void setPhone(CellPhone phone) {
this.phone = phone;
}

public CellPhone getPhone() {
return phone;
}

public void dialNumber(int number) {
phone.makeCall(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="SmartPhone" />
</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.dialNumber(1419494494);
}
}

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... 1419494494

 

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 asking explicitly or manually to spring to inject the dependency SmartPhone into the CallingApp class.But instead if we use autowiring feature we don’t have to use this ref tag <property name=”phone” ref=”SmartPhone”/> and spring will implicitly or automatically inject the dependency SmartPhone into the CallingApp class.

As mentioned in the beginning  there are 4 modes to implement dependency injection using autowiring.

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

Autowiring by byName: In this mode the name of the bean and name of the property must be same.Let’s understand what it means by implementing autowiring byName.

Our requirement is to inject the dependency SmartPhone into CallingApp,to do so two things which our beans.xml must have:

  1. The name of the SmartPhone bean in beans.xml must match the name of variable(property) present in CallingApp class into which we want to inject SmartPhone bean which in this case is Phone interface.
  2. An autowire=”byName” in the end of the Dependent class bean tag.

Let’s understand the above description with an example, we will implement the same example given at top of this post about “dependency injection in spring” with autowiring and if we compare all files will remain same from the above example except beans.xml and CallingApp.java.

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>

CallingApp.java


package com.codegeekslab.app;

import com.codegeekslab.device.Phone;

public class CallingApp {

private Phone phone;//variable name is same as BasicPhone bean name

// for setter injection
public Phone getPhone() {
return phone;
}

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

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

}

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 class property name(variable name) which is “phone”(private Phone 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 .

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.