《Spring揭秘》笔记——prototype作用域的“坑”

来源:互联网 发布:ubuntu登录界面循环 编辑:程序博客网 时间:2024/06/05 14:45

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@59465d7dcom.tz.test.FXNewsBean@59465d7dcom.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@331545abcom.tz.test.FXNewsBean@3990f7c0com.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");}@Overridepublic 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@2d0e39e6com.tz.test.FXNewsBean@fb4226com.tz.test.FXNewsBean@6fb3cd4a
容器在实例化实现了该接口的bean定义的过程中,会自动将容器本身注入该bean。这样该bean就持有了它所处的BeanFactory的引用。实际上方法一的方法注入动态生成的子类,完成的是类似逻辑,只不过实现细节不同。






阅读全文
1 0