在上一篇文章中为大家介绍了spring中的享元模式设计思想: 链接:juejin.cn/post/686752…
其中引申出来一个问题:单例bean引用原型bean的问题,即spring中生命周期长的对象,怎么保证依赖的生命周期短的对象,该对象在不同生命周期内,是不同的?
在上篇文章中我们使用了方法注入的方式来解决这个问题,今天我们看一下另外一种方式——scoped-proxy
先上代码,看效果:
spring.xml
<bean id="singletonReferencePrototype" class="org.springframework.context.test.bean.SingletonReferencePrototype">
<property name="myTestBean" ref="myTestBean"></property>
</bean>
<bean id="myTestBean" class="org.springframework.context.test.bean.MyTestBean" scope="prototype">
<property name="userId" value="1"></property>
<property name="age" value="18"></property>
<property name="userName" value="akun" ></property>
<aop:scoped-proxy></aop:scoped-proxy>
</bean>
我们定义了一个singletonReferencePrototype一个类,默认是单例bean,其中引用了一个属性
再来看测试代码:
public class SingletonReferencePrototype {
private MyTestBean myTestBean;
public MyTestBean getMyTestBean() {
System.out.println(myTestBean.hashCode());
return myTestBean;
}
public void setMyTestBean(MyTestBean myTestBean) {
this.myTestBean = myTestBean;
}
public void soutName(){
System.out.println(myTestBean);
System.out.println(myTestBean);
}
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.loadBeanDefinitions(new ClassPathResource("spring.xml"));
SingletonReferencePrototype referencePrototype = (SingletonReferencePrototype) beanFactory.getBean("singletonReferencePrototype");
//System.out.println(referencePrototype.getMyTestBean() == referencePrototype.getMyTestBean());
System.out.println(referencePrototype.getMyTestBean());
System.out.println(referencePrototype.getMyTestBean());
}
}
运行main方法:得到测试结果
跟我们想象中一样我们看到打印出来的两个对象的地址并不一样。
这里请注意个问题,我们在getMyTestBean()方法时打印出了对象的hashCode,
发现两个myTestBean的hashCode是一样的,其实我们在代码里面注释了一行,感兴趣的同学可以将这行代码的注释放开,发现打印出来是true。
有心的同学可能会发现这里的问题,为什么两个对象 == 的时候内存地址是一样的才会打印出true,为什么后面打印出两个对象的地址是不一样的呢?
其实笔者在这里的时候也有这样的疑问,我们来看下官方的解释:
When declaring <aop:scoped-proxy/> against a bean of scope prototype, every method call on the shared proxy leads to the creation of a new target instance to which the call is then being forwarded.
意思就是在scope为prototype的bean声明里面声明了<aop:scoped-proxy/>的对象,实际上spring会为该对象创建一个代理对象,当该对象的每一个方法被调用时都会导致创建一个新的该对象实例,调用的方法也都会转发到新对象实例上面去。
我们在回头看一下,当System.out.println(referencePrototype.getMyTestBean())时,实际上会先调用myTestBean的toString()方法,按照上面的说法,就会导致导致代理对象创建一个新对象实例,然后再toString(),最终导致打印出来的两个对象的内存地址是不一样的。
到这里就清晰了,其实对象都是那个代理对象而已,所以 == 为true,只是调方法时,代理对象会创建一个新的对象实例,最终调用的新对象的方法而已。
附录
spring地址(官网是最好的学习资料):
源码分析spring的scoped-proxy