Tuesday, March 20, 2012

@AutoWiring


1.    Introduction:

In the last blog I have explained the Dependency Injection. DI helps in injecting the dependencies using either the <property> or <constructor-arg> elements .And hence whenever there is a new bean defined one needs to go and change the spring configuration file (servlet xml). Just to avoid this, spring offers AutoWiring. AutoWiring helps in reducing configuration overhead by not using the property and constructor arg elements. How?
Let’s first understand the AutoWiring.
Bookish Definition: The Spring container is able to autowire relationships between collaborating beans. This means that it is possible to automatically let Spring resolve collaborators (other beans) for your bean by inspecting the contents of the BeanFactory.
Simple Definition: 
Autowiring let spring container decide which bean to inject into a controller. 
It helps in avoiding the explicit wiring of bean properties.
Example: To display the results from Database, A controller needs a DataSource bean.
Now in Dependency Injection what we do is, we inject the datasoure bean to the controller by setter or constructor dependency injection in the xml configuration file. Autowiring lets Spring to decide how to wire dependency and hence we do not need to explicitly wire bean properties.
Dependency Injection    
 And AutoWiring:

      2. Types of AutoWiring:

  •  byName: Based on the name of a property.
  • byType: Based on a type of class on a setter.
  • constructors: Based on a constructor argument's class types.
  • autodetect : Chooses constructor or byType through introspection of the bean class.
Code examples:
            Class 1:
package com.sk.autowiring;
            public class Player {
                        private Game game;
                        public void setGame(Game game) {
                                    this.game = game;
                        }
                        //Some logic...
}
Class2:
package com.sk.autowiring;
            public class Game {
            private String gameName;
            // Some logic ..
}
Class3:
package com.sk.autowiring;
public class Batsman {
            private String batsmanType;
            //...
}

2.1 ByName:

Autowiring by property name. This option will inspect the container and look for a bean named exactly the same as the property which needs to be autowired. This uses the setter method.
In Dependency Injection, we have done explicit wiring for beans. For ex.
<bean id="player" class="com.sk.autowiring.Player" >
            <property name="game" ref="game" />
</bean>
 <bean id="game" class="com.sk.autowiring.Game" >
            <property name="gameName" value="cricket" />
</bean>
But using autowiring , there is no need to declare the property tag . As long as the “game” bean has same name as the property of “player” bean, which is “game”, spring will wire it automatically.
<bean id="player" class="com.sk.autowiring.Player" autowire="byName"/>
 <bean id="game" class="com.sk.autowiring.Game" >
            <property name="gameName" value="cricket" />
</bean>

2.2 ByType :

When attempting to autowire a property by type, Spring will look for beans whose type is assignable to the property’s type.
            <bean id="player" class="com.sk.autowiring.Player" >
                        <property name="batsman" ref="batsman" />
            </bean>
            <bean id="batsman" class="com.sk.autowiring.Batsman" >
                        <property name="batsmanType" value="opening" />
            </bean>
With autowire by type, properties need not to be set. Spring will find the same data type and wire it automatically.
         <bean id="player" class="com.sk.autowiring.Player" autowire="byType" />
         <bean id="batsman" class="com.sk.autowiring.Batsman" >
                        <property name="batsmanType" value="opening" />
          </bean>
There can be a lot of beans which are of the same type and hence in that case spring will throw exception. There are 2 options using which We can avoid
a)    primary attribute : Bean element’s primary attribute helps in identifying  a primary candidate for autowiring. If its value is true, then that particular bean will be chosen in favor of others.

<bean id="batsman" class="com.sk.autowiring.Batsman” primary=”false”/>
 
b)    autowire-candidate attribute : Bean elements’s is used to identify a preferred autowire candidate among al of them. This attribute actually eliminates beans from considerations of autowiring when the value is set to false.

<bean id="batsman" class="com.sk.autowiring.Batsman” autowire-candidate=”false”/>

2.3 constructor:

 Based on a constructor argument's class types .If the bean is configured using constructor injection, we do not need to define <constructor-arg> elements and let Spring  automatically choose constructor elements from beans in the spring context.
