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

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的引用。实际上方法一的方法注入动态生成的子类,完成的是类似逻辑,只不过实现细节不同。






  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值