Tuesday, September 8, 2015

Autowiring in Spring

Autowiring is a technique to wire the beans together. Specially, when there are many dependencies, all of the dependencies can be  managed easily using Autowiring.

Autowiring can be performed in several methods, here are the following methods it can be done:
  1. byType
  2. byName
  3. constructor
  4. default
We can use the autowiring property of the bean to set the autowiring method.

In this example we are going to use the following classes, interface and XML file.

Employee - Interface

package com.kasibsblog.spring.test;

public interface Employee {
   
    public void print(String name, int salary, String company);

}

FullTimeEmployee - Class

package com.kasibsblog.spring.test;

public class FullTimeEmployee implements Employee {

    public void print(String name, int salary, String company) {
        System.out.println("Company : " + company + ", " + "Name : " + name + ", " + "Salary : " + salary + ",  "+ "Type : Full-Time");
    }

}

PartTimeEmployee - Class

package com.kasibsblog.spring.test;

public class PartTimeEmployee implements Employee {

    public void print(String name, int salary, String company) {
        System.out.println("Company : " + company + ", " + "Name : " + name + ", " + "Salary : " + salary + ", "
                + "Type : Part-Time");
    }
}

AbCompany - Class

package com.kasibsblog.spring.test;

public class AbCompany {

    private FullTimeEmployee fulltime;
    private PartTimeEmployee parttime;
 
    public void setFulltime(FullTimeEmployee fulltime) {
        this.fulltime = fulltime;
    }

    public void setParttime(PartTimeEmployee parttime) {
        this.parttime = parttime;
    }
   
    public void printFullTime(String name, int salary, String company){
        fulltime.print(name, salary, company);
    }
   
    public void printPartTime(String name, int salary, String company){
        parttime.print(name, salary, company);
    }

}

Main - Class

package com.kasibsblog.spring.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("com/kasibsblog/spring/test/beans/beans.xml");
       
        AbCompany abcompany= (AbCompany) context.getBean("abcompany");
        abcompany.printFullTime("Sue", 12000, "Ab Company");
        abcompany.printPartTime("Mary", 10000, "Ab Company");

        ((ClassPathXmlApplicationContext) context).close();
    }

}

beans.xml  

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    default-init-method="init" default-destroy-method="destroy"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean id="abcompany" class="com.kasibsblog.spring.test.AbCompany">
    </bean>

    <bean id="partTime" class="com.kasibsblog.spring.test.PartTimeEmployee">
    </bean>
   
    <bean id="fullTime" class="com.kasibsblog.spring.test.FullTimeEmployee">
    </bean>

</beans>

Now let's look at different modes of autowiring.

1. byType

Autowiring is done by using the data-type. It tries to match exactly a bean per data-type, if it finds more than a bean of the same type then an exception is thrown, also known as "Autowiring ambiguity".

  <bean id="abcompany" class="com.kasibsblog.spring.test.AbCompany" autowiring="byType">
  </bean>

 Assume that there are two beans of FullTimeEmployee as:

<bean id="fullTime" class="com.kasibsblog.spring.test.FullTimeEmployee">
</bean>

<bean id="fullTime2" class="com.kasibsblog.spring.test.FullTimeEmployee">
 </bean>

In this case, an exception would be thrown.

2. byName

Autowiring byName uses the the bean name or the bean id to wire the beans together.

<bean id="abcompany" class="com.kasibsblog.spring.test.AbCompany" autowiring="byName">
</bean>

<bean id="fullTime" class="com.kasibsblog.spring.test.FullTimeEmployee">
</bean>

<bean name="partTime" class="com.kasibsblog.spring.test.PartTimeEmployee">
</bean>

3. constructor

<bean id="abcompany" class="com.kasibsblog.spring.test.AbCompany" autowiring="constructor">
</bean>

The abcompany bean autowiring property is now set to constructor. The ABCompany class should include a two argument constructor, for this example.

public AbCompany(FullTimeEmployee fulltime, PartTimeEmployee parttime){
        this.fulltime = fulltime;
        this.parttime = parttime;
    }

The beans should match both the arguments specified in the in the constructor, otherwise it will thrown an error.

Assume that the bean with id - fulltime, has the class set to AbCompany. This will result an ambiguity as the abcompany been autowired by constructor.

<bean id="fullTime" class="com.kasibsblog.spring.test.AbCompany">
</bean>

4. default

Spring allows us to set a default autowiring which will be activated for the specified XML configuration file.

The default autowiring should be added to the beans tag in the configuration file, not the bean tag

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd"
    default-autowire="byType">

</beans>

In the above sample code, I have selected the default autowiring method as byType. We can also specify any one of the above discussed methods.

Moreover, assume that there are two beans that belongs to FullTimeEmployee class. For example,

<bean name="fulltime" class="com.kasibsblog.spring.test.FullTimeEmployee">
 </bean>

<bean name="fulltime2" class="com.kasibsblog.spring.test.FullTimeEmployee">
</bean>

In this case, an exception would be thrown since that Spring cannot detect which bean to select from the two beans. In order to eliminate this ambiguity we can specify what bean should be used to wire with the "abcompany" bean.

We can achieve this by using the default-autowing-candidates property of the beans tag.

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
    default-autowire="byType" default-autowire-candidates="fulltime,parttime">

</beans>

Here the fulltime and partime beans areselected as the default-autowire-candidates. It is a comma seperated list also note that the list cannot contain any white spaces.

Using wildcards to specify default-autowire-candidates

Wildcards can be used to specify the default candidates, an asterisk(*) is used as the wildcard character.

In our example, both the beans end with "time" - fulltime & parttime. The code can be changed to 

default-autowire-candidates="*time"










2 comments :

  1. Hi Kasib. Thank you for your topic.
    But why did you use out-of-date XML configuration?

    ReplyDelete
  2. Hi Sergey,
    Thanks for the feedback. I used XML configuration to explain the behind the scenes of Autowiring. My next post will be on Autowiring with Annotations and don't forget to check it out.

    ReplyDelete