Spring循环依赖

文章目录

  • Spring循环依赖
  • 前言
  • 一、搭积木
  • 1.1 定义循环依赖Bean
  • 1.2 手写第一版本
  • 1.3 手写第二版本
  • 二、问题解决
  • 二级缓存解决不成熟bean的情况
  • 二级缓存完美解决
  • Spring的纠结点
  • 三、完美解决

前言

循环依赖其实就是循环引用,也就是两个或者两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。如下图:

分析spring循环依赖的插件_一级缓存

在本博客,我将手写实现一下Spring的循环依赖。试试水

一、搭积木

1.1 定义循环依赖Bean

1、student类

package com.jztai.spring.circledependence;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Teacher {

	@Autowired
	private Student student;

}

2、Student

package com.jztai.spring.circledependence;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Student {
	@Autowired
	private Teacher teacher;
}

3、动态代理

package com.jztai.spring.circledependence;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;

public class JdkProxyBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {


	@Override
	public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		// 简单化,直接返回对象
		return bean;
	}
}

1.2 手写第一版本

第一版本是入门,但是会出现死循环。

package com.jztai.spring.circledependence;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Written by MaShanTao
 * 第一版本的循环依赖,很明显会出现死循环
 */
public class CircleDev1 {

	private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

	// 大名鼎鼎的单例缓存池
	private static final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/**
	 * 加载Bean定义,Spring里面将类加载成BeanDefinition,并存在Map中
	 */
	static void loadBeanDefinations() {
		RootBeanDefinition studentDefinition = new RootBeanDefinition(Student.class);
		RootBeanDefinition teacherDefinition = new RootBeanDefinition(Teacher.class);
		beanDefinitionMap.put("student", studentDefinition);
		beanDefinitionMap.put("teacher", teacherDefinition);
	}


	/**
	 * 获取Bean
	 *
	 * @param beanName
	 */
	private static Object getBean(String beanName) throws Exception {
		// 1、实例化
		BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
		Class<? extends BeanDefinition> beanClass = beanDefinition.getClass();
		Class beanInstance = beanClass.getClass().getDeclaredConstructor().newInstance();
		// 2、属性复制
		// 2.1、拿到所有的带有Autowerid注解的属性
		Field[] declaredFields = beanClass.getDeclaredFields();
		for (Field declaredField : declaredFields) {
			// 拿到该字段的Autowired注解
			Autowired annotation = declaredField.getAnnotation(Autowired.class);
			// 拿到的注解不为空,就代表有该注解
			if (annotation != null) {
				// 打开该属性的访问权限,因为访问权限是private
				declaredField.setAccessible(true);
				// 递归调用getBean去获取属性teatcher
				// Spring 可以根据Name、Type、构造函数来获取,这里只写name
				String name = declaredField.getName();
				Object bean = getBean(name);
				declaredField.set(beanInstance, bean);
			}
		}
		// 3、初始化,看看Bean有没有实现InitializingBean接口或者有没有指定init-method。
		// 4、添加到一级缓存
		singletonObjects.put(beanName, beanInstance);
		return beanInstance;
	}

	public static void main(String[] args) throws Exception {
		loadBeanDefinations();
		for (String beanName : beanDefinitionMap.keySet()) {
			getBean(beanName);
		}
	}

}

分析spring循环依赖的插件_二级缓存_02

1.3 手写第二版本

1.2出现的问题是死循环,解决他的方式就是先看看单例池里面有没有,有的话,直接获取单例池的即可。但是这个版本的问题是导致Spring获取到了不完整的bean对象。这个状态称之为纯净态的bean。

分析spring循环依赖的插件_二级缓存_03

package com.jztai.spring.circledependence;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Written by MaShanTao
 * 第二版本的循环依赖,加入了判断,如果单例池中有就直接返回
 * 但是这个版本会导致获取不成熟的bean(纯净态的bean)。循环依赖的属性得不到注入。
 */
public class CircleDev2 {

	private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

