xml配置如下
<bean id="newsBean" class="com.tz.test.FXNewsBean" scope="prototype"></bean>
<bean id="mockPersister" class="com.tz.test.MockNewPersister">
<property name="newsBean" ref="newsBean"></property>
<!-- <lookup-method name="getNewsBean" bean="newsBean"/> -->
</bean>
相关类如下
public class MockNewPersister implements IFXNewsPersister {
private FXNewsBean newsBean;
public void persisterNews(FXNewsBean newsBean){
persisterNews();
}
public void persisterNews() {
System.out.println(getNewsBean());
}
/**
* 获取newsBean
* @return newsBean newsBean
*/
public FXNewsBean getNewsBean() {
return newsBean;
}
/**
* 设置newsBean
* @param newsBean newsBean
*/
public void setNewsBean(FXNewsBean newsBean) {
this.newsBean = newsBean;
}
}
测试代码如下
ApplicationContext ctx = new ClassPathXmlApplicationContext("test.xml");
MockNewPersister mock = (MockNewPersister) ctx.getBean("mockPersister");
MockNewPersister mock2 = (MockNewPersister) ctx.getBean("mockPersister");
mock.persisterNews();
mock2.persisterNews();
mock.persisterNews();
打印结果如下
com.tz.test.FXNewsBean@59465d7d
com.tz.test.FXNewsBean@59465d7d
com.tz.test.FXNewsBean@59465d7d
newsBean被配置为prototype,那么容器每次给出的newsBean实例应该是不一样的,但是为什么最后打印的都是相同的呢?
原因不在于newsBean的scope是否是prototype的,而在于实例的取得方式。容器将一个FXNewsBean的实例注入到MockNewPersister之后,MockNewPersister会一直持有这个FXNewsBean实例的引用。虽然每次输出都调用了getNewsBean()方法返回了FXNewsBean的实例,但实际上每次返回的都是MockNewPersister持有的容器第一次注入的实例。换句话说,第一次实例注入后MockNewPersister再也没有重新向容器申请新的实例。所以,容器也不会重新为其注入新的FXNewsBean类型的实例。
解决问题的关键在于保证getNewsBean()方法每次从容器中取得新的FXNewsBean实例,而不是每次都返回其持有的单一实例。
解决方法之一是修改xml配置
<bean id="newsBean" class="com.tz.test.FXNewsBean" scope="prototype"></bean>
<bean id="mockPersister" class="com.tz.test.MockNewPersister">
<lookup-method name="getNewsBean" bean="newsBean"/>
</bean>
这种方式称为方法注入,通过name属性指定需要注入的方法名,bean属性指定需要注入的对象,当
getNewsBean()方法被调用时,容器可以每次返回一个新的FXNewsBean类型的实例。
以下是修改后的输出
com.tz.test.FXNewsBean@331545ab
com.tz.test.FXNewsBean@3990f7c0
com.tz.test.FXNewsBean@5c797bc6
解决方法之二是实现BeanFactoryAware接口
将MockNewPersister类修改如下
public class MockNewPersister implements IFXNewsPersister, BeanFactoryAware {
private BeanFactory beanFactory;
public void persisterNews(FXNewsBean newsBean) {
persisterNews();
}
public void persisterNews() {
System.out.println(getNewsBean());
}
public FXNewsBean getNewsBean() {
return (FXNewsBean) beanFactory.getBean("newsBean");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
xml配置文件修改如下
<bean id="newsBean" class="com.tz.test.FXNewsBean" scope="prototype"></bean>
<bean id="mockPersister" class="com.tz.test.MockNewPersister">
<!-- <property name="newsBean" ref="newsBean"></property> -->
<!-- <lookup-method name="getNewsBean" bean="newsBean"/> -->
</bean>
输出如下
com.tz.test.FXNewsBean@2d0e39e6
com.tz.test.FXNewsBean@fb4226
com.tz.test.FXNewsBean@6fb3cd4a
容器在实例化实现了该接口的bean定义的过程中,会自动将容器本身注入该bean。这样该bean就持有了它所处的BeanFactory的引用。实际上方法一的方法注入动态生成的子类,完成的是类似逻辑,只不过实现细节不同。