源码阅读---Spring是如何解决循环依赖?

前言

本篇debug源码的方式去进行。

准备测试代码
在这里插入图片描述
切面类:

@Aspect
@Order
@Component
public class TulingLogAspect {

	public TulingLogAspect() {
		System.out.println("加载TulingLog");
	}

	@Pointcut("execution(* tuling.TulingCalculateA.*(..))")
    public void pointCut(){};

    @Before(value = "pointCut()")
    public void methodBefore(JoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("执行目标方法【"+methodName+"】的<前置通知>,入参"+ Arrays.asList(joinPoint.getArgs()));
    }

    @After(value = "pointCut()")
    public void methodAfter(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("执行目标方法【"+methodName+"】的<后置通知>,入参"+Arrays.asList(joinPoint.getArgs()));
    }

    @AfterReturning(value = "pointCut()",returning = "result")
    public void methodReturning(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("执行目标方法【"+methodName+"】的<返回通知>,入参"+Arrays.asList(joinPoint.getArgs()));
    }

    @AfterThrowing(value = "pointCut()")
    public void methodAfterThrowing(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("执行目标方法【"+methodName+"】的<异常通知>,入参"+Arrays.asList(joinPoint.getArgs()));
    }

}
@Component
public class TulingCalculateA {

	@Autowired
	TulingCalculateB tulingCalculateB;

    public int add(int numA, int numB) {

        System.out.println("执行目标方法:add");
        return numA+numB;
    }

    public int sub(int numA, int numB) {
        System.out.println("执行目标方法:reduce");
        return numA-numB;
    }

    public int div(int numA, int numB) {
        return tulingCalculateB.div(numA,numB);
    }
//
    public int multi(int numA, int numB) {
        return tulingCalculateB.multi(numA,numB);
    }
//
    public int mod(int numA,int numB){
        System.out.println("执行目标方法:mod");

		int retVal = ((Calculate)AopContext.currentProxy()).add(numA,numB);
        //int retVal = this.add(numA,numB);

        return retVal%numA;

        //return numA%numB;
    }

}
@Component
public class TulingCalculateB {//implements Calculate{

	@Autowired
	TulingCalculateA tulingCalculateA;


	public int add(int numA, int numB) {
		return tulingCalculateA.add(numA,numB);
	}

	public int sub(int numA, int numB) {
		return tulingCalculateA.sub(numA,numB);
	}

	public int div(int numA, int numB) {
		System.out.println("执行目标方法:div");

		return numA/numB;
	}
    public int multi(int numA, int numB) {
        System.out.println("执行目标方法:multi");

        return numA*numB;
    }

    public int mod(int numA,int numB){
        System.out.println("执行目标方法:mod");

		int retVal = ((Calculate)AopContext.currentProxy()).add(numA,numB);
        //int retVal = this.add(numA,numB);

        return retVal%numA;

        //return numA%numB;
    }

}

配置类

@Configuration
@EnableAspectJAutoProxy  /*<aop:aspectj-autoproxy/>*/
//(exposeProxy = true) //(proxyTargetClass = true)
@ComponentScan("tuling")
public class MainConfig {


}

源码解读

解析配置类,生成bean定义的我们就不看了,之前分析过,之间来到finishBeanFactoryInitialization(实例化我们剩余的单实例bean)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

解析切面类

在这里插入图片描述

/**
* 后置处理器的【第一次】调用 总共有九处调用 事务在这里不会被调用,aop的才会被调用
* 为啥aop在这里调用了,因为在此处需要解析出对应的切面保存到缓存中
*/
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
	/**
	 * 获取容器中的所有后置处理器
	 */
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		//判断后置处理器是不是InstantiationAwareBeanPostProcessor
		if (bp instanceof InstantiationAwareBeanPostProcessor) {//是不是实现了InstantiationAwareBeanPostProcessor接口
			//把我们的BeanPostProcessor强制转为InstantiationAwareBeanPostProcessor
			InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
			/**
			 * 【很重要】
			 * 我们AOP @EnableAspectJAutoProxy 为我们容器中导入了 AnnotationAwareAspectJAutoProxyCreator
			 * 我们事务注解@EnableTransactionManagement 为我们的容器导入了 InfrastructureAdvisorAutoProxyCreator
			 * 都是实现了我们的 BeanPostProcessor接口,InstantiationAwareBeanPostProcessor,
			 * 进行后置处理解析切面
			 */
			Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
			if (result != null) {
				return result;
			}
		}
	}
	return null;
}