	// 大名鼎鼎的单例缓存池
	private static final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/**
	 * 加载Bean定义,Spring里面将类加载成BeanDefinition,并存在Map中
	 */
	static void loadBeanDefinations() {
		RootBeanDefinition studentDefinition = new RootBeanDefinition(Student.class);
		RootBeanDefinition teacherDefinition = new RootBeanDefinition(Teacher.class);
		beanDefinitionMap.put("student", studentDefinition);
		beanDefinitionMap.put("teacher", teacherDefinition);
	}


	/**
	 * 获取Bean,先看看单例池有没有,有的话就返回,
	 * 但是版本一的代码会出现单例池无法put的情况,因为循环依赖到不了初始化的那个阶段,所以将put提前。
	 *
	 * @param beanName
	 */
	private static Object getBean(String beanName) throws Exception {
		// 0、看看单例池有没有
		Object singleton = getSingleton(beanName);
		if (singleton != null) {
			return singleton;
		}
		// 1、实例化
		BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
		Class<? extends BeanDefinition> beanClass = beanDefinition.getClass();
		Class<?> beanInstance = beanClass.getClass().getDeclaredConstructor().newInstance();

		// 4、添加到一级缓存
		singletonObjects.put(beanName, beanInstance);

		// 2、属性赋值
		// 2.1、拿到所有的带有Autowerid注解的属性
		Field[] declaredFields = beanClass.getDeclaredFields();
		for (Field declaredField : declaredFields) {
			// 拿到该字段的Autowired注解
			Autowired annotation = declaredField.getAnnotation(Autowired.class);
			// 拿到的注解不为空,就代表有该注解
			if (annotation != null) {
				// 打开该属性的访问权限,因为访问权限是private
				declaredField.setAccessible(true);
				// 递归调用getBean去获取属性teatcher
				// Spring 可以根据Name、Type、构造函数来获取,这里只写name
				String name = declaredField.getName();
				Object bean = getBean(name);
				declaredField.set(beanInstance, bean);
			}
		}
		// 3、初始化,看看Bean有没有实现InitializingBean接口或者有没有指定init-method。
		return beanInstance;
	}

	private static Object getSingleton(String beanName) {
		if (singletonObjects.containsKey(beanName)) {
			return singletonObjects.get(beanName);
		}
		return null;
	}

	public static void main(String[] args) throws Exception {
		loadBeanDefinations();
		for (String beanName : beanDefinitionMap.keySet()) {
			getBean(beanName);
		}
		Student student = (Student) singletonObjects.get("student");
		System.out.println(student.toString());
	}

}

二、问题解决

二级缓存解决不成熟bean的情况

上面的版本2能实现循环依赖,但是会造成获取到不成熟的Bean,因为A创建完成加入到一级缓存了,此时A里面的属性B还没有赋值呢,此时如果读取A的话,A就是不完整的bean。所以此时二级缓存上线了。即先去一级缓存拿,如果一级缓存没有就去二级缓存拿,总之这个缓存就是为了解决纯净bean的问题,将完整bean和纯净bean分离开来,避免读取到不完整的bean。引入二级缓存之后其实就可以解决循环依赖的问题了。

分析spring循环依赖的插件_分析spring循环依赖的插件_04

package com.jztai.spring.circledependence;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Written by MaShanTao
 * 第三版本的循环依赖,引入二级缓存,解决获取不到成熟Bean的问题。
 * 一级缓存有的话,先去一级缓存拿,如果一级缓存没有的话,就去二级缓存拿。
 */
public class CircleDev3 {

	private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

	// 大名鼎鼎的单例缓存池,存放成熟Bean
	private static final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	// 二级缓存,为了将成熟bean和纯净bean分离开,避免读取到不完整的bean。
	private static final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

	/**
	 * 加载Bean定义,Spring里面将类加载成BeanDefinition,并存在Map中
	 */
	static void loadBeanDefinations() {
		RootBeanDefinition studentDefinition = new RootBeanDefinition(Student.class);
		RootBeanDefinition teacherDefinition = new RootBeanDefinition(Teacher.class);
		beanDefinitionMap.put("student", studentDefinition);
		beanDefinitionMap.put("teacher", teacherDefinition);
	}


