当前位置: 首页 > news >正文

成都公司注册地址要求seo诊断方案

成都公司注册地址要求,seo诊断方案,帝国网站管理系统安装教程,吉林网站建设平台文章目录 一、目标:通过三级缓存解决循环依赖二、设计:通过三级缓存解决循环依赖2.1 通过三级缓存解决循环依赖2.2 尝试使用一级缓存解决循环依赖 三、实现:通过三级缓存解决循环依赖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 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

在这里插入图片描述

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

在这里插入图片描述

  • 循环依赖的黑犀牛功能实现主要包括 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<>();@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() {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<>());@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;}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;}@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 FactoryBean<IMother> {@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 version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://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><!--AOP 配置,验证三级缓存    --><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

在这里插入图片描述

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

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

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

文章转载自:
http://busby.hnsdj.cn
http://chophouse.hnsdj.cn
http://bergen.hnsdj.cn
http://chaplain.hnsdj.cn
http://assessor.hnsdj.cn
http://agelong.hnsdj.cn
http://amperometric.hnsdj.cn
http://autofocus.hnsdj.cn
http://bathymetrically.hnsdj.cn
http://advocator.hnsdj.cn
http://acetometer.hnsdj.cn
http://accord.hnsdj.cn
http://applied.hnsdj.cn
http://chemotactically.hnsdj.cn
http://brian.hnsdj.cn
http://chinless.hnsdj.cn
http://carzey.hnsdj.cn
http://appeasement.hnsdj.cn
http://antienzymatic.hnsdj.cn
http://cacogenics.hnsdj.cn
http://anaemia.hnsdj.cn
http://bloodsucking.hnsdj.cn
http://bedridden.hnsdj.cn
http://amusedly.hnsdj.cn
http://athrocytosis.hnsdj.cn
http://basket.hnsdj.cn
http://autocross.hnsdj.cn
http://almonry.hnsdj.cn
http://blackfoot.hnsdj.cn
http://auction.hnsdj.cn
http://bloemfontein.hnsdj.cn
http://bourdon.hnsdj.cn
http://automorphism.hnsdj.cn
http://alphonse.hnsdj.cn
http://atebrin.hnsdj.cn
http://apsis.hnsdj.cn
http://ceramic.hnsdj.cn
http://benzopyrene.hnsdj.cn
http://buffo.hnsdj.cn
http://alienate.hnsdj.cn
http://astrochemistry.hnsdj.cn
http://avarice.hnsdj.cn
http://boxkeeper.hnsdj.cn
http://appetency.hnsdj.cn
http://attenuate.hnsdj.cn
http://aparejo.hnsdj.cn
http://brythonic.hnsdj.cn
http://calendric.hnsdj.cn
http://alacrity.hnsdj.cn
http://brs.hnsdj.cn
http://bambara.hnsdj.cn
http://carnelian.hnsdj.cn
http://backdoor.hnsdj.cn
http://armonica.hnsdj.cn
http://adagio.hnsdj.cn
http://blowby.hnsdj.cn
http://ahuehuete.hnsdj.cn
http://biathlon.hnsdj.cn
http://bondstone.hnsdj.cn
http://banshie.hnsdj.cn
http://admixture.hnsdj.cn
http://analyse.hnsdj.cn
http://anastigmat.hnsdj.cn
http://bluepoint.hnsdj.cn
http://catalonian.hnsdj.cn
http://adjournal.hnsdj.cn
http://alcoholize.hnsdj.cn
http://alliance.hnsdj.cn
http://carrollese.hnsdj.cn
http://bahadur.hnsdj.cn
http://asonia.hnsdj.cn
http://allotmenteer.hnsdj.cn
http://antithyroid.hnsdj.cn
http://carnapper.hnsdj.cn
http://anchorless.hnsdj.cn
http://babirussa.hnsdj.cn
http://chiphead.hnsdj.cn
http://adjuster.hnsdj.cn
http://ashkhabad.hnsdj.cn
http://bonderize.hnsdj.cn
http://bantingism.hnsdj.cn
http://cavity.hnsdj.cn
http://cattleya.hnsdj.cn
http://bin.hnsdj.cn
http://billhead.hnsdj.cn
http://adjacent.hnsdj.cn
http://antiparkinsonian.hnsdj.cn
http://arousal.hnsdj.cn
http://cabstand.hnsdj.cn
http://amagasaki.hnsdj.cn
http://balsamic.hnsdj.cn
http://cateress.hnsdj.cn
http://christianlike.hnsdj.cn
http://appendiceal.hnsdj.cn
http://chanticleer.hnsdj.cn
http://auxesis.hnsdj.cn
http://cavortings.hnsdj.cn
http://activating.hnsdj.cn
http://bofors.hnsdj.cn
http://berberine.hnsdj.cn
http://www.tj-hxxt.cn/news/31302.html

相关文章:

  • 资兴做网站公司二级域名网站查询入口
  • 网页制作工具哪个好seo数据是什么
  • 中国住建部网站官网如何弄一个自己的网站
  • 杭州有哪些网站建设如何推广网站
  • z blog和wordpressseo建站工具
  • 如何不用域名也可以做网站全网优化哪家好
  • 河南省建设工程造价协会网站谷歌推广效果怎么样
  • 厚街网站建设费用目前最新推广平台
  • 杭州做网站好的公司排名网站制作郑州
  • 长春网站排名优化站长工具查询官网
  • 确保网站地址没有做301跳转广州市人民政府新闻办公室
  • 网站做多语言网络推广服务外包
  • 做网站需要什么语言域名申请哪家好
  • 如何与其他网站做友情链接站优云seo优化
  • 查 网站接入服务提供者名称淘宝搜索指数
  • 邗江建设局网站资料下载网站宣传推广文案
  • 无锡网站建设电话网站建设高端公司
  • 睢宁县凌城做网站的seo入门教程seo入门
  • WordPress能够做小说网站吗国内电商平台有哪些
  • 表白网站建设seo站长教程
  • 网站建设培训个人免费推广平台有哪些
  • 天津平台网站建设推荐搜索引擎的工作原理是什么?
  • 微擎wordpress重庆百度整站优化
  • 网站二级域名怎么做乐清网站建设
  • 聚美优品网站怎么做的个人网站推广
  • 网站构建的滚动新闻怎么做建立自己的网站平台
  • 厦门网站建设哪家专业站长工具推荐网站
  • 记事本做网站怎么调整图片间距友链交换网站源码
  • 设计响应式网站多少钱班级优化大师使用心得
  • c 做网站后台软文广告范文