手写Spring:第17章-通过三级缓存解决循环依赖

文章目录

  • 一、目标:通过三级缓存解决循环依赖
  • 二、设计:通过三级缓存解决循环依赖
    • 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:第17章-通过三级缓存解决循环依赖_第1张图片

  • 循环依赖主要分为三种:自身依赖于自身、互相循环依赖、多组循环依赖。
  • 但无论循环依赖的数量有多少,循环依赖的本质是一样。
    • 就是你的完整创建依赖于我,而我的完整创建也依赖于你,但我们互相没法解耦,最终导致依赖创建失败。
  • 所以需要 Spring 提供除了构造函数注入和原型注入外的,setter 循环依赖注入解决方案。

二、设计:通过三级缓存解决循环依赖

2.1 通过三级缓存解决循环依赖

设计:通过三级缓存解决循环依赖

  • 用于解决循环依赖需要用到三个缓存,这三个缓存分别存放:
    • 成品对象、半成品对象(未填充属性值)、代理对象,分阶段存放对象内容,来解决循环依赖问题。
  • 需要知道核心原理:用于解决循环依赖就必须是三级缓存吗?二级缓存行吗?一级缓存行吗?
    • 其实都能解决。但是 Spring 框架的实现要保证几个事情。如:
      • 只有一级缓存处理流程没法拆分,复杂度也会增加,同时半成品对象可能会有空指针异常。
      • 而将半成品与成品对象分开,处理起来也更加优雅、简单、易扩展。
    • 另外 Spring 的两大特性中不仅有 IOC,还有 AOP,也就是基于字节码增强后的方法,该存放到哪。
      • 而三级缓存最主要,要解决的循环依赖就是对 AOP 的处理,但如果把 AOP 代理对象的创建提前,那么二级缓存也一样可以解决。
      • 但是,这就违背了 Spring 创建对象的原则,Spring 更喜欢把所有的普通 Bean 都初始化完成,再处理代理对象的初始化。
  • 思考:如果有对象不只是简单的对象,还有代理对象,还有 AOP 应用,要怎么处理这样的依赖问题。

手写Spring:第17章-通过三级缓存解决循环依赖_第2张图片

  • 关于循环依赖在目前的 Spring 框架中,主要就是对于创建的提前暴露。
    • 如果是工厂对象则会使用 getEarlyBeanReference 逻辑提前将工厂对象存放到三级缓存中。
    • 等到后续获取对象的时候实际拿到的是工厂对象中 getObject,这个才是最终的实际对象。
  • 在创建对象的 AbstractAutowireCapableBeanFactory#doCreateBean 方法中,提前暴露对象以后。
    • 就可以通过接下来的流程,getSingleton 从三个缓存中以此寻找对象。
    • 一级、二级如果有则直接取走,如果对象是三级缓存中则会从三级缓存中获取后并删掉工厂对象,把实际对象放到二级缓存中。
  • 最后是关于单例的对象的注册操作,这个注册操作就是把真实的实际对象放到一级缓存中,因为此时它已经是一个成品对象了。

2.2 尝试使用一级缓存解决循环依赖

手写Spring:第17章-通过三级缓存解决循环依赖_第3张图片

  • 如果仅以一级缓存解决循环依赖,那么在实现上可以通过 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

手写Spring:第17章-通过三级缓存解决循环依赖_第4张图片

  • 从测试效果和截图依赖过程中可以看到,一级缓存也可以解决简单场景的循环依赖问题。
  • 其实 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 通过三级缓存解决循环依赖类图

手写Spring:第17章-通过三级缓存解决循环依赖_第5张图片

  • 循环依赖的黑犀牛功能实现主要包括 DefaultSingletonBeanRegistry 提供三级缓存。
    • singletonObjectsearlySingletonObjectssingletonFactiries,分别存放成品对象、半成品对象和工厂对象。
    • 同时包装三个缓存提供方法:getSingletonregisterSingletonaddSingletonFactory,这样使用方就可以分别在不同时间段存放和获取对应的对象。
  • AbstractAutowireCapableBeanFactorydoCreateBean 方法中,提供了关于提前暴露对象的操作。
    • 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 类中,共有三个缓存对象的属性:
    • singletonObjectsearlySingletonObjectssingletonFactories
    • 用于存放不同类型的对象:单例对象、早期的半成品单例对象、单例工厂对象。
  • 紧接着在这三个缓存对象下提供了获取、添加和注册不同对象的方法,包括:getSingletonregisterSingletonBeanaddSingletonFactory
    • 后面的两个方法都比较简单,主要是 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


<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>

    
    <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

手写Spring:第17章-通过三级缓存解决循环依赖_第6张图片

  • 测试结果看,无论是简单对象依赖,还是代理工程对象,或者 AOP 切面对象,都可以在三级缓存下解决循环依赖的问题。
  • 此外从运行截图 DefaultSingletonBeanRegistry#getSingleton 中也可以看到需要三级缓存存放工厂对象的类,都会使用到 getObject 获取真实对象,并随后存入半成品对象 earlySingletonObjects 中以及移除工厂对象。

五、总结:通过三级缓存解决循环依赖

  • Spring 中所有的功能都是以解决 Java 编程中的特性而存在的,就像我们处理的循环依赖,如果没有 Spring 框架的情况下,可能我们也会尽可能避免写出循环依赖的操作,因为在没有经过加工处理后,这样的依赖关系肯定会报错的。
    • 这也是程序从 能用好用 的升级。
  • 在解决循环依赖的核心流程中,主要是提前暴露对象的设计,以及建立三级缓存的数据结构来存放不同时期的对象。
    • 如果说没有如切面和工厂中的代理对象,那么二级缓存也就可以解决了,哪怕是只有一级缓存。
    • 但为了设计上的合理和可扩展性,所以创建了三级缓存来放置不同时期的对象。

你可能感兴趣的:(手写spring,spring,缓存,java)