	/**
	 * 获取Bean,先看看单例池有没有,单例池没有,看看二级缓存有没有,如果有的话去二级缓存拿
	 * 一级缓存存成熟bean,二级缓存存纯净bean。
	 * 如果A在创建依赖B的时候发现二级缓存有,去拿二级缓存中的B给自己注入,注入之后A就成熟了。
	 * 此时再循环到B的时候,注入A即可,A是成熟的了,完美解决循环依赖
	 * @param beanName
	 */
	private static Object getBean(String beanName) throws Exception {
		// 0、看看单例池有没有
		Object singleton = getSingleton(beanName);
		if (singleton != null) {
			return singleton;
		}
		// 1、实例化
		BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
		Class<? extends BeanDefinition> beanClass = beanDefinition.getClass();
		Class<?> beanInstance = beanClass.getClass().getDeclaredConstructor().newInstance();

		// 4、添加到二级缓存
		earlySingletonObjects.put(beanName, beanInstance);

		// 2、属性赋值
		// 2.1、拿到所有的带有Autowerid注解的属性
		Field[] declaredFields = beanClass.getDeclaredFields();
		for (Field declaredField : declaredFields) {
			// 拿到该字段的Autowired注解
			Autowired annotation = declaredField.getAnnotation(Autowired.class);
			// 拿到的注解不为空,就代表有该注解
			if (annotation != null) {
				// 打开该属性的访问权限,因为访问权限是private
				declaredField.setAccessible(true);
				// 递归调用getBean去获取属性teatcher
				// Spring 可以根据Name、Type、构造函数来获取,这里只写name
				String name = declaredField.getName();
				Object bean = getBean(name);
				declaredField.set(beanInstance, bean);
			}
		}
		// 3、初始化,看看Bean有没有实现InitializingBean接口或者有没有指定init-method。
		// 4、添加到一级缓存
		singletonObjects.put(beanName, beanInstance);
		return beanInstance;
	}

	private static Object getSingleton(String beanName) {
		if (singletonObjects.containsKey(beanName)) {
			return singletonObjects.get(beanName);
		} else if (earlySingletonObjects.containsKey(beanName)) {
			return earlySingletonObjects.get(beanName);
		}
		return null;
	}

	public static void main(String[] args) throws Exception {
		loadBeanDefinations();
		for (String beanName : beanDefinitionMap.keySet()) {
			getBean(beanName);
		}
		Student student = (Student) singletonObjects.get("student");
		System.out.println(student.toString());
	}
}

二级缓存完美解决

只要在初始化Bean之后,创建动态代理,就可以完美实现Spring的循环依赖。其实从这开始要注意,二级缓存是不清理的,为的就是在循环依赖的时候有多重依赖问题,好几个类依赖我,不能每次都从三级缓存中创建一份,所以当二级缓存没有的时候,去三级缓存拿,拿出来之后删除三级缓存,然后加入到二级缓存,为的是多个依赖我,能从二级缓存中拿

package com.jztai.spring.circledependence;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Written by MaShanTao
 * 第四版本的循环依赖,二级缓存完美解决循环依赖,包括Aop
 */
public class CircleDev4 {

	private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

	// 大名鼎鼎的单例缓存池,存放成熟Bean
	private static final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	// 二级缓存,为了将成熟bean和纯净bean分离开,避免读取到不完整的bean。
	private static final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

	/**
	 * 加载Bean定义,Spring里面将类加载成BeanDefinition,并存在Map中
	 */
	static void loadBeanDefinations() {
		RootBeanDefinition studentDefinition = new RootBeanDefinition(Student.class);
		RootBeanDefinition teacherDefinition = new RootBeanDefinition(Teacher.class);
		beanDefinitionMap.put("student", studentDefinition);
		beanDefinitionMap.put("teacher", teacherDefinition);
	}


