Wednesday, 20 April 2016

Injecting a prototype bean into a singleton bean

Issue: If we will inject the prototype bean into singleton bean; by default it will be singleton means it will not behaving like prototype bean.

<?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>


Sunday, 10 April 2016

Prototype vs Request bean scope in Spring

prototype: This bean scope just reverses the behavior of singleton scope and produces a new instance each and every time a bean is requested.

request: Only one instance is created for an HttpRequest.
With this bean scope, a new bean instance will be created for each web request made by client. As soon as request completes, bean will be out of scope and garbage collected.

HttpRequest or request scope
For a in a single HttpRequest, when we will call getBean twice on Application and there will ever be one bean instantiated, whereas that same bean scoped to Prototype in that same single HttpRequest would get 2 different instances.

     MyBean myBean1 = context.getBean("myBean");
     MyBean myBean2 = context.getBean("myBean");
     myBean1 == myBean2; //This will return true

prototype scope
Prototype creates a brand new instance every time when we call getBean on the ApplicationContext.

     MyBean myBean1 = context.getBean("myBean");
     MyBean myBean2 = context.getBean("myBean");
     myBean1 == myBean2; //This will return false.


How to define the bean scope

1) In bean configuration file
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
      
    <bean id="myBean" class="com.MyBean" scope="session"/>
      
</beans>

2) Using annotations

@Service
@Scope("session")
public class MyBean {
     //Some code
}
Related Posts Plugin for WordPress, Blogger...