Monday, April 9, 2012

Auto-Wiring in Spring

Dear Reader,

We are going to discuss "Auto-Wiring in Spring framework". You might be knowing or might be expert on this,
either way you can comment if something more need to be added.

Topics discussed:
 1) A simple and complete program on Spring framework to start with.
 2) Types of Auto-Wiring and details of each Auto Wire mode.

Auto-Wiring is a term we use in Spring framework. It is a kind of injection of objects.
Let me write a basic Spring program and then I will discuss further:

======================================
//Customer class 
package com.deepak;
public class Customer {
    private Person person;
    public Customer(){
        System.out.println("Default Customer constructor");
    }  
    //person is set here through Constructor and setter method, see below:
    public Customer(Person person) {
        System.out.println("Parameterized Customer constructor");
        this.person = person;
    }
    public void setPerson(Person person) {
        System.out.println("Customer setter method");
        this.person = person;
    }
    public Person getPerson() {
        System.out.println("Customer getter method");
        return person;
    }
}

//Person class
package com.deepak;
public class Person {
    String skill="Default Skill is Java and Spring";
    public Person(){
        System.out.println("Default Person constructor");
    }

    public String getSkill() {
        System.out.println("Person getter method");
        return skill;
    }
    public void setSkill(String skill) {
        System.out.println("Person setter method");
        this.skill = skill;
    }
}

//autowire.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"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="customer" class="com.deepak.Customer">
        <property name="person" ref="person" />
    </bean>

    <bean id="person" class="com.deepak.Person">
        <property name="skill" value="Skill set changed to J2EE and Spring" />
    </bean>
</beans>


//Main Program to run
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.deepak.Customer;
import com.deepak.Person;

public class AutoWireMainProgram {
    public static void main(String[] args) {
        BeanFactory beanfactory = new ClassPathXmlApplicationContext("./autowire.xml");
        
        Customer customerBean=(Customer)beanfactory.getBean("customer");
        Person personBean=(Person)beanfactory.getBean("person");
        System.out.println("PersonBean: "+personBean+", Skill: "+personBean.getSkill());
        System.out.println("Bean Factory contains Bean(\"person\"): "+beanfactory.containsBean("person"));
    }
}


//Output:
    log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
    log4j:WARN Please initialize the log4j system properly.
    Default Customer constructor
    Default Person constructor
    Person setter method
    Customer setter method
    Person getter method
    PersonBean: com.deepak.Person@285b5c, Skill: Skill set changed to J2EE and Spring
    Bean Factory contains Bean("person"): true
======================================


The programs are quite basic and do not need any explanation.
That's it. Now we will see how Auto-Wiring works. In Spring we can wire beans with auto-wiring feature, this need to be 
configured in XML config file. To enable it, just define the "autowire" attribute in <bean> tag. 

So total 5 Auto-wiring modes are supported:
   1. no – It means No auto wiring. Better set it manually via "ref" attribute.
   2. byName – Auto wiring by property name. If the name of a bean is same as the name of other bean property, auto wire it.
   3. byType – Auto wiring by property data type. If data type of a bean is compatible with the data type of other bean 
      property, auto wire it.
   4. constructor – byType mode in constructor argument.
   5. default – This is same as "no" auto-wire in terms of functions.

Generally "byName", "byType", "constructor" are in use for Auto-wiring. You can see one more type "autodetect" mode but
I don't see this in Spring2.5 where I have tested the application.  

Details of all wiring modes:

Auto-Wiring with "no" mode: The above example uses "ref" attribute to refer a bean. This is "no" auto-wire. By the way
   same can be specified, so "no" wire mode is like below:
   
    //autowire.xml
    <bean id="customer" class="com.deepak.Customer" autowire="no">
        <!-- <property name="person" ref="person" /> -->
    </bean>

    <bean id="person" class="com.deepak.Person">
        <property name="skill" value="Skill set changed to J2EE and Spring" />
    </bean>