	/**
	 * 获取Bean,先看看单例池有没有,单例池没有,看看二级缓存有没有,如果有的话去二级缓存拿
	 * 一级缓存存成熟bean,二级缓存存纯净bean。
	 * 如果A在创建依赖B的时候发现二级缓存有,去拿二级缓存中的B给自己注入,注入之后A就成熟了。
	 * 此时再循环到B的时候,注入A即可,A是成熟的了,完美解决循环依赖
	 *
	 * AOP动态代理咋解决
	 * 直接在实例化之后,调用Bean的后置处理器,去解析Pointcut,然后创建动态代理即可。
	 * @param beanName
	 */
	private static Object getBean(String beanName) throws Exception {
		// 0、看看单例池有没有
		Object singleton = getSingleton(beanName);
		if (singleton != null) {
			return singleton;
		}
		// 1、实例化
		BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
		Class<? extends BeanDefinition> beanClass = beanDefinition.getClass();
		Object beanInstance = beanClass.getClass().getDeclaredConstructor().newInstance();

		// 给beanInstance创建动态代理
		beanInstance = new JdkProxyBeanPostProcessor().getEarlyBeanReference(beanInstance, beanName);

		// 4、添加到二级缓存
		earlySingletonObjects.put(beanName, beanInstance);

		// 2、属性赋值
		// 2.1、拿到所有的带有Autowerid注解的属性
		Field[] declaredFields = beanClass.getDeclaredFields();
		for (Field declaredField : declaredFields) {
			// 拿到该字段的Autowired注解
			Autowired annotation = declaredField.getAnnotation(Autowired.class);
			// 拿到的注解不为空,就代表有该注解
			if (annotation != null) {
				// 打开该属性的访问权限,因为访问权限是private
				declaredField.setAccessible(true);
				// 递归调用getBean去获取属性teatcher
				// Spring 可以根据Name、Type、构造函数来获取,这里只写name
				String name = declaredField.getName();
				Object bean = getBean(name);
				declaredField.set(beanInstance, bean);
			}
		}
		// 3、初始化,看看Bean有没有实现InitializingBean接口或者有没有指定init-method。
		// 初始化之后,Spring也进行了动态代理的创建
		// 4、添加到一级缓存
		singletonObjects.put(beanName, beanInstance);
		return beanInstance;
	}

	private static Object getSingleton(String beanName) {
		if (singletonObjects.containsKey(beanName)) {
			return singletonObjects.get(beanName);
		} else if (earlySingletonObjects.containsKey(beanName)) {
			return earlySingletonObjects.get(beanName);
		}
		return null;
	}

	public static void main(String[] args) throws Exception {
		loadBeanDefinations();
		for (String beanName : beanDefinitionMap.keySet()) {
			getBean(beanName);
		}
		Student student = (Student) singletonObjects.get("student");
		System.out.println(student.toString());
	}

}

Spring的纠结点

其实是用二级缓存就可以完美实现Spring的循环依赖。包括动态代理,但是Spring还是希望正常的Bean(没有循环依赖的bean)是在初始化之后创建动态代理,只有在循环依赖的前提下才在实例化之后创建。 ,上面的版本,正常的bean也在实例化bean之后进行创建了。改一下,将实例化之后创建的动态代理去掉,在初始化之后创建动态代理,然后循环依赖的时候,在一级缓存中拿不到,去二级缓存中拿的时候,创建动态代理,去二级缓存拿就说明此时是处于循环依赖的。这样就完美解决了在循环依赖的情况下,实例化后创建动态代理;以及没有循环依赖的bean在初始化之后创建动态代理。

package com.jztai.spring.circledependence;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Written by MaShanTao
 * 第五版本的循环依赖
 * Spring还是希望正常的Bean是在初始化之后创建动态代理,只有在循环依赖的前提下才在实例化之后创建
 * 要判断是否是循环依赖。二级缓存如果有的话,就代表当前处于循环依赖状态。
 * 但是如果二级缓存有的话,getBean函数就返回了,所以直接将创建动态代理的代码放在getSigton函数里面。
 * 所以其实只用耳机缓存就可以完美实现动态代理
 */
public class CircleDev5 {

	private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

	// 大名鼎鼎的单例缓存池,存放成熟Bean
	private static final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	// 二级缓存,为了将成熟bean和纯净bean分离开,避免读取到不完整的bean。
	private static final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

	// 假设Student使用了AOP,@PointCut(""),要给Student创建动态代理

	/**
	 * 加载Bean定义,Spring里面将类加载成BeanDefinition,并存在Map中
	 */
	static void loadBeanDefinations() {
		RootBeanDefinition studentDefinition = new RootBeanDefinition(Student.class);
		RootBeanDefinition teacherDefinition = new RootBeanDefinition(Teacher.class);
		beanDefinitionMap.put("student", studentDefinition);
		beanDefinitionMap.put("teacher", teacherDefinition);
	}


