软件编程
位置:首页>> 软件编程>> java编程>> Spring轻松解决循环依赖

Spring轻松解决循环依赖

作者:这堆干货有点猛  发布时间:2021-11-07 15:06:11 

标签:Spring,循环依赖

Spring 框架是一个流行的Java应用程序框架,它提供了许多强大的功能,如依赖注入和面向切面编程。然而在使用 Spring 框架时,我们可能会遇到循环依赖的问题。

这种情况发生在两个或多个 Bean 之间相互依赖的情况下,其中一个 Bean 依赖于另一个 Bean,而另一个 Bean 又依赖于第一个 Bean。在这种情况下,Spring 框架需要解决循环依赖的问题,否则应用程序可能会出现死锁或其他错误。

本文将探讨 Spring 框架是如何解决循环依赖的问题,以及它是如何工作的。我们将分析 Spring 框架的源代码,并提供一些示例来说明 Spring 框架如何解决循环依赖的问题。

解决循环依赖的原理

在 Spring 框架中,当两个或多个 Bean 之间相互依赖时, Spring 框架会创建一个代理对象,该代理对象负责管理这些 Bean 之间的依赖关系。这个代理对象被称为“early proxy”或“exposed proxy”。

当一个 Bean 需要访问另一个 Bean 时, Spring 框架会通过代理对象来获取该 Bean。这个代理对象负责保证 Bean 的实例化顺序,确保每个 Bean 都只被实例化一次,并且在所有依赖关系被满足之前,不会暴露任何未实例化的 Bean 。

Spring 框架解决循环依赖的过程如下:

  • 当 Spring 框架启动时,它会扫描应用程序中的所有 Bean,并将它们注册到一个 Bean Factory中。

  • 当一个 Bean 被实例化时Spring 框架会检查它是否有任何依赖关系。

  • 如果 Bean 有依赖关系,则 Spring 框架会检查这些依赖关系是否已经被创建。

  • 如果依赖关系已经被创建,则 Spring 框架会将依赖关系注入到 Bean 中,并返回该 Bean 的实例。

  • 如果依赖关系还没有被创建,则 Spring 框架会创建一个代理对象(通过 getEarlyBeanReference 方法),并将该代理对象暴露给该 Bean。

  • 当依赖关系被创建时,Spring 框架会使用代理对象来获取依赖关系,并将依赖关系注入到 Bean 中。

  • 当所有依赖关系都被满足时,Spring 框架会返回该 Bean 的实例。

源码解析

为了更好地理解 Spring 框架如何解决循环依赖的问题,我们将分析 Spring 框架的源代码。下面是一个简单的示例,演示了 Spring 框架如何解决循环依赖的问题。

public class A {
   private B b;
   public A() {}
   public void setB(B b) {
       this.b = b;
   }
}
public class B {
   private A a;
   public B() {}
   public void setA(A a) {
       this.a = a;
   }
}
@Configuration
public class AppConfig {
   @Bean
   public A a() {
       return new A();
   }
   @Bean
   public B b() {
       return new B();
   }
}

在这个示例中,类A依赖于类B,而类B又依赖于类A。因此,这个示例展示了一个循环依赖的情况。

当应用程序启动时,Spring 框架会扫描所有的 Bean ,并将它们注册到一个BeanFactory中。

当 BeanFactory创建 Bean 时,它会检查 Bean 是否有任何依赖关系。

在这个示例中,当 BeanFactory 创建 A 和 B 时,它会检查它们之间的依赖关系。由于 A 依赖于 B,而 B 又依赖于 A,因此存在循环依赖的问题。

为了解决这个问题,Spring 框架会创建一个代理对象,该代理对象负责管理A和B之间的依赖关系。在这个示例中,当 BeanFactory 创建 A 时,它会创建一个代理对象,并将该代理对象暴露给A。当BeanFactory创建B时,它会创建一个代理对象,并将该代理对象暴露给 B。这样,A和B就可以通过代理对象来访问彼此,而不会出现循环依赖的问题。

下面是 Spring 框架解决循环依赖的源码示例:

首先 Spring 框架会从缓存中获取需要的 bean:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
       synchronized (this.singletonObjects) {
           singletonObject = this.earlySingletonObjects.get(beanName);
           if (singletonObject == null && allowEarlyReference) {
               ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
               if (singletonFactory != null) {
                   singletonObject = singletonFactory.getObject();
                   this.earlySingletonObjects.put(beanName, singletonObject);
                   this.singletonFactories.remove(beanName);
               }
           }
       }
   }
   return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

上面代码中,框架分别从 singletonObjects、earlySingletonObjects、singletonFactories 中获取需要的实例,如果获取不到,就就行创建,在创建的过程中如果发现需要处理循环依赖,就会调用下面方法获取代理对象:

private Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   Object exposedObject = bean;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
       for (BeanPostProcessor bp : getBeanPostProcessors()) {
           if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
               SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
               exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
               if (exposedObject == null) {
                   return exposedObject;
               }
           }
       }
   }
   return exposedObject;
}

在这个示例中,getEarlyBeanReference() 方法是 Spring 框架用来获取代理对象的方法。该方法首先检查 Bean 是否为合成的 Bean ,然后检查该 Bean 是否有任何实例化后的 Bean 后处理器。如果 Bean 有实例化后的 Bean 后处理器,则 Spring 框架会使用这些 Bean 后处理器来获取代理对象。

Spring轻松解决循环依赖

来源:https://blog.csdn.net/wizard_hu/article/details/130081004

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com