zoukankan      html  css  js  c++  java
  • 依赖注入深度剖析

    一、循环依赖:

    有两个Bean——a和b,而这两个Bean通过各自的构造函数互为依赖项,那么Spring容器就无法实例化这两个Bean:

    public class A{

    private B b;

    public A(B b){

        this.b=b;

    }

    }

    public class B{

    private A a;

    public B(A a){

        this.a=a;

    }

    }

    <bean id=”a” class=”com.lizhen.A”>

        <constructor-arg ref=”b” />

    </bean>

    <bean id=”b” class=”com.lizhen.B”>

        <constructor-arg ref=”a” />

    </bean>

    这是因为当第一个Bean被创建时,期待第二个Bean被注入到自身。然而,此时第二个Bean也处于创建阶段,并且也期待第一个Bean作为自己的依赖项。这样就会在应用程序中导致BeanCurrentlyCreationException。但另一方面,Setter注入能够处理此类循环。虽然Spring通过使用Setter注入允许循环依赖,但对于那些有循环依赖的Bean而言,Spring的很多其他功能将无法使用。因此,一般来说,不建议在配置中使用循环依赖。

    二、依赖解析过程

    Spring容器的启动过程大致可分为两个主要阶段:

    ①  容器处理配置元数据并建立元数据中存在的Bean定义,在该过程中还会对这些Bean定义进行验证。例如,检查是否向<property>和<constructor—arg>元素提供正确的Bean引用,等等。然而,在该步骤中,Bean并没有被创建,相关的属性也没有被注入。

    ②  首先完成Bean的创建,然后完成依赖注入。但实际上,并不是所有的Bean都被创建;在容器启动期间,仅创建了无状态作用域的Bean。Bean的创建实际触发了一连串其他依赖Bean的创建,而这些依赖Bean又会触发它们的依赖项的创建,以此类推。

    一个Bean在被完全创建且自己的依赖项被注入之前是不会作为一个依赖项被注入到其他Bean中去的。因此,必须确保被注入某一Bean中的Bean依赖项被完全配置且可以在目标Bean中引用。(唯一类外的是上面所说的循环依赖)

    三、重写Bean定义

    重写Spring容器中的Bean定义是可能的。每个Bean都有身份(即id名),而Bean的名称定义了自己的身份。如果创建了一个Bean定义,而该Bean的名称已经赋予了其他Bean定义,那么第二个定义将重写第一个定义。

    四、depends-on特性

    如果Bean  a直接或间接依赖Bean b,那么可以肯定Spring容器将首先创建Bean b。然而,如果两个Bean定义彼此之间没有直接或间接依赖,那么Bean创建的顺讯就有Spring容器内部确定。此时,无法确保Bean b始终在Bean a之前被创建。有时,虽然Bean之间没有彼此依赖,但他们却需要彼此之间有一个特定的创建顺序。例如,一个执行JVM级别初始化的Bean必须在其他Bean之前被创建,因为这些Bean在被初始化之前必须先完成JVM级别的初始化。在此类情况下,可以在基于XML的配置中通过使用<bean>元素的depends-on特性来指定Bean  b 在Bean  a之前被创建。

    <bean id=”a” class=”com.lz.A” depends-on=”b,c” />

    可以在depends-on特性中列出多个Bean名称。同时,在Bean析构阶段和Bean初始化阶段,depends-on特性也扮演了非常重要的角色。只有在无状态Bean的情况下,当该Bean使用了depends-on特性时,depends-on特性中所列举的Bean才被销毁。

    作用:指定的Bean被创建之后才会创建本类,否则就不会创建本类。

    五、自动装配

    有时,并没有必要显示地在Bean定义中定义依赖项;可以让Spring容器自动地向Bean中注入依赖项。该过程成为自动装配。

    自动装配有三种模式:byType、byName和cinstructor

    byType模式:

    Spring首先通过Java反射查看Bean定义中的类,以便研究定义中的属性,然后尝试将容器中可用的Bean注入与器类型相匹配的属性。该注入操作主要是通过调用这些属性的Setter方法来完成的。例如:

    <bean id=”a” class=”com.lz.A”  autowire=”byType” />

    <bean id=”b” class=”com.lz.B”  />

    如果有多个Bean实例适合自动装配到某一个特定的属性,那么依赖注入将会失败。此时需要为Spring容器提供帮助,以便确定注入哪个Bean实例。其中一种解决办法是从自动装配的候选Bean中进行过滤,并注入剩下的Bean。为此,可以使用<bean>元素的autowire-candidate特性:

    <bean id=”a” class=”com.lz.A”  autowire=”byType” />

    <bean id=”b” class=”com.lz.B”  autowire-candidate=”false” />

    <bean id=”c” class=”com.lz.C”  />

    byName模式:

    上边情况的另外一种解决方法就是用byName自动装配模式,这种情况下,容器尝试将属性名与Bean名称进行匹配,并注入匹配的Bean。

    <bean id=”a” class=”com.lz.A”  autowire=”byName” />

    <bean id=”b” class=”com.lz.B”  />

    在Spring容器中没有候选Bean是将不会注入任何Bean,其默认属性值保持不变。

    constructor模式:

    该模式类似于byType模式,但在使用constructor模式时,Spring容器尝试找到那些类型与构造函数参数相匹配的Bean。同样,如果针对某一参数有多个候选Bean,Spring无法注入该参数。

  • 相关阅读:
    【leetcode】Recover Binary Search Tree
    【leetcode】Dungeon Game
    【leetcode】Text Justification
    【leetcode】Largest Number
    【leetcode】Merge k Sorted Lists
    【leetcode】Reverse Nodes in k-Group
    【leetcode】Multiply Strings
    【leetcode】Unique Binary Search Trees II
    hdu 1885 bfs+状压
    hdu 1429 bfs+状态压缩
  • 原文地址:https://www.cnblogs.com/lizhen-home/p/7819298.html
Copyright © 2011-2022 走看看