When bean property is wired explicitly:
            <bean id="player" class="com.sk.autowiring.Player" >
                        <constructor-arg>
 <ref bean="batsman" />
</constructor-arg>
            </bean>
            <bean id="batsman" class="com.sk.autowiring.Batsman" >
                        <property name="batsmanType" value="openning" />
            </bean>
With autowire by type, constructor arg elements need not to be set.Spring will find the same data type and wire it automatically.
            <bean id="player" class="com.sk.autowiring.Player" autowire="constructor" />

            <bean id="batsman" class="com.sk.autowiring.Batsman" >
                        <property name="batsmanType" value="openning" />
            </bean>

2.4 autodetect:

 In Spring, "Autowiring by AutoDetect", means chooses "autowire by constructor". If default constructor (argument with any data type), otherwise uses "autowire by type".
<bean id="player" class="com.sk.autowiring.player" autowire="autodetect" />
 <bean id="game" class="com.sk.autowiring.Game" />
           

3.    Autowiring of beans with @Autowired annotations

Autowiring of beans with @Autowired annotations feature started from Spring 2.5 version. @Autowired annotation can be used to auto wire bean on the setter method, constructor or a field. Spring checks the property on which this is being defined and then it will try to perform ‘byType’ autowiring on that property. You don’t need a setter method to use it.  Since Annotation wiring is not turned on by default and hence we need to enable it. 

3.1   Enable autowiring:

               <context:annotation-config />
 
               In the Spring’s context configuration namespace (servlet.xml)
               
   <beans xmlns="http://www.springframework.org/schema/beans"

  ..................... 
                  
             <context:annotation-config />
 
    </beans>
 

3.2 @Autowired property Examples:

1. @Autowired setter method
package com.sk.autowiring;
                        import org.springframework.beans.factory.annotation.Autowired;
                        public class Player {
                                    private Game game;
                                    //Autowiring setter
                                    @Autowired
                                    public void setGame(Game game) {
                                                this.game = game;
                                    }
}
2. @Autowired construtor
package com.sk.autowiring;
import org.springframework.beans.factory.annotation.Autowired;
                        public class Player {
                                    private Game game;
                                    // Autowiring Constructor
                                    @Autowired
                                    public Player(Game game) {
                                                this.game = game;
                                    }
}
3. @Autowired field
package com.sk.autowiring;
                        import org.springframework.beans.factory.annotation.Autowired;
                        public class Player {
                                    //Autowiring field
                                    @Autowired
                                    private Game game;
                        }

4. @Qualifier

There can be a case when more than one bean is defined of the same name or type. In that event, there is no way for @Autowired to choose which one should really be selected. To help @Autowired figure out which bean you want, you can accompany it with Spring's @Qualifier annotation. The @Qualifier annotation used to control which bean should be autowire on a field.
For example, bean configuration file with two similar game beans.
<beans xmlns="http://www.springframework.org/schema/beans"
                            .............   
                        <context:annotation-config />
                        <bean id="Player" class="com.sk.autowiring.Player">
                                                <property name="name" value="Sushant" />
                                    </bean>
                        <bean id="Game1" class="com.sk.autowiring.Game">
                                                <property name="gameName" value="Cricket" />
                                    </bean>
                                    <bean id="Game2" class="com.sk.autowiring.Game">
                                                <property name="gameName" value="Football" />
                                    </bean>
                        </beans>
Now how will Spring decide which bean it should wire? To fix it, you can use  @Qualifier to auto wire a particular bean, for example,
package com.sk.autowiring;
                        import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
                        public class Player {
                                    @Autowired
                                    @Qualifier("Game1")
                                    private Game game;
}
In this case, Game1 is autowired.This is how the Autowiring works.

5.    Pros\Cons of Autowiring

As there are pros and cons of each approach, with this also there are few. Defining everything explicitly in the xml obviously is easier to understand by everybody and even to new people who joins the team at a later stage. But then maintaining an xml file for each and everything will be a big overhead. Annotations are easier to use and maintain.
Now even Spring autowiring also increases the complexity for the servlet xml file and hence better to use the @Autowired annotations.
So which ever approach will be used all are at last Dependency Injection only.




No comments:

Post a Comment