关于Sping singleton依赖prototype

704 阅读2分钟

在上一篇文章中为大家介绍了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, 发现两个myTestBeanhashCode是一样的,其实我们在代码里面注释了一行,感兴趣的同学可以将这行代码的注释放开,发现打印出来是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())时,实际上会先调用myTestBeantoString()方法,按照上面的说法,就会导致导致代理对象创建一个新对象实例,然后再toString(),最终导致打印出来的两个对象的内存地址是不一样的。

到这里就清晰了,其实对象都是那个代理对象而已,所以 == 为true,只是调方法时,代理对象会创建一个新的对象实例,最终调用的新对象的方法而已。

附录

spring地址(官网是最好的学习资料):

docs.spring.io/spring-fram…

源码分析spring的scoped-proxy

juejin.cn/post/686940…