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>