Wednesday, 20 April 2016

Injecting a prototype bean into a singleton bean

Problem: If we will inject the prototype bean into singleton bean; by default it will be singleton i.e. it will not behaving like prototype bean.

autowiring-spring.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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.0.xsd"

       default-autowire="byName" default-autowire-candidates="*">

       <context:annotation-config />

       <bean id="employee" class="spring.core.proto.in.sing.Employee" scope="singleton">
              <property name="id" value="1"></property>
              <property name="name" value="Rajesh kumar"></property>
              <property name="profile" value="developer"></property>
       </bean>

       <bean id="two" class="spring.core.proto.in.sing.PastInformation" scope="prototype">
              <property name="lastCompany" value="ABC2"></property>
       </bean>
</beans>

package spring.core.proto.in.sing;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class Employee {
       private int id;
       private String name;
       private String profile;

       @Autowired
       @Qualifier("two")
       private PastInformation lastSecond;

       // setters and getters

       public void displayInfo() {
              lastSecond.displayInfo("last");
              String empDetails="id : "+id+" name : "name + " profile : " + profile;
              System.out.println(empDetails);
       }
}

package spring.core.proto.in.sing;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestIOC {
       private static ApplicationContext appContext;
       public static void main(String[] args) {
              appContext = new ClassPathXmlApplicationContext
                              ("spring/core/proto/in/sing/autowiring-spring.xml");
              Employee empl1 = appContext.getBean("employee", Employee.class);

              empl1.displayInfo();
             
              Employee empl2 = appContext.getBean("employee", Employee.class);

              if(empl1==empl2) {
                     System.out.println("singleton !!");
              }

              /* This line should not print for prototype scope coz both     
              instance will be different. */
              if(empl1.getLastSecond()==empl2.getLastSecond()) {
                     System.out.println("singleton : not prototype as per scope !!");
              }
       }
}

Output:
last : ABC2
id : 1 name : Rajesh kumar profile : developer
singleton !!
singleton : not prototype as per scope !!

Resolve using Interface ObjectFactory:


package spring.core.proto.in.sing;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class Employee {
       @Autowired
       @Qualifier("two")
       private ObjectFactory<PastInformation> myPrototypeFactory;

       private int id;
       private String name;
       private String profile;

       public void displayInfo() {
              myPrototypeFactory.getObject().displayInfo("last");
              String empDetails="id : "+id+" name : "name + " profile : " + profile;
              System.out.println(empDetails);
       }

       public PastInformation getLastSecond() {
              return myPrototypeFactory.getObject();
       }
      
       public ObjectFactory<PastInformation> getMyPrototypeFactory() {
              return myPrototypeFactory;
       }

       public void setMyPrototypeFactory(
                     ObjectFactory<PastInformation> myPrototypeFactory) {
              this.myPrototypeFactory = myPrototypeFactory;
       }
}

Now, output:
last : ABC2
id : 1 name : Rajesh kumar profile : developer
singleton !!

Lookup Method injection
The Spring Framework implements method injection by using CGLIB library to generate dynamically a subclass that overrides the method. So for the method to be overridden, we have to define that method in the class and either provide a dummy implementation for it or make it abstract.

Making a method abstract implies that class also has to be made abstract which will make it difficult to unit test. So providing a dummy implementation is a better choice.

Whenever we define a bean with lookup methods, spring creates a subclass of the bean and overrides those methods which are marked as lookup-methods and this sub classed bean gets registered into the context. The subclass delegates all the non-lookup methods to the original class.

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.0.xsd"
       default-autowire="byName" default-autowire-candidates="*">

       <context:annotation-config />

       <bean id="employee" class="spring.core.proto.in.sing.Employee"
              scope="singleton">
              <property name="id" value="1"></property>
              <property name="name" value="Rajesh kumar"></property>
              <property name="profile" value="developer"></property>
              <lookup-method name="getLastSecond" bean="two"/>
       </bean>


       <bean id="two" class="spring.core.proto.in.sing.PastInformation"
              scope="prototype">
              <property name="lastCompany" value="ABC2"></property>

       </bean>
</beans>

Now, output:
last : ABC2
id : 1 name : Rajesh kumar profile : developer
singleton !!

Scoped Proxies:
<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.0.xsd"

       default-autowire="byName" default-autowire-candidates="*">

       <context:annotation-config />

       <bean id="employee" class="spring.core.proto.in.sing.Employee"
              scope="singleton">
              <property name="id" value="1"></property>
              <property name="name" value="Rajesh kumar"></property>
              <property name="profile" value="developer"></property>
              <lookup-method name="getLastSecond" bean="two" />
       </bean>


       <bean id="two" class="spring.core.proto.in.sing.PastInformation"
              scope="prototype">
              <property name="lastCompany" value="ABC2"></property>
            <aop:scoped-proxy />
       </bean>
</beans>

No comments:

Post a Comment

Related Posts Plugin for WordPress, Blogger...