Tuesday, August 12, 2014

Spring Dependency Injection

The dependency injection is about building relationships of the objects. The dependencies can be of primitive types or other objects. Spring support two types of dependency injection:
  • Constructor Dependency Injection: The dependency is injected via constructor arguments.
  • Setter Dependency Injection: Dependency is provided through setter methods as per Java Bean style.
Constructor Dependency Injection

Let's have a constructor in User which has arguments

User.java

public class User {

   User(String first,String last){
       firstName =first;
       lastName = last;
   }
}

Now to inject the dependencies, put the dependencies via configuration XML

<bean id=“user” class=“User”>
   <constructor-arg value=“ChandraGupta"/>
   <constructor-arg value=“Maurya"/>
</bean>

The argument resolution is done by doing type matching.The matching is done in the order it is defined. For better ambiguity resolution we can use type or index.
Suppose we have a constructor User(int,double) than we can use

<bean id=“user” class=“User”>
   <constructor-arg type="int" value="45" />
   <constructor-arg type="double" value="58.5" />
</bean>

            or

<bean id=“user” class=“User”>
   <constructor-arg index= "0" value="45" />
   <constructor-arg index= "1" value="58.5" />
</bean>

If suppose we have two constructors User(String) and User(int) and have the following in XML

<bean id=“user” class=“User”>
   <constructor-arg  value="45" />
</bean>

Spring will go for User(String), as there is no way for it figure out that the value is a number. In XML everything is String. However if you want to use User(int) than qualify it with type.

Setter Dependency Injection

In setter based dependency injection, the bean style setter are used by Spring to set the properties. In our example of User, the properties can be set by injecting properties

<bean id=“user” class=“User”>    
   <property name=“firstName" value="ChandraGupta"/>
   <property name=“lastName" value="Maurya"/>
</bean>

Constructor vs Setter Dependency Injection

Which is better? Constructor based dependency injection forces to set the property. However the property cannot be changed later on. Setter based dependency injection allows reconfiguration later on. You have have both Constructor based dependency injection and Setter based dependency injection also together.

Dependency Injection

Spring supports various kind of dependency injection which includes:

  • Primitive type and Simple Values(like String): The above example belong to this category.
  • Other beans in same or parent factory: We can provide other beans also as dependency. Multiple Spring factories can be built with parent child relationships. In that case we can inject bean from parent factory to child factory.
  • Collections: We can inject Properties,Set,List and Map.
  • Properties defined in external properties/resource files: This is useful for properties which change at deployment levels.

Primitive type and Simple Values

Suppose User has three properties age,height and firstName and corresponding setters than we can inject those properties  through configuration XML

<bean id=“user" class=“User">
   <property name="age" value="64" />
   <property name="height" value="184.20" />
   <property name=“firstName" value="Amitabh" />    
</bean>

Other beans in same or parent factory

Let's write an Address class and we will inject some addresses in our User class

Address.java

public class Address {
   private String street;
   private String city;
    
  //Setters and getters for street and city
  ...
}

Let's introduce two address reference in User.java

User.java

Address homeAddress;
Address officeAddress;

//Setters and getters for the address properties

Now Let's have two Address bean in Spring and we inject them in User

<bean id= “officeAdd" class=“Address">
    <property name="street" value="dadar"/>
    <property name="city" value="Mumbai"/>  
</bean>
<bean id= “homeAdd" class="Address">
    <property name="street" value="dadar"/>
    <property name="city" value="Mumbai"/>  
</bean>    
<bean id="user" class="User">
    <property name="officeAddress">
       <ref bean= “officeAdd" />
    </property>
    <property name=" homeAddress ">
       <ref bean= “homeAdd " />
    </property>
</bean>

ref allows creating a reference to any bean in the same or parent container. Also we can inject bean of any type or subtype. Spring honors the inheritance hierarchy. If we want to restrict the wiring to the local container only, than configuration will be:

