For most application
scenarios, the majority of the beans in the container will be singletons.
When a singleton bean
needs to collaborate with another singleton bean, or a non-singleton bean needs
to collaborate with another non-singleton bean, the typical and common approach
of handling this dependency by defining one bean to be a property of the other
is quite adequate.
There is a problem
when the bean lifecycles are different. Consider a singleton bean A which needs
to use a non-singleton (prototype) bean B, perhaps on each method invocation on
A.
The container will
only create the singleton bean A once, and thus only get the opportunity to set
the properties once.
There is no
opportunity for the container to provide bean A with a new instance of bean B
every time one is needed.
There are two
solutions to this issue:
1.
Implementing BeanFactoryAware/ApplicationContextAware
by bean A;
2.
Using Lookup method
injection.
Here is some code
examples:
Bean A
public class A
{
private
String text;
private B
b;
public void
setB(B b) {
this.b =
b;
}
public B getB()
{
return
b;
}
public String
getText() {
return
text;
}
public void
setText(String text) {
this.text =
text;
}
}
Bean B
public class B {
private String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
spring-config.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-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<bean
id="a" class="ua.cn.dmitrykrivenko.spring.example.A"
scope="singleton" >
<property name="text" value="text A"/>
<property name="b">
<ref
bean="b"/>
</property>
</bean>
<bean
id="b" class="ua.cn.dmitrykrivenko.spring.example.B"
scope="prototype">
<property name="text" value="text B"/>
</bean>
</beans>
And let's create some test class:
public class
Test {
public static
void main(String[] args) {
ApplicationContext ctx = new
ClassPathXmlApplicationContext("spring-config.xml");
A a =
ctx.getBean("a", A.class);
System.out.println("a before: " + a.getText());
System.out.println("b before: " + a.getB().getText());
a.setText("text A1");
a.getB().setText("text B1");
a =
ctx.getBean("a", A.class);
System.out.println("a after: " + a.getText());
System.out.println("b after: " + a.getB().getText());
}
}
The output will be looks like this:
a before: text
A
b before: text
B
a after: text
A1
b after: text
B1
As you see inside singleton bean A another bean
B("prototype") is used as singleton too.
1. Implementing BeanFactoryAware/ApplicationContextAware by bean A
Change bean A
public class A
implements ApplicationContextAware {
private
String text;
private
ApplicationContext applicationContext;
public B getB() {
return applicationContext.getBean("b", B.class);
}
public String
getText() {
return
text;
}
public void
setText(String text) {
this.text =
text;
}
public void
setApplicationContext(ApplicationContext ac) throws BeansException {
this.applicationContext = ac;
}
}
and spring-config.xml
<bean
id="a" class="ua.cn.dmitrykrivenko.spring.example.A"
scope="singleton" >
<property name="text" value="text A"/>
</bean>
<bean
id="b" class="ua.cn.dmitrykrivenko.spring.example.B"
scope="prototype">
<property name="text" value="text B"/>
</bean>
And run test class again. You'll see:
a before: text
A
b before: text
B
a after: text
A1
b after: text
B
But this example is generally not a desirable solution
since the business code is then aware of and coupled to the Spring Framework.
Method Injection, a somewhat advanced feature of the Spring IoC container,
allows this use case to be handled in a clean fashion.
2. Lookup method injection
Lookup method injection refers to the ability of the
container to override methods on container managed beans, to return the result
of looking up another named bean in the container. The Spring Framework
implements this method injection by dynamically generating a subclass
overriding the method, using bytecode generation via the CGLIB library.
Change bean A like this
public abstract
class A{
private
String text;
public abstract B getB();
public String
getText() {
return
text;
}
public void
setText(String text) {
this.text =
text;
}
}
or like this
public class
A{
private
String text;
public B
getB(){
return
null;
}
public String
getText() {
return
text;
}
public void
setText(String text) {
this.text =
text;
}
}
and spring-config.xml
<bean
id="a" class="ua.cn.dmitrykrivenko.spring.example.A"
scope="singleton" >
<property name="text" value="text A"/>
<lookup-method
name="getB" bean="b"/>
</bean>
<bean
id="b" class="ua.cn.dmitrykrivenko.spring.example.B"
scope="prototype">
<property name="text" value="text B"/>
</bean>
After running test class again you'll see:
a before: text
A
b before: text
B
a after: text
A1
b after: text
B
That means we get new instance of B every time
("prototype" scope).
If the method is abstract, the dynamically-generated subclass will implement the method. Otherwise, the dynamically-generated subclass will override the concrete method defined in the original class.
If the method is abstract, the dynamically-generated subclass will implement the method. Otherwise, the dynamically-generated subclass will override the concrete method defined in the original class.
[Spring Interview Questions]
We recommend you take Big Data Hadoop class room training at eMexo Technologies in electronic city, Bangalore to learn more about Big Data Hadoop.
0 Comments:
Post a Comment