	/**
	 * 获取Bean,先看看单例池有没有,单例池没有,看看二级缓存有没有,如果有的话去二级缓存拿
	 * 一级缓存存成熟bean,二级缓存存纯净bean。
	 * 如果A在创建依赖B的时候发现二级缓存有,去拿二级缓存中的B给自己注入,注入之后A就成熟了。
	 * 此时再循环到B的时候,注入A即可,A是成熟的了,完美解决循环依赖
	 *
	 * AOP动态代理咋解决
	 * 直接在实例化之后,调用Bean的后置处理器,去解析Pointcut,然后创建动态代理即可。
	 *
	 * Spring还是希望正常的Bean是在初始化之后创建动态代理,只有在循环依赖的前提下才在实例化之后创建
	 * 要判断是否是循环依赖。二级缓存如果有的话,就代表当前处于循环依赖状态。
	 * 但是如果二级缓存有的话,getBean函数就返回了,所以直接将创建动态代理的代码放在getSigton函数里面。
	 * @param beanName
	 */
	private static Object getBean(String beanName) throws Exception {
		// 0、看看单例池有没有
		Object singleton = getSingleton(beanName);
		if (singleton != null) {
			return singleton;
		}
		// 1、实例化
		BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
		Class<? extends BeanDefinition> beanClass = beanDefinition.getClass();
		Object beanInstance = beanClass.getClass().getDeclaredConstructor().newInstance();

		// 2、属性赋值
		// 2.1、拿到所有的带有Autowerid注解的属性
		Field[] declaredFields = beanClass.getDeclaredFields();
		for (Field declaredField : declaredFields) {
			// 拿到该字段的Autowired注解
			Autowired annotation = declaredField.getAnnotation(Autowired.class);
			// 拿到的注解不为空,就代表有该注解
			if (annotation != null) {
				// 打开该属性的访问权限,因为访问权限是private
				declaredField.setAccessible(true);
				// 递归调用getBean去获取属性teatcher
				// Spring 可以根据Name、Type、构造函数来获取,这里只写name
				String name = declaredField.getName();
				Object bean = getBean(name);
				declaredField.set(beanInstance, bean);
			}
		}
		// 3、初始化,看看Bean有没有实现InitializingBean接口或者有没有指定init-method。
		// 初始化之后,Spring也进行了动态代理的创建
		// 4、添加到一级缓存
		singletonObjects.put(beanName, beanInstance);
		return beanInstance;
	}


	private static Object getSingleton(String beanName) {
		if (singletonObjects.containsKey(beanName)) {
			return singletonObjects.get(beanName);
		} else if (earlySingletonObjects.containsKey(beanName)) {
			// Spring还是希望正常的Bean是在初始化之后创建动态代理,只有在循环依赖的前提下才在实例化之后创建
			// 要判断是否是循环依赖。二级缓存如果有的话,就代表当前处于循环依赖状态。
			// 给beanInstance创建动态代理
			Object beanInstance = earlySingletonObjects.get(beanName);
			if(beanInstance isinstanceof JdkProxyBeanPostProcessor) return beanInstance;
			beanInstance = new JdkProxyBeanPostProcessor().getEarlyBeanReference(beanInstance, beanName);
			// 4、添加到二级缓存,如果有其他的也依赖于当前的对象,可以只拿到一个单例的动态代理。
			earlySingletonObjects.put(beanName, beanInstance);
			return beanInstance;
		}
		return null;
	}

	public static void main(String[] args) throws Exception {
		loadBeanDefinations();
		for (String beanName : beanDefinitionMap.keySet()) {
			getBean(beanName);
		}
		Student student = (Student) singletonObjects.get("student");
		System.out.println(student.toString());
	}
}

三、完美解决

分析spring循环依赖的插件_spring_05

