Spring依赖解析过程和重写bean定义

一.依赖解析过程

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

第一阶段:容器处理配置元数据并建立元数据中存在的Bean定义,容器还会对这些Bean定义验证是否正确。

注意:这一阶段Bean并没有被创建,相关的属性也没有被注入。

第二阶段:首先容器完成对Bean的创建,然后完成注入工作。 但实际上并不是所有的Bean都被创建。 我们知道,一些Bean的创建实际上触发了一连串其他依赖Bean的创建,而这些依赖Bean又会触发它们的依赖性的创建,以此类推。

注意:一个Bean在完全被创建且自己的依赖性被注入之前是不会作为一个依赖项注入到别的Bean中去的。所以构造器的循环注入会出现死锁情况。 还有,不建议我们使用循环注入。

二.重写Bean定义

Spring容器提供了两种不同形式的Bean重写机制:

第一种:发生在Bean配置元数据文件级别。
首先将配置元数据划分到多个不同的文件或类中去,然后再ApplicationContext(容器)创建期间指定这些文件或类组合在一起。此时Spring容器将来自不同配置源的所有Bean定义合并在一起,在这个期间,配置源的顺序很重要,若前后存在Bean重名,后者将覆盖前者。

第二种:发生在容器级别
ApplicationContext可能有父ApplicationContext,当它们俩的实例中共存了两个同名的Bean实例时,Spring将提供子ApplicationContext中所定义的Bean。

三.使用 depends-on 特性指定无关Bean之间的创建顺序

如果两个Bean之间有依赖关系,我们可以知道它们之间的创建顺序一定有先后关系。
但如果两个Bean定义彼此之间没有直接或间接的依赖,那么Bean的创建顺序就由Spring容器内部确定了,此时我们就无法精确控制Bean的创建顺序了?

当然不,我们可以在基于XML的配置中通过使用< bean >元素的depends-on特性来指定Bean之间的创建顺序。
例子:

<bean id="a" class="com.Spring.Study.A" depends-on="b,c" />

上面表示a的创建在b,c之后。

四.自动装配

有时我们并没有必要显式地在Bean定义中定义依赖项,这时我们可以让Spring容器自动地向Bean中注入依赖项,这个过程就叫做自动装配。

自动装配有三种模式:
byType,byName,constructor(不建议使用)

1.byType
在此模式中,Spring首先通过Java反射查看Bean定义中的类,然后尝试将容器中可用的Bean注入与其类型相匹配的属性。 此操作主要通过调用Setter方法完成。
在XML中是通过< bean > 元素的autowire特性来启用自动装配的。
例子:

<bean id="accountService" class="com.Spring.Study.AccountService" 
  autowire="byType" />

但如果有多个Bean实例适合自动装配到某一个特定属性中,必然会发生冲突导致失败,此时我们需要为Spring容器设置相关参数以便确定注入到那个实例中。

一种解决方法是从自动装配的候选Bean中进行过滤,并注入剩下的Bean,我们可以使用
autowire-candidate特性:

<bean id="accoutService" class="com.Spring.Study.AccountService" 
  autowire="byType" />

<bean id="accountDao" class="com.Spring.Study.AccountDao"
 autowire-candidate="false" /> 

进行accoutService装配时,将不考虑accountDao.

另一种解决方法是如果有多个候选Bean,则使用byName自动装配模式,这种情况下,容器尝试将属性名与Bean名称进行匹配并注入匹配的Bean

<bean id="accountService" class="com.Spring.Study.AccountService" 
 autowire="byName" />

如果Spring容器中没有候选的Bean将不会注入任何Bean。

五.Bean查找

在任何启用了Spring的应用程序中我们应该:
尽可能增加Spring管理的Bean的数量,减少处于Spring容器控制之外的其他对象的数量。

一.外部实例如何引用Spring内的Bean?
1.首先获取对该环境中ApplicationContext实例的引用。
2.通过使用ApplicationContext接口中定义的不同getBean()方法执行显式查找Bean。

二.如何在Spring管理的Bean内执行显式Bean查找?
我们仍需要对Spring管理的Bean中ApplicationContext实例的引用,以便可以调用其getBean()方法来执行Bean查找。为此Spring提供了org.springframework.context.ApplicationContextAware接口:

Public interface ApplicationContextAware extends Aware{
  void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

如果你所创建的Bean类实现了该接口,那么在创建期间Spring容器会将自身注入到Bean实例,如此一来,我们的Bean就可以访问自己的容器了。

猜你喜欢

转载自blog.csdn.net/c1776167012/article/details/106316348
今日推荐