<bean id="user" class="User">
   <property name="officeAddress">
      <ref local = "address" />
    </property>

Similarly for referencing the bean only in parent container

<bean id="user" class="User">
   <property name="officeAddress">
     <ref parent = "address" />
   </property>

You can also inject beans as inner beans. Inner beans are similar to inner classes.They are anonymous and always scoped as prototype. The name and id is not defined for inner bean. Even if they are defined it is ignored.Also it is not possible to inject inner beans into other beans.

<bean id="user" class="User">
   <property name="officeAddress">
      <bean class="Address">
    <property name="street" value="dadar" />
    <property name="city" value="Mumbai" />
      </bean>
   </property>
</bean>

Injecting Collections

In Spring you can inject collection of type Properties, List, Map and Set
Properties injection: Let's have a java.util.Properties phoneNumbers in User and have setters and getters for it.

<!-- results in a setPhoneNmubers(java.util.Properties) call -->
<property name=“phoneNumbers">
   <props>
     <prop key=“personal">1234</prop>
     <prop key=“official">5678</prop>
     <prop key=“secret">8888</prop>
   </props>
</property>

Similarly for List have the properties and inject it through XML

<!-- results in a setRecoveries(java.util.List) call -->
<property name="recoveries">
   <list>
     <value>"House Rent"</value>
     <value>"Over Payment"</value>
     <value>"House Rent"</value>
   </list>
</property>

For Set

<property name="loans">
   <set>
     <value>"Monthly Premium"</value>
     <value>"Education"</value>
     <value>"Monthly Premium"</value>
   </set>
</property>

For Maps

<property name="emails">
   <map>
     <entry>
    <key><value>"personal"</value></key>
    <value>aa@gmail.com</value>
     </entry>
     <entry>
    <key><value>"official"</value></key>
    <value>bb@lalit.com</value>
     </entry>
   </map>
</property>

Spring supports merging of collections also.

<bean id="parent" abstract="true" class=“User">
   <property name="phoneNumbers">
     <props>
    <prop key="personal">1111</prop>
    <prop key=“office">2222</prop>
     </props>
   </property>
</bean>

<bean id="child" parent="parent“ class=“User”>
   <property name="phoneNumbers">
    <!-- the attribute merge="true" tells it to take the 
    properties from Parent and than append it from here -->
       <props merge="true">
      <prop key="office">5555</prop>
      <prop key="secret">8888</prop>
       </props>
   </property>
</bean>

With Java5+ Generics feature we can have type safe collections. Suppose user has a Map defined as

private Map<String,Float>marks;

In spring configuration

<property name=“marks">
   <map>
     <entry>
    <key><value>"maths"</value></key>
    <value>56</value>
     </entry>
     <entry>
    <key><value>"Physics"</value></key>
    <value>77</value>
     </entry>
   </map>
</property>

Without type safety from ((Generics)), the collection contains plain String objects.

Shortcuts for injecting Dependencies

you can use shortcuts to inject dependencies. Prefer them than the verbose way of writing the things

<property name="age" value="32"/>
<constructor-arg value="Chandragupta"/>
<entry key="maths" value="56"/>
<property name="officeAddress" ref="officeAdd"/>
<constructor-arg ref="homeAdd"/>

Compound Property injection

Spring can deep dive into the relationships and can set the values.

<bean id=“user” class=“User”>
   <property name= “homeAddress.city" value="Pune"/>
</bean>

This will result in call of getHomeAddress().setCity("Pune"). Be careful that now you are responsible for instantiating homeAddress reference properly before Spring reaches to set this property. The nesting can be any level deep.

Lazy initialization

By default Spring creates the singleton beans eagerly. The prototype beans are created on demand only. However if you want to change the behaviour so that singleton beans are also created on demand than use lazy-init attribute

<bean id=“user" class="User" lazy-init="true"/>

Lazy initialization can be turned on at container level

More Articles on Spring

No comments:

Post a Comment