在这里插入图片描述

进入循环依赖模块

在这里插入图片描述
在这里插入图片描述

在第一次创建A的时候会在在这里插入图片描述
加入到singletonsCurrentlyInCreation里,把A标记为正在创建在这里插入图片描述
回调createBean方法
在这里插入图片描述
调用doCreateBean
在这里插入图片描述

缓存单例到三级缓存,防止循环依赖。三级缓存存的函数式接口,用于后置处理器调用AOP,代码解耦
在这里插入图片描述

在A属性赋值,注入属性B,解析autowired注解
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
发现了A的autowireB,去getBean(B)。继续createBean(B),可以发现此时循环依赖标识中已经把B加入了
在这里插入图片描述

在这里插入图片描述
此时属性赋值B,此时正在创建的集合里有了A和B
在这里插入图片描述
在这里插入图片描述
又发现了A在这里插入图片描述
继续getBean(A)在这里插入图片描述
在这里插入图片描述

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	/**
	 * 第一步:我们尝试去一级缓存(单例缓存池中去获取对象,一般情况从该map中获取的对象是直接可以使用的)
	 * IOC容器初始化加载单实例bean的时候第一次进来的时候 该map中一般返回空
	 */

	Object singletonObject = this.singletonObjects.get(beanName);
	/**
	 * 若在第一级缓存中没有获取到对象,并且singletonsCurrentlyInCreation这个list包含该beanName
	 * IOC容器初始化加载单实例bean的时候第一次进来的时候 该list中一般返回空,但是循环依赖的时候可以满足该条件
	 */
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		synchronized (this.singletonObjects) {
			/**
			 * 尝试去二级缓存中获取对象(二级缓存中的对象是一个早期对象)
			 * 何为早期对象:就是bean刚刚调用了构造方法,还来不及给bean的属性进行赋值的对象(纯净态)
			 * 就是早期对象
			 */
			singletonObject = this.earlySingletonObjects.get(beanName);
			/**
			 * 二级缓存中也没有获取到对象,allowEarlyReference为true(参数是有上一个方法传递进来的true)
			 */
			if (singletonObject == null && allowEarlyReference) {
				/**
				 * 直接从三级缓存中获取 ObjectFactory对象 这个对接就是用来解决循环依赖的关键所在
				 * 在ioc后期的过程中,当bean调用了构造方法的时候,把早期对象包裹成一个ObjectFactory
				 * 暴露到三级缓存中
				 */
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				//从三级缓存中获取到对象不为空
				if (singletonFactory != null) {
					/**
					 * 在这里通过暴露的ObjectFactory 包装对象中,通过调用他的getObject()来获取我们的早期对象
					 * 在这个环节中会调用到 getEarlyBeanReference()来进行后置处理
					 */
					singletonObject = singletonFactory.getObject();
					//把早期对象放置在二级缓存,
					this.earlySingletonObjects.put(beanName, singletonObject);
					//ObjectFactory 包装对象从三级缓存中删除掉
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}

在这里插入图片描述
因为之前A和B已经存到3级缓存里了,此时singletonFactory.getObject()
会调用后置处理器给B中的A创建动态代理
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
利用完3级缓存中的后置处理器创建了A的动态代理
在这里插入图片描述
放到了2级缓存中,从3级缓存中删除了A,
在这里插入图片描述
此时B中的A赋值完成。
在这里插入图片描述
B的属性赋值完成,在这里插入图片描述
在这里插入图片描述
此时什么也拿不到,因为1级缓存里没有,二级缓存里也没有B。移除正在创建的B
在这里插入图片描述
把B加入1级缓存里在这里插入图片描述
这时A里的B走完了,实例化,属性赋值,初始化,放入缓存的过程。回到了A的属性赋值
在这里插入图片描述
A属性赋值完,去getSingleton,一级缓存没有,并且是正在创建,从2级缓存中拿。
在这里插入图片描述
拿到返回,加入1级缓存里。
在这里插入图片描述
此时完成了循环依赖的解决
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值