其实通过二级缓存就可以实现Spring的循环依赖了。但是Spring为了解耦,在上面的方法里面getSington方法里面即获取Bean又创建Bean,代码看起来不优美,所以引入了三级缓存。引入三级缓存之后,三级缓存是工厂的缓存,里面定义着创建动态代理的代码;因为会出现多个依赖问题,比如A、B、C、D,四个相互依赖,那么B再注入A的时候,给A创建了动态代理,C在注入A的时候,不能再次创建动态代理了,所以就用二级缓存来缓存动态代理对象,一级缓存还是存成熟的Bean。二级缓存的作用变了之后,没办法之后当前是否是循环依赖了,所以引入了Set集合来标识当前正在创建的Bean,当再次创建时,Set集合里面有该Bean就代表当前是循环依赖。代码如下:

package com.jztai.spring.circledependence;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Written by MaShanTao
 * 第6版本的循环依赖,引入三级缓存,为了代码解耦
 * Spring还是希望正常的Bean是在初始化之后创建动态代理,只有在循环依赖的前提下才在实例化之后创建
 * 要判断是否是循环依赖。二级缓存如果有的话,就代表当前处于循环依赖状态。
 * 但是如果二级缓存有的话,getBean函数就返回了,所以直接将创建动态代理的代码放在getSigton函数里面。
 * 所以其实只用二级缓存就可以完美实现动态代理。
 * <p>
 * 三级缓存是Map<String, ObjectFactory<?>>,ObjectFactory就是一个函数式接口,用来存创建动态代理的执行单元。
 * 三级缓存创建代理对象之后,将代理对象放到二级缓存。二级缓存不存纯净对象了。
 * 如果A,B,C互相依赖的话,A在创建B的时候生成代理对象了,此时C再去注入B的时候不能让他在创建一次
 * 所以就将代理对象存二级缓存,C再注入B的时候,可以直接去二级缓存拿,避免重复创建。
 * 而二级缓存不存纯净对象之后,就不能知道是否是循环依赖了。所以引入了Set标识循环依赖
 * <p>
 * A注入的时候,去创建B,B创建的时候,利用三级缓存创建A的动态代理,并将A的动态代理注入到B,将代理对象村存到二级缓存
 * 此时B创建完之后回到A,A还是纯净对象,应该去二级缓存中拿代理对象。
 */
public class CircleDev6 {

	private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

	// 大名鼎鼎的单例缓存池,存放成熟Bean
	private static final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	// 二级缓存,为了将成熟bean和纯净bean分离开,避免读取到不完整的bean。
	private static final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

	// 三级缓存,为了解决代码耦合
	// 假设Student使用了AOP,@PointCut(""),要给Student创建动态代理
	private static final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	// 当前创建的BeanName
	private static final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

	/**
	 * 加载Bean定义,Spring里面将类加载成BeanDefinition,并存在Map中
	 */
	static void loadBeanDefinations() {
		RootBeanDefinition studentDefinition = new RootBeanDefinition(Student.class);
		RootBeanDefinition teacherDefinition = new RootBeanDefinition(Teacher.class);
		beanDefinitionMap.put("student", studentDefinition);
		beanDefinitionMap.put("teacher", teacherDefinition);
	}


