【spring】spring循环依赖-三级缓存

一.作用

  • 1.为了保证动态代理只创建一次
  • 2.如果只有二级缓存,出现多次循环依赖,例如A<–>B 和A<–>C,此时会创建多个代理A

二.代码示例

package com.learning.circulardependency;

import org.springframework.beans.factory.InitializingBean;
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.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author wangyouhui
 * @Description 循环依赖-二级缓存
 **/
public class MyApplicationContext3 {
	// 单例 解决线程安全: 双重检查锁
	private Map<String, BeanDefinition> beanDefinitionMap = new LinkedHashMap<>();

	// 一级缓存 单例池 问题:早期的bean和完整bean放在一起,会出现并发下获取不完的bean
	// 所有完整的bean
	private final Map<String,Object> singletonObjects = new ConcurrentHashMap<>();

	// 二级缓存 为了解决循环依赖,并且能够解决并发下获取不完整bean的性能问题,利用双重检查锁+二级缓存
	private final Map<String,Object> earlySingletonObjects = new ConcurrentHashMap<>();

	// 三级缓存 为了保证动态代理只创建一次(如果只有二级缓存,出现多次循环依赖,例如A<->B A<->C,此时会创建多个代理A)
	private final Map<String,Object> factoriesSingletonObjects = new ConcurrentHashMap<>();


	public MyApplicationContext3() throws Exception{
		// 加载ioc容器:创建所有的Bean
		refresh();
	}

	// ioc容器加载
	private  void refresh() throws Exception{
		// 解析配置 注册BeanDefinition
		loadBeanDefinitions();

		// 创建所有单例Bean
		finishBeanFactoryInitialization();
	}

	/**
	 * 创建所有的Bean
	 */
	private void finishBeanFactoryInitialization() throws Exception{
		for (String beanName : beanDefinitionMap.keySet()) {
			getBean(beanName);
		}
	}

	/**
	 * 根据beanName创建Bean
	 */
	public Object getBean(String beanName) throws Exception {
		// 判断Bean是否已经创建好。如果已经创建好了就直接返回,如果没有创建就开始创建
		Object bean = getSingleton(beanName);
		if(bean != null){
			return bean;
		}
		synchronized (singletonObjects) {
			// 双重检查锁,解决并发获取不完整的bean
			if(singletonObjects.containsKey(beanName)){
				return singletonObjects.get(beanName);
			}

			//1. 实例化
			RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
			Class<?> beanClass = beanDefinition.getBeanClass();
			bean = beanClass.newInstance();

			//2. 将代理的bean放入二级缓存
			earlySingletonObjects.put(beanName, bean);

			//3. 属性注入
			Field[] declaredFields = beanClass.getDeclaredFields();
			for (Field field : declaredFields) {
				// 拿到属性的Autowired注解
				Autowired autowired = field.getAnnotation(Autowired.class);
				// 如果有@Autowired,就要进行注入
				if (autowired != null) {
					// spring中先根据类型找,如果类型都一样,再根据名字找
					// 这里按名字找
					String name = field.getName();
					Object dependentBean = getBean(name);
					// 设置下访问权限
					field.setAccessible(true);
					field.set(bean, dependentBean);
				}
			}

			//4. 初始化
			if (bean instanceof InitializingBean) {
				InitializingBean initializingBean = (InitializingBean) bean;
				initializingBean.afterPropertiesSet();
			}


			// 5.将bean放入一级缓存

			// 再次获取代理bean  为了解决如果在循环依赖中创建了动态代理,需要拿到循环依赖中的proxy对象
			Object beanProxy = getSingleton(beanName);
			singletonObjects.put(beanName, beanProxy);
			// 6.一级缓存中的bean创建完后,将二级缓存中的去掉
			earlySingletonObjects.remove(beanName);
			factoriesSingletonObjects.remove(beanName);
		}
		return bean;
	}

	/**
	 * 创建Bean是否创建
	 * @param beanName
	 */
	private Object getSingleton(String beanName) {
		// 一级缓存中有则返回,否则从二级缓存中拿
		if(singletonObjects.containsKey(beanName)){
			return singletonObjects.get(beanName);
		}

		synchronized (singletonObjects){
			// 三级缓存
			if(factoriesSingletonObjects.containsKey(beanName)){
				return factoriesSingletonObjects.get(beanName);
			}

			// 二级缓存
			// 所有的bean实例化后就创建proxy, 应该判断只有出现循环依赖才创建proxy
			if(earlySingletonObjects.containsKey(beanName)){
				Object bean = earlySingletonObjects.get(beanName);
				Object beanProxy = new JdkProxyBeanPostProcessor().getEarlyBeanReference(bean, beanName);
				factoriesSingletonObjects.put(beanName, beanProxy);
				return beanProxy;
			}
		}

		return null;
	}


	/**
	 * 根据配置信息创建BeanDefinition 会根据配置信息动态创建
	 */
	private void loadBeanDefinitions() {
		// 创建A BeanDefition
		RootBeanDefinition aBeanDefinition = new RootBeanDefinition(InstanceA.class);
		// 创建B BeanDefinition
		RootBeanDefinition bBeanDefinition = new RootBeanDefinition(InstanceB.class);
		beanDefinitionMap.put("instanceA", aBeanDefinition);
		beanDefinitionMap.put("instanceB", bBeanDefinition);

	}


	public static void main(String[] args) throws Exception {
		MyApplicationContext3 context = new MyApplicationContext3();
		InstanceA instanceA = (InstanceA)context.getBean("instanceA");
		System.out.println(instanceA);
	}
}

package com.learning.circulardependency;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @Author wangyouhui
 * @Description jdk动态代理
 **/
public class JdkDynamicProxy implements InvocationHandler {

	private Object target;

	public JdkDynamicProxy(Object target) {
		this.target = target;
	}

	public <T> T getProxy(){
		return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("proxy增强");
		return method.invoke(target, args);
	}
}

package com.learning.circulardependency;

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

/**
 * @Author wangyouhui
 * @Description TODO
 **/
public class JdkProxyBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {

	@Override
	public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		// 假设InstanceA被切点命中,需要创建代理 @PointCut(execution...)
		if(bean instanceof InstanceA){
			JdkDynamicProxy jdkDynamicProxy = new JdkDynamicProxy(bean);
		}
		return null;
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王佑辉

老板,赏点吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值