杭州网站建设提供商,如何快速的制作h5页面,响应式网站的意义,建设网页的公司文章目录 一、目标#xff1a;通过三级缓存解决循环依赖二、设计#xff1a;通过三级缓存解决循环依赖2.1 通过三级缓存解决循环依赖2.2 尝试使用一级缓存解决循环依赖 三、实现#xff1a;通过三级缓存解决循环依赖3.1 工程结构3.2 通过三级缓存解决循环依赖类图3.3 设置三… 文章目录 一、目标通过三级缓存解决循环依赖二、设计通过三级缓存解决循环依赖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 都初始化完成再处理代理对象的初始化。 思考如果有对象不只是简单的对象还有代理对象还有 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 MapString, 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(ClassT 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.A266474c2
com.lino.springframework.test.B6f94fa3e从测试效果和截图依赖过程中可以看到一级缓存也可以解决简单场景的循环依赖问题。其实 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.xml3.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 ObjectFactoryT {/*** 获取对象** 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 MapString, Object singletonObjects new ConcurrentHashMap();/*** 二级缓存提前暴露对象没有完全实例化的对象*/protected final MapString, Object earlySingletonObjects new HashMap();/*** 三级缓存存放代理对象*/private final MapString, ObjectFactory? singletonFactories new HashMap();private final MapString, DisposableBean disposableBeans new HashMap();Overridepublic 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;}Overridepublic 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() {SetString 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 SetObject earlyProxyReferences Collections.synchronizedSet(new HashSet());Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory (DefaultListableBeanFactory) beanFactory;}Overridepublic Object postProcessBeforeInstantiation(Class? beanClass, String beanName) throws BeansException {return null;}Overridepublic 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);}Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}Overridepublic 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;}CollectionAspectJExpressionPointcutAdvisor 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;}Overridepublic Object getEarlyBeanReference(Object bean, String beanName) {earlyProxyReferences.add(beanName);return wrapIfNecessary(bean, beanName);}Overridepublic 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();Overrideprotected 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 {// 实例化Beanbean 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_PROTOTYPEObject 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 FactoryBeanIMother {Overridepublic IMother getObject() throws Exception {return (IMother) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{IMother.class},(proxy, method, args) - 婚后媳妇妈妈的职责被婆婆代理了 method.getName());}Overridepublic Class? getObjectType() {return IMother.class;}Overridepublic 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 {Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println(关怀小两口(切面) method);}
}4.1.6 Spring属性配置文件 spring.xml ?xml version1.0 encodingutf-8 ?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdbean idhusband classcom.lino.springframework.test.bean.Husbandproperty namewife refwife//beanbean idhusbandMother classcom.lino.springframework.test.bean.HusbandMother/bean idwife classcom.lino.springframework.test.bean.Wifeproperty namehusband refhusband/property namemother refhusbandMother//bean!--AOP 配置验证三级缓存 --bean classcom.lino.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator/bean idbeforeAdvice classcom.lino.springframework.test.bean.SpouseAdvice/bean idmethodInterceptor classcom.lino.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptorproperty nameadvice refbeforeAdvice//beanbean idpointcutAdvisor classcom.lino.springframework.aop.aspectj.AspectJExpressionPointcutAdvisorproperty nameexpression valueexecution(* com.lino.springframework.test.bean.Wife.*(..))/property nameadvice refmethodInterceptor//bean/beans4.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 框架的情况下可能我们也会尽可能避免写出循环依赖的操作因为在没有经过加工处理后这样的依赖关系肯定会报错的。 这也是程序从 能用 到 好用 的升级。 在解决循环依赖的核心流程中主要是提前暴露对象的设计以及建立三级缓存的数据结构来存放不同时期的对象。 如果说没有如切面和工厂中的代理对象那么二级缓存也就可以解决了哪怕是只有一级缓存。但为了设计上的合理和可扩展性所以创建了三级缓存来放置不同时期的对象。