spring系列5-IOC的三级缓存

目录

1. 前言

2. 如何写demo

3. demo

4. 分析demo


 

1. 前言

在博客《spring系列3-IOC的实现》的第3节通过两张流程图大致梳理了IOC主要逻辑,值得关注的是3处红色标注的各级缓存放入处

考虑一下常见问题,加深对IOC三级缓存的理解:

问题1:IOC是如何解决循环依赖的?

比较浅地回答:通过缓存。在对象已实例化,但属性未装配(populate)前,将早期bean放入缓存中,使得递归解决属性注入时,依赖早期bean的其它bean能够拿到早期bean的引用。

问题2:IOC解决循环依赖为什么需要3级缓存,只用1级缓存行不行?只用2级缓存行不行?

根据博客:https://my.oschina.net/u/4340310/blog/4332450

(1)1级缓存不够,原因:如果只有1级缓存,存放了已实例化但未装配属性的bean,值=null的属性可能引发空指针,所以至少需要2级,一级存放完全可用的bean、二级存放早期的bean。

(2)2级缓存不够,参考别人的博文没想明白,只知道与代理、SmartInstantiationAwareBeanPostProcessor接口有关。还是自己动手写用例,通过debug来理解。

2. 如何写demo

研究SmartInstantiationAwareBeanPostProcessor接口

spring系列3-IOC的实现》第3节的第2张流程图的三级缓存放入处代码如下:

在《spring系列3-IOC的实现》第3节的第1张流程图的二级缓存放入处回调getEarlyBeanReference(...)方法,方法内部会调用SmartInstantiationAwareBeanPostProcessor接口的getEarlyBeanReference(...)方法,而上述接口的直接实现类只有2个:AbstractAutoProxyCreator(可能返回代理)、InstantiationAwareBeanPostProcessorAdapter(直接返回bean)。

既然要理解第3级缓存对于代理情况的作用,那就基于AbstractAutoProxyCreator写用例。

ps:如果对advice陌生,可以了解一下《spring系列4-AOP的实现

3. demo

demo很简单,就是Mother类、Child类相互依赖:

//Child类依赖Mother类
public class Child {

	private Mother mother;

	public Mother getMother() {
		return mother;
	}

	public void setMother(Mother mother) {
		this.mother = mother;
	}

}

//Mother类依赖Child类
public class Mother {

	private Child child;

	public Child getChild() {
		return child;
	}

	public void setChild(Child child) {
		this.child = child;
	}

}

//起床BPP处理器,只对Mother类返回advice
public class GetUpPostProcessor extends AbstractAutoProxyCreator {

	@Override
	protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource customTargetSource) throws BeansException {
		if (beanClass.equals(Mother.class)) {
			return new Object[]{new GetUpAdvice()};
		} else {
			return null;
		}
	}

	static class GetUpAdvice implements AfterReturningAdvice {
		@Override
		public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
			System.out.println("Hurry up! You will be late!");
		}
	}
}

public class MainTest {

	@Test
	public void test() {
		BeanFactory bf = new XmlBeanFactory(new ClassPathResource("mytest/ioc/circularrefercence/beanFactoryTest.xml"));
		BeanPostProcessor postProcessor = new GetUpPostProcessor();
		((XmlBeanFactory) bf).addBeanPostProcessor(postProcessor);
		Mother mother = (Mother) bf.getBean("mother");
		System.out.println(mother);
	}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">

	<bean id="mother" class="com.mytest.ioc.circularreference.Mother">
		<property name="child" ref="child"/>
	</bean>

	<bean id="child" class="com.mytest.ioc.circularreference.Child">
		<property name="mother" ref="mother"/>
	</bean>

</beans>

4. 分析demo

获取bean的流程如下:

 

继续回答问题2(2):2级缓存不够,原因:2th级缓存用于存放proxy或未注入属性的bean,3th缓存用于存放生产2th缓存的工厂。

是否可以将3th缓存生产的内容直接放入2th缓存,不用3th缓存记录工厂呢?我想应该是不行的,工厂生产的proxy无法装配属性,调用populateBean方法会错误吧。

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值