文章目录
- 一、目标:通过三级缓存解决循环依赖
- 二、设计:通过三级缓存解决循环依赖
- 2.1 通过三级缓存解决循环依赖
- 2.2 尝试使用一级缓存解决循环依赖
- 三、实现:通过三级缓存解决循环依赖
- 3.1 工程结构
- 3.2 通过三级缓存解决循环依赖类图
- 3.3 设置三级缓存
- 3.3.1 对象工厂
- 3.3.2 设置三级缓存
- 3.4 提前暴露对象
- 3.4.1 实例化感知对象处理
- 3.4.2 默认自动代理创建者
- 3.4.3 实现默认bean创建的抽象bean工厂超类
- 四、测试:通过三级缓存解决循环依赖
- 4.1 添加测试配置
- 4.1.1 老公类
- 4.1.2 媳妇类
- 4.1.3 婆婆接口
- 4.1.4 婆婆代理类
- 4.1.5 切面
- 4.1.6 Spring属性配置文件
- 4.2 单元测试
- 五、总结:通过三级缓存解决循环依赖
一、目标:通过三级缓存解决循环依赖
💡 如何解决类与类之间的循环依赖?
- 在目前的 Spring 框架中,如果你配置了
A、B
两个 Bean 对象互相依赖,那么立刻会抛出java.lang.StackOverflowError
,为什么?- 因为 A 创建时需要依赖 B 创建,而 B 的创建又依赖于 A 创建,就这样死循环了。
- 循环依赖 基本可以说是 Spring 中经典的实现,所要解决的场景主要三种情况。
- 循环依赖主要分为三种:自身依赖于自身、互相循环依赖、多组循环依赖。
- 但无论循环依赖的数量有多少,循环依赖的本质是一样。
- 就是你的完整创建依赖于我,而我的完整创建也依赖于你,但我们互相没法解耦,最终导致依赖创建失败。
- 所以需要 Spring 提供除了构造函数注入和原型注入外的,
setter
循环依赖注入解决方案。
二、设计:通过三级缓存解决循环依赖
2.1 通过三级缓存解决循环依赖
💡 设计:通过三级缓存解决循环依赖
- 用于解决循环依赖需要用到三个缓存,这三个缓存分别存放:
成品对象、半成品对象(未填充属性值)、代理对象
,分阶段存放对象内容,来解决循环依赖问题。
- 需要知道核心原理:用于解决循环依赖就必须是三级缓存吗?二级缓存行吗?一级缓存行吗?
- 其实都能解决。但是 Spring 框架的实现要保证几个事情。如:
- 只有一级缓存处理流程没法拆分,复杂度也会增加,同时半成品对象可能会有空指针异常。
- 而将半成品与成品对象分开,处理起来也更加优雅、简单、易扩展。
- 另外 Spring 的两大特性中不仅有 IOC,还有 AOP,也就是基于字节码增强后的方法,该存放到哪。
- 而三级缓存最主要,要解决的循环依赖就是对 AOP 的处理,但如果把 AOP 代理对象的创建提前,那么二级缓存也一样可以解决。
- 但是,这就违背了 Spring 创建对象的原则,Spring 更喜欢把所有的普通 Bean 都初始化完成,再处理代理对象的初始化。
- 其实都能解决。但是 Spring 框架的实现要保证几个事情。如:
- 思考:如果有对象不只是简单的对象,还有代理对象,还有 AOP 应用,要怎么处理这样的依赖问题。
- 关于循环依赖在目前的 Spring 框架中,主要就是对于创建的提前暴露。
- 如果是工厂对象则会使用
getEarlyBeanReference
逻辑提前将工厂对象存放到三级缓存中。 - 等到后续获取对象的时候实际拿到的是工厂对象中
getObject
,这个才是最终的实际对象。
- 如果是工厂对象则会使用
- 在创建对象的
AbstractAutowireCapableBeanFactory#doCreateBean
方法中,提前暴露对象以后。- 就可以通过接下来的流程,
getSingleton
从三个缓存中以此寻找对象。 - 一级、二级如果有则直接取走,如果对象是三级缓存中则会从三级缓存中获取后并删掉工厂对象,把实际对象放到二级缓存中。
- 就可以通过接下来的流程,
- 最后是关于单例的对象的注册操作,这个注册操作就是把真实的实际对象放到一级缓存中,因为此时它已经是一个成品对象了。
2.2 尝试使用一级缓存解决循环依赖
- 如果仅以一级缓存解决循环依赖,那么在实现上可以通过 A 对象
newInstance
创建且未填充属性后,直接放入缓存中。 - 在 A 对象的属性填充 B 对象时,如果缓存中不能获取到 B 对象,则开始创建 B 对象,同样创建完成后,把 B 对象填充到缓存中。
- 接下来就开始对 B 对象的属性进行填充,恰好这会可以从缓存中拿到半成品的 A 对象,那么这个时候 B 对象的属性就填充完了。
- 最后返回来继续完成 A 对象的属性填充,把实例化后并填充了属性的 B 对象赋值给 A 对象的
b
属性,这样就完成了一个循环依赖操作。
CircleTest.java
package com.lino.springframework.test;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @description: 循环依赖案例
*/
public class CircleTest {
private final static Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
public static void main(String[] args) throws Exception {
System.out.println(getBean(B.class).getA());
System.out.println(getBean(A.class).getB());
}
private static <T> T getBean(Class<T> beanClass) throws Exception {
String beanName = beanClass.getSimpleName().toLowerCase();
if (singletonObjects.containsKey(beanName)) {
return (T) singletonObjects.get(beanName);
}
// 实例化对象入缓存
Object obj = beanClass.newInstance();
singletonObjects.put(beanName, obj);
// 属性填充补全对象
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
Class<?> fieldClass = field.getType();
String fieldBeanName = fieldClass.getSimpleName().toLowerCase();
field.set(obj, singletonObjects.containsKey(fieldBeanName) ? singletonObjects.get(fieldBeanName) : getBean(fieldClass));
field.setAccessible(false);
}
return (T) obj;
}
}
class A {
private B b;
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
}
class B {
private A a;
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
}
测试结果
com.lino.springframework.test.A@266474c2
com.lino.springframework.test.B@6f94fa3e
- 从测试效果和截图依赖过程中可以看到,一级缓存也可以解决简单场景的循环依赖问题。
- 其实
getBean
,是整个解决循环依赖的核心内容,A 创建后填充属性时依赖 B,那么就去创建 B,在创建 B 开始填充时发现依赖于 A,但此时 A 这个半成品对象已经存放在缓存到singletonObjects
中了,所以 B 可以正常创建,再通过递归把 A 也创建完整了。
三、实现:通过三级缓存解决循环依赖
3.1 工程结构
spring-step-16
|-src
|-main
| |-java
| |-com.lino.springframework
| |-aop
| | |-aspectj
| | | |-AspectJExpressionPointcut.java
| | | |-AspectJExpressionPointcutAdvisor.java
| | |-framework
| | | |-adapter
| | | | |-MethodBeforeAdviceInterceptor.java
| | | |-autoproxy
| | | | |-DefaultAdvisorAutoProxyCreator.java
| | | |-AopProxy.java
| | | |-Cglib2AopProxy.java
| | | |-JdkDynamicAopProxy.java
| | | |-ProxyFactory.java
| | | |-ReflectiveMethodInvocation.java
| | |-AdvisedSupport.java
| | |-Advisor.java
| | |-BeforeAdvice.java
| | |-ClassFilter.java
| | |-MethodBeforeAdvice.java
| | |-MethodMatcher.java
| | |-Pointcut.java
| | |-PointcutAdvisor.java
| | |-TargetSource.java
| |-beans
| | |-factory
| | | |-annotation
| | | | |-Autowired.java
| | | | |-AutowiredAnnotationBeanPostProcessor.java
| | | | |-Qualifier.java
| | | | |-Value.java
| | | |-config
| | | | |-AutowireCapableBeanFactory.java
| | | | |-BeanDefinition.java
| | | | |-BeanFactoryPostProcessor.java
| | | | |-BeanPostProcessor.java
| | | | |-BeanReference.java
| | | | |-ConfigurableBeanFactory.java
| | | | |-InstantiationAwareBeanPostProcessor.java
| | | | |-SingletonBeanRegistry.java
| | | |-support
| | | | |-AbstractAutowireCapableBeanFactory.java
| | | | |-AbstractBeabDefinitionReader.java
| | | | |-AbstractBeabFactory.java
| | | | |-BeabDefinitionReader.java
| | | | |-BeanDefinitionRegistry.java
| | | | |-CglibSubclassingInstantiationStrategy.java
| | | | |-DefaultListableBeanFactory.java
| | | | |-DefaultSingletonBeanRegistry.java
| | | | |-DisposableBeanAdapter.java
| | | | |-FactoryBeanRegistrySupport.java
| | | | |-InstantiationStrategy.java
| | | | |-SimpleInstantiationStrategy.java
| | | |-xml
| | | | |-XmlBeanDefinitionReader.java
| | | |-Aware.java
| | | |-BeanClassLoaderAware.java
| | | |-BeanFactory.java
| | | |-BeanFactoryAware.java
| | | |-BeanNameAware.java
| | | |-ConfigurableListableBeanFactory.java
| | | |-DisposableBean.java
| | | |-FactoryBean.java
| | | |-HierarcgicalBeanFactory.java
| | | |-InitializingBean.java
| | | |-ListableBeanFactory.java
| | | |-ObjectFactory.java
| | | |-PropertyPlaceholderConfigurer.java
| | |-BeansException.java
| | |-PropertyValue.java
| | |-PropertyValues.java
| |-context
| | |-annotation
| | | |-ClassPathBeanDefinitionScanner.java
| | | |-ClassPathScanningCandidateComponentProvider.java
| | | |-Scope.java
| | |-event
| | | |-AbstractApplicationEventMulticaster.java
| | | |-ApplicationContextEvent.java
| | | |-ApplicationEventMulticaster.java
| | | |-ContextclosedEvent.java
| | | |-ContextRefreshedEvent.java
| | | |-SimpleApplicationEventMulticaster.java
| | |-support
| | | |-AbstractApplicationContext.java
| | | |-AbstractRefreshableApplicationContext.java
| | | |-AbstractXmlApplicationContext.java
| | | |-ApplicationContextAwareProcessor.java
| | | |-ClassPathXmlApplicationContext.java
| | |-ApplicationContext.java
| | |-ApplicationContextAware.java
| | |-ApplicationEvent.java
| | |-ApplicationEventPublisher.java
| | |-ApplicationListener.java
| | |-ConfigurableApplicationContext.java
| |-core.io
| | |-ClassPathResource.java
| | |-DefaultResourceLoader.java
| | |-FileSystemResource.java
| | |-Resource.java
| | |-ResourceLoader.java
| | |-UrlResource.java
| |-stereotype
| | |-Component.java
| |-util
| | |-ClassUtils.java
| | |-StringValueResolver.java
|-test
|-java
|-com.lino.springframework.test
|-bean
| |-Husband.java
| |-HusbandMother.java
| |-IMother.java
| |-SpouseAdvice.java
| |-Wife.java
|-ApiTest.java
|-CircleTest.java
|-resources
|-spring.xml
3.2 通过三级缓存解决循环依赖类图
- 循环依赖的黑犀牛功能实现主要包括
DefaultSingletonBeanRegistry
提供三级缓存。singletonObjects
、earlySingletonObjects
、singletonFactiries
,分别存放成品对象、半成品对象和工厂对象。- 同时包装三个缓存提供方法:
getSingleton
、registerSingleton
、addSingletonFactory
,这样使用方就可以分别在不同时间段存放和获取对应的对象。
- 在
AbstractAutowireCapableBeanFactory
的doCreateBean
方法中,提供了关于提前暴露对象的操作。addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, beanDefinition, finalBean))
- 以及后续获取对象和注册对象的操作:
exposedObject = getSingleton(beanName)
、registerSingleton(beanName, exposedObject)
。 - 经过这样的处理就可以完成对复杂场景循环依赖的操作。
- 另外在
DefaultAdvisorAutoProxyCreator
提供的切面服务中,也需要实现接口InstantiationAwareBeanPostProcessor
新增的getEarlyBeanReference
方法,便于把依赖的切面对象也能存放到三级缓存中,处理对应的循环依赖。
3.3 设置三级缓存
3.3.1 对象工厂
ObjectFactory.java
package com.lino.springframework.beans.factory;
import com.lino.springframework.beans.BeansException;
/**
* @description: 对象工厂
*/
public interface ObjectFactory<T> {
/**
* 获取对象
*
* @return 泛型对象
* @throws BeansException 异常
*/
T getObject() throws BeansException;
}
3.3.2 设置三级缓存
DefaultSingletonBeanRegistry.java
package com.lino.springframework.beans.factory.support;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.DisposableBean;
import com.lino.springframework.beans.factory.ObjectFactory;
import com.lino.springframework.beans.factory.config.SingletonBeanRegistry;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* @description: 通用的注册表实现
*/
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
protected static final Object NULL_OBJECT = new Object();
/**
* 一级缓存,普通对象
*/
private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
/**
* 二级缓存,提前暴露对象,没有完全实例化的对象
*/
protected final Map<String, Object> earlySingletonObjects = new HashMap<>();
/**
* 三级缓存,存放代理对象
*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();
private final Map<String, DisposableBean> disposableBeans = new HashMap<>();
@Override
public Object getSingleton(String beanName) {
Object singletonObject = singletonObjects.get(beanName);
if (null == singletonObject) {
singletonObject = earlySingletonObjects.get(beanName);
// 判断二级缓存中是否有对象,这个对象就是代理对象,因为只有代理对象才会放到三级缓存中
if (null == singletonObject) {
ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// 把三级缓存中的代理对象中的真实对象获取出来,放入二级缓存中
earlySingletonObjects.put(beanName, singletonObject);
singletonFactories.remove(beanName);
}
}
}
return singletonObject;
}
@Override
public void registerSingletonBean(String beanName, Object singletonObject) {
singletonObjects.put(beanName, singletonObject);
earlySingletonObjects.remove(beanName);
singletonFactories.remove(beanName);
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
}
}
public void registerDisposableBean(String beanName, DisposableBean bean) {
disposableBeans.put(beanName, bean);
}
public void destroySingletons() {
Set<String> keySet = this.disposableBeans.keySet();
Object[] disposableBeanNames = keySet.toArray();
for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
Object beanName = disposableBeanNames[i];
DisposableBean disposableBean = disposableBeans.remove(beanName);
try {
disposableBean.destroy();
} catch (Exception e) {
throw new BeansException("Destroy method on bean with name '" + beanName + "' threw an exception", e);
}
}
}
}
- 在用于提供单例对象注册操作的
DefaultSingletonBeanRegistry
类中,共有三个缓存对象的属性:singletonObjects
、earlySingletonObjects
、singletonFactories
。- 用于存放不同类型的对象:单例对象、早期的半成品单例对象、单例工厂对象。
- 紧接着在这三个缓存对象下提供了获取、添加和注册不同对象的方法,包括:
getSingleton
、registerSingletonBean
、addSingletonFactory
。- 后面的两个方法都比较简单,主要是
getSingleton
的操作,它是一层层处理不同时期的单例对象,直至拿到有效的对象。
- 后面的两个方法都比较简单,主要是
3.4 提前暴露对象
3.4.1 实例化感知对象处理
InstantiationAwareBeanPostProcessor.java
package com.lino.springframework.beans.factory.config;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValues;
/**
* @description: 实例化感知对象处理
*/
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
...
/**
* 在 Spring 中由 SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference 提供
*
* @param bean 对象
* @param beanName 对象名称
* @return 二级缓存对象
*/
default Object getEarlyBeanReference(Object bean, String beanName) {
return bean;
}
}
- 添加
getEarlyBeanReference
缓存二级缓存对象方法
3.4.2 默认自动代理创建者
DefaultAdvisorAutoProxyCreator.java
package com.lino.springframework.aop.framework.autoproxy;
import com.lino.springframework.aop.*;
import com.lino.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import com.lino.springframework.aop.framework.ProxyFactory;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.BeanFactory;
import com.lino.springframework.beans.factory.BeanFactoryAware;
import com.lino.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import com.lino.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* @description: 默认自动代理创建者
*/
public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {
private DefaultListableBeanFactory beanFactory;
private final Set<Object> earlyProxyReferences = Collections.synchronizedSet(new HashSet<>());
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (DefaultListableBeanFactory) beanFactory;
}
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
private boolean isInfrastructureClass(Class<?> beanClass) {
return Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass);
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (!earlyProxyReferences.contains(beanName)) {
return wrapIfNecessary(bean, beanName);
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName) {
if (isInfrastructureClass(bean.getClass())) {
return bean;
}
Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();
for (AspectJExpressionPointcutAdvisor advisor : advisors) {
ClassFilter classFilter = advisor.getPointcut().getClassFilter();
// 过滤匹配类
if (!classFilter.matches(bean.getClass())) {
continue;
}
AdvisedSupport advisedSupport = new AdvisedSupport();
TargetSource targetSource = new TargetSource(bean);
advisedSupport.setTargetSource(targetSource);
advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
advisedSupport.setProxyTargetClass(true);
// 返回代理对象
return new ProxyFactory(advisedSupport).getProxy();
}
return bean;
}
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
earlyProxyReferences.add(beanName);
return wrapIfNecessary(bean, beanName);
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException {
return pvs;
}
}
3.4.3 实现默认bean创建的抽象bean工厂超类
AbstractAutowireCapableBeanFactory.java
package com.lino.springframework.beans.factory.support;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.*;
import com.lino.springframework.beans.factory.config.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* @description: 实现默认bean创建的抽象bean工厂超类
*/
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
private InstantiationStrategy instantiationStrategy = new SimpleInstantiationStrategy();
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {
// 判断是否返回代理 Bean 对象
Object bean = resolveBeforeInstantiation(beanName, beanDefinition);
if (null != bean) {
return bean;
}
return doCreateBean(beanName, beanDefinition, args);
}
protected Object doCreateBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
Object bean = null;
try {
// 实例化Bean
bean = createBeanInstance(beanDefinition, beanName, args);
// 处理循环依赖,将实例化后的Bean对象提前放入缓存中暴露出来
if (beanDefinition.isSingleton()) {
Object finalBean = bean;
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, beanDefinition, finalBean));
}
// 实例化后判断
boolean continueWithPropertyPopulation = applyBeanPostProcessorsAfterInstantiation(beanName, bean);
if (!continueWithPropertyPopulation) {
return bean;
}
// 在设置Bean属性之前,允许 BeanPostProcessor修改属性值
applyBeanPostProcessorsBeforeApplyingPropertyValues(beanName, bean, beanDefinition);
// 给bean填充属性
applyPropertyValues(beanName, bean, beanDefinition);
// 执行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置处理方法
bean = initializeBean(beanName, bean, beanDefinition);
} catch (Exception e) {
throw new BeansException("Instantiation of bean failed", e);
}
// 注册实现 DisposableBean 接口的 Bean 对象
registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);
// 判断 SCOPE_SINGLETON、SCOPE_PROTOTYPE
Object exposedObject = bean;
if (beanDefinition.isSingleton()) {
// 获取代理对象
exposedObject = getSingleton(beanName);
registerSingletonBean(beanName, exposedObject);
}
return exposedObject;
}
protected Object getEarlyBeanReference(String beanName, BeanDefinition beanDefinition, Object bean) {
Object exposedObject = bean;
for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
exposedObject = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).getEarlyBeanReference(exposedObject, beanName);
if (null == exposedObject) {
return exposedObject;
}
}
}
return exposedObject;
}
...
}
- 在
AbstractAutowireCapableBeanFactory#doCreateBean
的方法中主要是扩展了对象的提前暴露addSingletonFactory
,和单例对象的获取getSingleton
,以及注册操作registerSingletonBean
。 getEarlyBeanReference
方法就是定义在如 AOP 切面中这样的代理对象。
四、测试:通过三级缓存解决循环依赖
4.1 添加测试配置
4.1.1 老公类
Husband.java
package com.lino.springframework.test.bean;
/**
* @description: 老公类
*/
public class Husband {
private Wife wife;
public String queryWife() {
return "Husband.wife";
}
public Wife getWife() {
return wife;
}
public void setWife(Wife wife) {
this.wife = wife;
}
}
4.1.2 媳妇类
Wife.java
package com.lino.springframework.test.bean;
/**
* @description: 媳妇类
*/
public class Wife {
private Husband husband;
private IMother mother;
public String queryHusband() {
return "Wife.husband、Mother.callMother: " + mother.callMother();
}
public Husband getHusband() {
return husband;
}
public void setHusband(Husband husband) {
this.husband = husband;
}
public IMother getMother() {
return mother;
}
public void setMother(IMother mother) {
this.mother = mother;
}
}
4.1.3 婆婆接口
IMother.java
package com.lino.springframework.test.bean;
/**
* @description: 婆婆接口
*/
public interface IMother {
String callMother();
}
4.1.4 婆婆代理类
HusbandMother.java
package com.lino.springframework.test.bean;
import com.lino.springframework.beans.factory.FactoryBean;
import java.lang.reflect.Proxy;
/**
* @description: 老公婆婆类
*/
public class HusbandMother implements FactoryBean<IMother> {
@Override
public IMother getObject() throws Exception {
return (IMother) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{IMother.class},
(proxy, method, args) -> "婚后媳妇妈妈的职责被婆婆代理了!" + method.getName());
}
@Override
public Class<?> getObjectType() {
return IMother.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
4.1.5 切面
SpouseAdvice.java
package com.lino.springframework.test.bean;
import com.lino.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
/**
* @description: 拦截器
*/
public class SpouseAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("关怀小两口(切面):" + method);
}
}
4.1.6 Spring属性配置文件
spring.xml
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="husband" class="com.lino.springframework.test.bean.Husband">
<property name="wife" ref="wife"/>
</bean>
<bean id="husbandMother" class="com.lino.springframework.test.bean.HusbandMother"/>
<bean id="wife" class="com.lino.springframework.test.bean.Wife">
<property name="husband" ref="husband"/>
<property name="mother" ref="husbandMother"/>
</bean>
<!--AOP 配置,验证三级缓存 -->
<bean class="com.lino.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<bean id="beforeAdvice" class="com.lino.springframework.test.bean.SpouseAdvice"/>
<bean id="methodInterceptor" class="com.lino.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor">
<property name="advice" ref="beforeAdvice"/>
</bean>
<bean id="pointcutAdvisor" class="com.lino.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
<property name="expression" value="execution(* com.lino.springframework.test.bean.Wife.*(..))"/>
<property name="advice" ref="methodInterceptor"/>
</bean>
</beans>
4.2 单元测试
ApiTest.java
@Test
public void test_autoProxy() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
Husband husband = applicationContext.getBean("husband", Husband.class);
Wife wife = applicationContext.getBean("wife", Wife.class);
System.out.println("老公的媳妇:" + husband.queryWife());
System.out.println("媳妇的老公:" + wife.queryHusband());
}
测试结果
老公的媳妇:Husband.wife
关怀小两口(切面):public java.lang.String com.lino.springframework.test.bean.Wife.queryHusband()
媳妇的老公:Wife.husband、Mother.callMother: 婚后媳妇妈妈的职责被婆婆代理了!callMother
- 测试结果看,无论是简单对象依赖,还是代理工程对象,或者 AOP 切面对象,都可以在三级缓存下解决循环依赖的问题。
- 此外从运行截图
DefaultSingletonBeanRegistry#getSingleton
中也可以看到需要三级缓存存放工厂对象的类,都会使用到getObject
获取真实对象,并随后存入半成品对象earlySingletonObjects
中以及移除工厂对象。
五、总结:通过三级缓存解决循环依赖
- Spring 中所有的功能都是以解决 Java 编程中的特性而存在的,就像我们处理的循环依赖,如果没有 Spring 框架的情况下,可能我们也会尽可能避免写出循环依赖的操作,因为在没有经过加工处理后,这样的依赖关系肯定会报错的。
- 这也是程序从 能用 到 好用 的升级。
- 在解决循环依赖的核心流程中,主要是提前暴露对象的设计,以及建立三级缓存的数据结构来存放不同时期的对象。
- 如果说没有如切面和工厂中的代理对象,那么二级缓存也就可以解决了,哪怕是只有一级缓存。
- 但为了设计上的合理和可扩展性,所以创建了三级缓存来放置不同时期的对象。