Spring解决循环依赖问题及三级缓存的作用

下面是对于“Spring解决循环依赖问题及三级缓存的作用”的详细讲解:

一、什么是循环依赖问题?

在Spring中循环依赖是指两个或多个Bean互相依赖而形成的闭环,这样的循环依赖问题会导致Bean不能正确地完成依赖注入过程,从而导致应用程序启动失败。在依赖注入时,如果两个Bean之间相互依赖,但它们两个都没在容器中加载完成,那么就会出现循环引用的问题。例如,两个Bean有相互依赖的关系,当创建Bean A时,需要Bean B的某些属性值,而当创建Bean B时,也需要Bean A的某些属性值,这时就会形成循环依赖问题。

Spring提供了两种解决循环依赖的机制:通过BeanPostProcessor解决、使用三级缓存解决。

二、如何使用BeanPostProcessor解决循环依赖问题?

  1. 关于BeanPostProcessor

BeanPostProcessor是Spring框架中新增的特殊方法调用机制,它允许在BeanFactory组装Bean的过程中尽早的拦截到每个Bean,并进行一些增强或者替换,是SpringAOP的核心之一。

通过自定义BeanPostProcessor,可以在bean中指定需要解决的循环依赖,从而避免环依赖导致的问题。

  1. 示例说明

  2. 添加两个类:A和B

public class A {
    public B b;

    public void run() {
        ......
    }
}
public class B {
    public A a;

    public void run() {
        ......
    }
}
  • 解决方案

定义一个MyBeanPostProcessor,对bean进行特殊处理,解决循环依赖问题。

public class MyBeanPostProcessor implements BeanPostProcessor {
    private Map<String, Object> beanMap = new ConcurrentHashMap<>();

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        beanMap.put(beanName, bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        //1.先要判断当前的bean是否依赖了其他bean
        if (bean instanceof A) {
            A a = (A) bean;
            if (a.b == null){
                a.b = (B) beanMap.get("B");
            }
        } else if (bean instanceof B) {
            B b = (B) bean;
            if (b.a == null) {
                b.a = (A) beanMap.get("A");
            }
        }
        return bean;
    }
}

三、如何使用三级缓存解决循环依赖问题?

  1. 关于三级缓存

Spring容器初始化时,会先将BeanDefinition缓存到BeanDefinitionMap中,然后再把实例对象缓存到singletonObjects中,这就是Spring IOC容器的一级缓存和二级缓存,而三级缓存则是用来解决循环依赖问题的。

  1. 示例说明

  2. 添加两个类:C和D

public class C {
    public D d;

    public void run() {
        ......
    }
}
public class D {
    public C c;

    public void run() {
        ......
    }
}
  • 解决方案

在创建Bean时,当发现Bean正在创建中,则会将当前正在创建的Bean对象缓存到“三级缓存”中,等待整个Bean创建完毕后再进行属性注入。

public class MyClassPathXmlApplicationContext extends AbstractApplicationContext {
  private final ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

  //...
  private final Map<String, Object> singletonFactories = new ConcurrentHashMap<>(256);
  private final Map<String, Object> earlySingletonObjects = new HashMap<>(256);
  private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

  //...
  private void doCreateBean(String beanName, BeanDefinition beanDefinition) {
        Object singletonObject = getSingleton(beanName);
        if (singletonObject != null) {
            return singletonObject;
        }
        //...
        createBeanInstance(beanName, beanDefinition);
        //...
        this.factoryBeanObjectCache.put(beanName, new Object[]{mbd, bean});
    }

    protected Object createBeanInstance(String beanName, BeanDefinition beanDefinition) {
        Object bean;
        try {
            //创建Bean实例
            bean = beanDefinition.getBeanClass().newInstance();
        } catch (Exception e) {
            //...
        }
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, beanDefinition, bean));
        //...
        return bean;
    }

    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.isTrue(!this.singletonFactories.containsKey(beanName), "bean factory already registered for bean \"" + beanName + "\"");
        //缓存三级缓存
        this.earlySingletonObjects.put(beanName, singletonFactory);
    }

    protected Object getEarlyBeanReference(String beanName, BeanDefinition beanDefinition, Object bean) {
        Object exposedObject = bean;
        String[] dependsOn = beanDefinition.getDependsOn();
        if (dependsOn != null) {
            for (String dependsOnBean : dependsOn) {
                if (isDependent(beanName, dependsOnBean)) {
                    registerDependentBean(dependsOnBean, beanName);
                }
                getBean(dependsOnBean);
            }
        }
        return exposedObject;
    }
  //...
}