//No change in main program code base, below is the output:
    log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
    log4j:WARN Please initialize the log4j system properly.
    Default Customer constructor
    Default Person constructor
    Person setter method
    Person getter method
    PersonBean: com.deepak.Person@284370, Skill: Skill set changed to J2EE and Spring
    Bean Factory contains Bean("person"): true

NOTE: "Customer setter method" line is missing, not invoked. The same output comes when you set autowire="default".
      That shows by default it is "no" wire mode. Also note line "property name=person ref=person" is commented in bean tag.    
    

Auto-Wiring with "byName" mode: 
  Auto wire with "byName" mode means wiring by property name. Customer class has property name "person". 
  So Spring will auto wire it via setter method – "setPerson(Person person)".  
    
    //autowire.xml
    <bean id="customer" class="com.deepak.Customer" autowire="byName">    
    </bean>

    <bean id="person" class="com.deepak.Person">
        <property name="skill" value="Skill set changed to J2EE and Spring" />
    </bean>

//No change in main program code base, below is the output:
    log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
    log4j:WARN Please initialize the log4j system properly.
    Default Customer constructor
    Default Person constructor
    Person setter method
    Customer setter method
    Person getter method
    PersonBean: com.deepak.Person@284f12, Skill: Skill set changed to J2EE and Spring
    Bean Factory contains Bean("person"): true

NOTE: "Customer setter method" line is displayed, means invoked. The output is same as first one when we have not used wiring.    

Auto-Wiring with "byType" mode: 
    Auto wire with "byType" mode means wiring by property data type. Customer class has property "person" whose data
    type is "Person" and the same in config file too. So Spring will auto wire it via setter method – "setPerson(Person person)".   
    
    //autowire.xml
    <bean id="customer" class="com.deepak.Customer" autowire="byType">    
    </bean>

    <bean id="person" class="com.deepak.Person">
        <property name="skill" value="Skill set changed to J2EE and Spring" />
    </bean>
    
//No change in main program code base, below is the output:
    log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
    log4j:WARN Please initialize the log4j system properly.
    Default Customer constructor
    Default Person constructor
    Person setter method
    Customer setter method
    Person getter method
    PersonBean: com.deepak.Person@28862d, Skill: Skill set changed to J2EE and Spring
    Bean Factory contains Bean("person"): true

NOTE: "Customer setter method" line is displayed here too. The output is same as first one when we have not used wiring.    

Auto-Wiring with "constructor" mode: 
    Auto wire with "constructor" mode sets a bean by property data type in constructor argument. In this case, 
    since the data type of "person" bean is same as the constructor argument in Customer class. So Spring auto wired it 
    via constructor method – "public Customer(Person person)". Read the NOTE below carefully.
    
    //autowire.xml
    <bean id="customer" class="com.deepak.Customer" autowire="constructor">
    </bean>

    <bean id="person" class="com.deepak.Person">
        <property name="skill" value="Skill set changed to J2EE and Spring" />
    </bean>
    
//No change in main program code base, below is the output:
    log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
    log4j:WARN Please initialize the log4j system properly.
    Default Person constructor
    Person setter method
    Parameterized Customer constructor
    Person getter method
    PersonBean: com.deepak.Person@286fff, Skill: Skill set changed to J2EE and Spring
    Bean Factory contains Bean("person"): true

NOTE: "Customer setter method" line is not displayed here. But did you note: "Parameterized Customer constructor"
      is displayed which is a result of constructor auto wire. See the Constructor of Customer class again:
     
       public Customer(Person person) {
        System.out.println("Parameterized Customer constructor");
        this.person = person;
      }

Auto-Wiring with "default" mode: 
    This is same as "no" mode, which is discussed above.

Conclusion:  Spring "auto-wiring" makes development faster but it adds costs. The bean configuration file becomes
            quite complex because of this and some time you don’t even know which bean will auto wired in which bean.
===========================END==========================

No comments:

Post a Comment