	/**
	 * 获取Bean,先看看单例池有没有,单例池没有,看看二级缓存有没有,如果有的话去二级缓存拿
	 * 一级缓存存成熟bean,二级缓存存纯净bean。
	 * 如果A在创建依赖B的时候发现二级缓存有,去拿二级缓存中的B给自己注入,注入之后A就成熟了。
	 * 此时再循环到B的时候,注入A即可,A是成熟的了,完美解决循环依赖
	 * <p>
	 * AOP动态代理咋解决
	 * 直接在实例化之后,调用Bean的后置处理器,去解析Pointcut,然后创建动态代理即可。
	 * <p>
	 * Spring还是希望正常的Bean是在初始化之后创建动态代理,只有在循环依赖的前提下才在实例化之后创建
	 * 要判断是否是循环依赖。二级缓存如果有的话,就代表当前处于循环依赖状态。
	 * 但是如果二级缓存有的话,getBean函数就返回了,所以直接将创建动态代理的代码放在getSigton函数里面。
	 *
	 * @param beanName
	 */
	private static Object getBean(String beanName) throws Exception {
		// 0、看看单例池有没有
		Object singleton = getSingleton(beanName);
		if (singleton != null) {
			return singleton;
		}
		if (!singletonsCurrentlyInCreation.contains(beanName)) {
			// 将当前Bean设置为正在创建。
			singletonsCurrentlyInCreation.add(beanName);
		}

		// 1、实例化
		BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
		Class<? extends BeanDefinition> beanClass = beanDefinition.getClass();
		Object beanInstance = beanClass.getClass().getDeclaredConstructor().newInstance();

		// 循环代理的Bean才会在实例化这里创建动态代理

		singletonFactories.put(beanName, () -> {
			// 动态代理根据原来的bean创建的,也就是原bean的信息还保留着。所以下面可以直接用二级缓存中的动态代理替换实例。
			Object earlyBeanReference = new JdkProxyBeanPostProcessor().getEarlyBeanReference(beanInstance, beanName);
			return earlyBeanReference;
		});

		// 二级缓存不能写在这里了。因为创建代理是在三级缓存进行的,异步处理的。
		// 二级缓存应该存的是AOP对象
		// 假设A使用AOP,A在解析的时候去创建B
		// B创建的时候,实例化A的动态代理对象,将动态代理对象注入到B
		// A递归回来之后继续创建,此时A还是纯净对象,所以应该去二级缓存拿代理对象

		earlySingletonObjects.put(beanName, beanInstance);

		// 2、属性赋值
		// 2.1、拿到所有的带有Autowerid注解的属性
		Field[] declaredFields = beanClass.getDeclaredFields();
		for (Field declaredField : declaredFields) {
			// 拿到该字段的Autowired注解
			Autowired annotation = declaredField.getAnnotation(Autowired.class);
			// 拿到的注解不为空,就代表有该注解
			if (annotation != null) {
				// 打开该属性的访问权限,因为访问权限是private
				declaredField.setAccessible(true);
				// 递归调用getBean去获取属性teatcher
				// Spring 可以根据Name、Type、构造函数来获取,这里只写name
				String name = declaredField.getName();
				Object bean = getBean(name);
				declaredField.set(beanInstance, bean);
			}
		}
		// 3、初始化,看看Bean有没有实现InitializingBean接口或者有没有指定init-method。
		// 初始化之后,Spring也进行了动态代理的创建
		// 4、添加到一级缓存
		// 如果二级缓存有的话,就代表当前Bean已经生成动态代理了,就将当前实例赋值为二级缓存中的动态代理。
		if (earlySingletonObjects.containsKey(beanName)) {
			beanInstance = earlySingletonObjects.get(beanName);
		}
		singletonObjects.put(beanName, beanInstance);
		// 后面还要remove掉二级缓存和三级缓存,根据当前Bean是否最后一次创建啥啥的。
		return beanInstance;
	}


	// Spring为了解耦,将后置处理器代码写在getSingleton,获取单例函数里面代码不耦合。
	private static Object getSingleton(String beanName) {
		Object bean = singletonObjects.get(beanName);
		// 一级缓存中没有,但是当前bean标识着正在创建,就代表着二三级缓存中有
		if (bean == null && singletonsCurrentlyInCreation.contains(beanName)) {
			// 二级缓存中存的是代理对象,先从二级缓存拿
			bean = earlySingletonObjects.get(beanName);
			if (bean == null) {
				// 一二级缓存都没有的话,去三级缓存拿
				ObjectFactory<?> objectFactory = singletonFactories.get(beanName);
				// 三级缓存的对象工厂调用getObject函数获取bean
				if (objectFactory != null) {
					bean = objectFactory.getObject();
					// 存到二级缓存,以防止好多个相互依赖,有多个Bean依赖A
					// 那么A就只用创建一次,然后放在二级缓存即可,下次直接从二级缓存中拿即可。
					earlySingletonObjects.put(beanName, bean);
					// 动态代理创建完之后就可以将当前beanName删除三级缓存
					singletonFactories.remove(beanName);
				}
			}
		}
		return bean;
	}

	public static void main(String[] args) throws Exception {
		loadBeanDefinations();
		for (String beanName : beanDefinitionMap.keySet()) {
			getBean(beanName);
		}
		Student student = (Student) singletonObjects.get("student");
		System.out.println(student.toString());
	}

}

Spring的实现其实和这个例子基本是一致的。

分析spring循环依赖的插件_一级缓存_06