以上就是通过三级缓存解决循环依赖问题的过程示例。

希望以上的详细讲解能够对你有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring解决循环依赖问题及三级缓存的作用 - Python技术站

(0)
上一篇 2023年6月26日
下一篇 2023年6月26日

相关文章

  • kotlin基础教程之类和继承

    Kotlin基础教程之类和继承 1. 类的定义 在Kotlin中,用class关键字定义一个类,类名要符合驼峰命名规则。下面是一个示例: class Animal { // 类的属性 var name: String = "" // 类的方法 fun sleep() { println("$name is sleeping.&q…

    other 2023年6月26日
    00
  • 在Linux 命令行终端分屏的两种工具

    在Linux命令行终端中,有时候需要同时运行多个命令或程序,为了方便查看和管理,可以使用终端分屏工具。下面将介绍两种常用的终端分屏工具: 1. tmux tmux是一款强大的终端复用工具,可以同时在一个终端窗口中运行多个终端会话,并能够在它们之间切换和管理。以下是使用tmux的基本流程: 1.1 安装和启动tmux 在终端中输入以下命令安装tmux: sud…

    other 2023年6月26日
    00
  • vue递归实现树形组件

    题目要求讲解“vue递归实现树形组件”的完整攻略,为了使文章更加清晰,我们需要分为以下几个部分进行说明: 1.树形组件介绍 2.递归实现树形组件的基本原理 3.基本的树形组件实现 4.多层级嵌套树形组件实现 1.树形组件介绍 在计算机中,树形结构是一种非常常用的数据结构,我们可以利用树形结构来展示网站的导航菜单、商品分类等。 2.递归实现树形组件的基本原理 …

    other 2023年6月27日
    00
  • 最小人工智能硬件资源jetsonnanovs树莓派4b

    以下是关于“最小人工智能硬件资源Jetson Nano和树莓派4B”的完整攻略,包含两个示例。 Jetson Nano和树莓派4B Jetson Nano和树莓派4B都是流行的最小人工智能硬件资源,它们都可以用于开发和运行人工智能应用程序。以下是关于Jetson Nano和树莓派4B的详细攻略。 1. Jetson Nano Jetson Nano是一款由N…

    other 2023年5月9日
    00
  • FPGA学习

    概述 FPGA(Field Programmable Gate Array)是一种可编程逻辑器件,可以通过编程实现不同的电路功能。学习FPGA可以帮助我们更好地理解数字电路设计和嵌入式系统开发。本文将为您提供一份完整攻略,介绍如何学习FPGA。 FPGA学习攻略 步骤1:了解FPGA的基本概念 在学习FPGA之前,需要了解FPGA的基本概念,包括FPGA的结…

    other 2023年5月5日
    00
  • fw.qq.com/ipaddress已失效 javascript获得客户端IP的新方法

    \”fw.qq.com/ipaddress已失效 javascript获得客户端IP的新方法\”攻略 背景 在过去,我们可以通过访问\”fw.qq.com/ipaddress\”来获取客户端的IP地址。然而,最近这个方法已经失效了。本攻略将介绍一种新的方法,使用JavaScript来获取客户端的IP地址。 步骤 步骤一:使用第三方服务 我们可以使用第三方服务…

    other 2023年7月31日
    00
  • 通过python顺序修改文件名字的方法

    以下是通过python顺序修改文件名字的方法的完整攻略: 步骤一:导入os和re模块 在使用Python修改文件名之前,首先需要导入两个模块,即os和re。 import os import re os模块:提供了访问文件系统的功能,包括对文件和目录的创建、删除、重命名、修改权限等操作。 re模块:是Python中处理正则表达式的模块,我们可以用它来匹配文件…

    other 2023年6月26日
    00
  • 前端从后端获得数据方法

    前端从后端获得数据是Web开发中的一个重要环节。以下是一个完整攻略,介绍了前端从后端获得数据的方法: 步骤1:后端API 要从后端获得数据,必须首先创建后端API。后端API是一组接口,用于从数据库或其他数据源检索数据,并将其返回给前端。 以下是一个示例: from flask import Flask, jsonify app = Flask(__name…

    other 2023年5月6日
    00
合作推广
合作推广
分享本页
返回顶部