Spring--IoC

 注:spring 4.0 不再支持 ref local 标签。(参考:http://blog.csdn.net/fo11ower/article/details/51162312

1.简介

  org.springframework.beans 及 org.springframework.context 包是 Spring IoC 容器的基础。B

BeanFactory 提供的高级配置机制,使得管理任何性质的对象成为可能。ApplicationContext 是 BeanFactory 的扩展,功能得到了进一步的加强。简而言之,BeanFactory 提供了配置框架及基本功能,而 ApplicationContext 完全由 BeanFactory 扩展而来,因而 BeanFactory 所具备的能力和行为也适用于 ApplicationContext。

2.容器和 bean 的基本原理

在 Spring 中,那些组成应用的主体及由 Spring IoC 容器所管理的对象被称之为 bean。简单的讲,bean 就是由 Spring 容器初始化、装配及被管理的对象。而 bean 定义以及 bean 相互间的依赖关系将通过配置元数据来描述。

2.1容器

org.springframework.factory.BeanFactory 是 SpringIoC 容器的实际代表者,IoC 容器负责容纳此前所描述的 bean,并对 bean 进行管理。

在 Spring 中,BeanFactory 是 IoC 容器的核心接口。它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

Spring 提供了很多易用的 BeanFactory 实现,XmlBeanFactory 就是最常用的一个。http://docs.spring.io/spring/docs/current/javadoc-api/

 2.1.1配置元数据

从上图可以看到,Spring IoC 容器将读取配置元数据;并通过它对应用中各个对象进行实例化、配置及组装。

Spring 支持三种配置元数据格式:XML 格式、Java 属性文件格式或使用 Spring 公共 API 编程实现。通常情况下我们使用简单直观的 XML 来作为配置元数据的描述格式。

Spring IoC 容器可以通过多种途径来加载配置元数据,比如本地系统、Java Classpath 等。

Spring IoC 容器至少包含一个 bean 定义,但大多数情况下会有多个 bean 定义。

bean 定义与应用程序中实际使用的对象一一对应。通常情况下 bean 的定义包括:服务层对象、数据访问层对象(DAO)、类似 Structs Action 的表示层对象、Hibernate SessionFactory 对象、JMS Queue 对象等等。

以下是一个基于 XML 配置元数据的基本结构:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xsi:schemaLocation="http://www.springframework.org/schema/beans
 5         http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
 6 
 7        <bean id="ioCDemo01"  class="demo.ioc.IoCDemo01" >
 8        </bean>
 9 
10 </beans>

2.2实例化容器

 1 package demo.ioc;
 2 
 3 import org.springframework.beans.factory.BeanFactory;
 4 import org.springframework.beans.factory.xml.XmlBeanFactory;
 5 import org.springframework.context.ApplicationContext;
 6 import org.springframework.context.support.ClassPathXmlApplicationContext;
 7 import org.springframework.core.io.ClassPathResource;
 8 import org.springframework.core.io.FileSystemResource;
 9 import org.springframework.core.io.Resource;
10 
11 public class Test {
12     
13     public static void main(String[] args) {
14         String fileName = "applicationContext.xml";
15         
16         //1
17 //        Resource resource = new FileSystemResource(fileName);
18 //        BeanFactory factory = new XmlBeanFactory(resource);
19         
20         //2
21 //        ClassPathResource resource = new ClassPathResource(fileName);
22 //        BeanFactory factory = new XmlBeanFactory(resource);
23         
24         //3
25         ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{fileName});
26         BeanFactory factory = (BeanFactory) context;
27         
28         IoCDemo01 ioCDemo01 = (IoCDemo01) factory.getBean("ioCDemo01");
29         ioCDemo01.show();
30     }
31 
32 }

2.2.1组成基于 XML 配置元数据

将 XML 配置文件分拆成多个部分是非常有用的。为了加载多个 XML 文件生成一个 ApplicationContext 实例,可以将文件路径作为字符串数组传给 ApplicationContext 构造器。而 beanfactory 将通过调用 bean defintion reader 从多个文件中读取 bean 定义。

通常情况下,更倾向于上述做法,因为这样各个配置并不会查觉到与其他配置文件的组合。另外一种方法是使用一个或多个的 <import /> 元素来从另外一个或多个文件加载 bean 定义。所有的 <import /> 元素必须放在 <bean /> 元素之前以完成 bean 的导入。

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xsi:schemaLocation="http://www.springframework.org/schema/beans
 5         http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
 6     
 7     <import resource="applicationContext2.xml"/>
 8 
 9     <bean id="ioCDemo01"  class="demo.ioc.IoCDemo01" >
10     </bean>
11 
12 </beans>

2.3多种 bean

Spring IoC 容器管理一个或多个 bean,这些 bean 将通过配置文件中的 bean 定义被创建。

在容器内部,这些 bean 的定义由 BeanDefinition 对象来表示,该定义将包含以下信息:

全限定类名:这通常就是已定义 bean 的实际实现类。如果通常调用 static factory 方法来实例化 bean,而不是使用常规的构造器,那么类名实际上就是工厂类的类名。

bean 行为的定义,即创建模式(prototype 还是 singleton)、自动装配模式、依赖检查模式、初始化及销毁方法。这些定义将决定 bean 在容器中的行为。

用于创建 bean 实例的构造器参数及属性值。比如使用 bean 来定义连接池,可以通过属性或者构造参数指定连接数,以及连接池大小限制等。

bean 之间的关系,即协作(或者称依赖)。

除了通过 bean 定义来描述要创建的指定 bean 的属性之外,某些 BeanFactory 的实现也允许将那些非 BeanFactory 创建的、已有的用户对象注册到容器中,比如使用 DefaultListableBeanFactory 的 registerSingleton(..) 方法。不过大多数应用还是采用元数据定义为主。

2.3.1命名 bean

bean 的命名采用标准的 Java 命名约定,即小写字母开头,首字母大写间隔的命名方式。

对 bean 采用统一的命名约定将会使配置更加简单易懂。而且在使用 Spring AOP 时,如果要发通知(advice)给一组名称相关的 bean 时,这种简单的命名方式会受益匪浅。

每个 bean 都有一个或多个 id(或称之为标识符或名称)。这些 id 在当前 IoC 容器中必须唯一。如果一个 bean 有多个 id,那么其他的 id 在本质上将被认为是别名。

当使用基于 XML 的配置元数据时,将通过 id 或 name 属性来指定 bean 标识符。id 属性具有唯一性,而且是一个整整的 XML ID 属性,因此其他 xml 元素在引用该 id 时,可以利用 XML 解析器的验证功能。通常情况下最好为 bean 指定一个 id。尽管 XML 规范规定了 XML ID 命名的有效字符,但是 bean 标识符的定义不受该限制,因为除了使用指定的 xml 字符来作为 id,还可以为 bean 指定别名,要实现这一点可以在 name 属性中使用逗号、冒号或者空格将多个 id 分隔。为一个 bean 提供一个 name 并不是必须的,如果没有指定,那么容器将为其生成一个唯一的 name。

2.3.1.1bean 的别名

在对 bean 进行定义时,除了使用 id 属性来指定名称之外,为了提供多个名称,需要通过 alias 属性来加以指定。

在定义 bean 时就指定所有的别名并不总是恰当的。有时我们期望能在当前位置为那些在别处定义的 bean 引入别名。在 XML 配置文件中,可以单独的 <alias /> 元素来完成 bean 别名的定义。

1 <alias name="ioCDemo01" alias="a1"/>

2.3.2实例化bean

当需要的时候,容器会从 bean 定义列表中取得一个指定的 bean 定义,并根据 bean 定义里面的配置元数据使用反射机制来创建一个实际的对象。

当采用 XML 描述配置元数据时,将通过 <bean /> 元素的 class 属性来指定实例化对象的类型。class 属性通常是必须的(实例工厂方法实例化和 bean 定义的继续除外)。

class 属性主要有两种用途:在大多数情况下,容器将直接通过反射调用指定类的构造器来创建 bean;在极少数情况下,容器将调用类的静态工厂方法来创建 bean 实例,class 属性将用来指定实际具有静态工厂方法的类。

2.3.2.1用构造器来实例化

1 <bean id="ioCDemo01"  class="demo.ioc.IoCDemo01" >
2 </bean>

2.3.2.2使用静态工厂方法实例化

1 <bean id="calendar01" class="java.util.Calendar" factory-method="getInstance">
2 </bean>

2.3.2.3使用实例工厂方法实例化

与使用静态工厂方法实例化类似,用来进行实例化的实例工厂方法位于另外一个已有的 bean 中,容器将调用该 bean 的工厂方法来创建一个新的 bean 实例。

为使用此机制,class 属性必须为空,而 factory-bean 属性必须制定为当前(或其祖先)容器中包含工厂方法的 bean 的名称,而该工厂 bean 的方法本身通过 factory-method 属性来设定。

1 <bean id="clazz01" class="java.lang.Class" factory-method="forName">
2     <constructor-arg>
3         <value>demo.ioc.IoCDemo01</value>
4     </constructor-arg>
5 </bean>
6     
7 <bean id="ioCDemo012" factory-bean="clazz01" factory-method="newInstance">
8 </bean>    

虽然设置 bean 属性的机制仍然在这里被提及,但隐式的做法是由工厂 bean 自己来管理以及通过依赖注入(DI)来进行配置。

2.4使用容器

BeanFactory 提供六种方法供客户代码调用:

 

3.依赖

3.1注入依赖

依赖注入(DI)背后的基本原理是对象之间的依赖关系(即一起工作的其他对象)只会通过以下几种方式来实现:构造器的参数、工厂方法的参数,或给由构造函数或者工厂方法创建的对象设置属性。因此,容器的工作就是创建 bean 时注入那些依赖关系。相对于由 bean 自己来控制其实例化、直接在构造器中指定依赖关系或者类似服务定位器模式这 3 种自主控制依赖关系注入的方法来说,控制从根本上发生了倒转,这也正是控制反转名字的由来。

DI 主要有两种注入方式,即 Setter 注入和构造器注入。

3.1.1Setter 注入

通过调用无参构造器或无参 static 工厂方法实例化 bean 之后,调用该 bean 的 setter 方法,即可实现基于 setter 的 DI。

 1 <bean id="setter01" class="demo.ioc.di.SetterDemo01">
 2     <property name="a01">
 3         <ref bean="di01"/>
 4     </property>
 5     <property name="no">
 6         <value>1001</value>
 7     </property>
 8 </bean>
 9     
10 <bean id="di01" class="demo.ioc.di.A01">
11     <property name="description">
12         <value>AAAAA</value>
13     </property>
14 </bean>                
 1 package demo.ioc.di;
 2 
 3 public class SetterDemo01 {
 4     
 5     private A01 a01;
 6     
 7     private int no;
 8 
 9     public A01 getA01() {
10         return a01;
11     }
12 
13     public void setA01(A01 a01) {
14         this.a01 = a01;
15     }
16 
17     public int getNo() {
18         return no;
19     }
20 
21     public void setNo(int no) {
22         this.no = no;
23     }
24 
25     @Override
26     public String toString() {
27         return "SetterDemo01 [a01=" + a01.getDescription() + ", no=" + no + "]";
28     }
29     
30     
31 
32 }
 1 package demo.ioc.di;
 2 
 3 public class A01 {
 4 
 5     private String description;
 6 
 7     public String getDescription() {
 8         return description;
 9     }
10 
11     public void setDescription(String description) {
12         this.description = description;
13     }
14 
15 }

3.1.2构造器注入

基于构造器的 DI 通过调用带参数的构造器来实现,每个参数代表着一个协作者。此外,还可通过给静态工厂方法传参数来构造 bean。

 1 <bean id="di01" class="demo.ioc.di.A01">
 2     <property name="description">
 3         <value>AAAAA</value>
 4     </property>
 5 </bean>
 6 
 7 <bean id="constructDemo01" class="demo.ioc.di.ConstructDemo01">
 8     <constructor-arg type="String" value="Tom">
 9     </constructor-arg>
10     <constructor-arg type="String" value="male">
11     </constructor-arg>
12     <constructor-arg type="int" value="18">
13     </constructor-arg>
14     <constructor-arg type="String" value="i like play football">
15     </constructor-arg>
16     <constructor-arg>
17         <ref bean="di01"/>
18     </constructor-arg>
19 </bean>
 1 package demo.ioc.di;
 2 
 3 public class ConstructDemo01 {
 4 
 5     private String name;
 6     private String sex;
 7     private int age;
 8     private String description;
 9     private A01 a01;
10 
11     public ConstructDemo01(String name, String sex, int age, String description, A01 a01) {
12         super();
13         this.name = name;
14         this.sex = sex;
15         this.age = age;
16         this.description = description;
17         this.a01 = a01;
18     }
19     
20     public void introduce() {
21         System.out.println("Hello, my name is " + name + ", i'm " + age + " years old.");
22         System.out.println("Description : " + a01.getDescription());
23     }
24 
25 }

如何在构造器注入和 Setter 注入之间进行选择?

由于大量的构造器参数可能是程序变得笨拙,特别是当前某些属性是可选的时候。因此通常情况下,Spring 开发团队提倡使用 setter 注入。而且 setter DI 在以后的某个时候还可以将实例重新配置(或重新注入)。

尽管如此,构造器注入因为某些原因还是收到了一些人的青睐。一次性将所有依赖注入的做法意味着,在未完全初始化的状态下,此对象不会返回给客户端代码(或被调用),此外对象也不能再次被重新配置(或重新注入)。

BeanFactory 对于它所管理的 bean 提供两种注入依赖方式(实际上它也支持同时使用构造器注入和 Setter 方式注入依赖)。需要注入的依赖保存在 BeanDefinition 中,它能根据指定的 PropertyEditor 实现将属性从一种格式转换成另外一种格式。

处理 bean 依赖关系通常按一下步骤进行:

1)根据定义 bean 的配置(文件)创建并初始化 BeanFactory 实例(大部分的 Spring 用户使用支持 XML 格式配置文件的 BeanFactory 或 ApplicationContext 实现)。

2)每个 bean 的依赖将以属性、构造器参数、或静态工厂方法参数的形式出现。当这些 bean 被实际创建时,这些依赖也将会提供给该 bean。

3)每个属性或构造器参数既可以是一个实际的值,也可以是对该容器中另一个 bean 的引用。

4)每个指定的属性构造器参数必须能够被转换成属性或构造参数所需的类型。默认情况下,Spring 会能够以 String 类型提供值转换成各种内置类型,比如 int、long、String、boolean 等。

Spring 会在容器被创建时验证容器中每个 bean 的配置,包括验证那些 bean 所引用的属性是否指向一个有效的 bean。然而,在 bean 被实际创建之前,bean 的属性并不会被设置。对于那些 singleton 类型和被设置为提前实例化的 bean(比如 ApplicationContext 中的 singleton bean)而言,bean 实例将于容器同时被创建。而另外一些 bean 则会在需要的时候被创建,伴随着 bean 被实际创建,作为该 bean 的依赖以及依赖 bean 的依赖 bean(以此类推)也将被创建和分配。

循环依赖。当你主要使用构造器注入的方式配置 bean 时,很有可能会产生循环依赖的情况。比如说,一个类 A,需要通过构造器注入类 B,而类 B 又需要通过构造器注入类 A。如果为类 A 和类 B 配置的 bean 被互相注入的话,那么 Spring IoC 容器将在运行时检测出循环引用,并抛出 BeanCurrentlyInCreationException 异常。

对于此问题,一个可能的解决方法就是修改源代码,将构造器注入改为 setter 注入。另一个解决方法就是完全放弃使用构造器注入,只是用 setter 注入。

Spring 会在 bean 创建时采取设置属性和依赖关系(只在需要时创建所依赖的其他对象)。Spring 容器被正确加载之后,当获取一个 bean 实例时,如果在创建 bean 或者设置依赖时出现问题,那么将抛出一个异常。因缺少或设置了一个无效属性而导致抛出一个异常的情况的确是存在的。因为一些配置问题而导致潜在的可见性被延迟,所以在默认情况下,ApplicationContect 实现中的 bean 采用提前实例化的 singleton 模式。在实际需要之前创建这些 bean 将带来时间与内存的开销。而这样做的好处就是 ApplicationContext 被加载的时候可以尽早的发现一些配置的问题。不过用户可以根据需要采用延迟实例化来替代默认的 singleton 模式。

当协作 bean 被注入到依赖 bean 时,协作 bean 必须在依赖 bean 之前完全配置好。即协作 bean 实例化完成,相关的依赖也设置完成。

3.2构造器参数的解析

 构造器参数将根据类型来进行匹配。如果 bean 定义中的构造器参数类型明确,那么 bean 定义中的参数顺序就是对应构造器参数的顺序。

3.2.1构造器参数类型匹配

可以在构造器参数定义中使用 type 属性来显式的指定参数所对应的简单类型。

1 <bean id="constructDemo02" class="demo.ioc.di.ConstructDemo02">
2     <constructor-arg type="String" value="Tom">
3     </constructor-arg>
4     <constructor-arg type="int" value="1">
5     </constructor-arg>
6 </bean>
 1 package demo.ioc.di;
 2 
 3 public class ConstructDemo02 {
 4 
 5     private String s1;
 6     private int s2;
 7 
 8     public ConstructDemo02(String s1, int s2) {
 9         super();
10         this.s1 = s1;
11         this.s2 = s2;
12     }
13 
14     @Override
15     public String toString() {
16         return "ConstructDemo02 [s1=" + s1 + ", s2=" + s2 + "]";
17     };
18 
19 }

3.2.2构造器参数索引

通过使用 index 属性可以显式的指定构造器参数出现顺序。

1 <bean id="constructDemo03" class="demo.ioc.di.ConstructDemo02">
2     <constructor-arg index="0" value="Jerry">
3     </constructor-arg>
4     <constructor-arg index="1" value="100">
5     </constructor-arg>
6 </bean>

使用 index 属性除了可以解决多个简单类型构造参数造成的模棱两可的问题之外,还可以用来解决两个构造参数类型相同造成的麻烦。index 属性值从 0 开始。

指定构造器参数索引是使用构造器 IoC 首选的方式。

3.3bean 属性及构造器参数详解

3.3.1直接量(基本类型、Strings 类型等)

<value /> 元素通过字符串来指定属性或构造器参数的值。

3.3.1.1idref 元素

idref 元素用来将容器内其他 bean 的 id 传给 <constructor-arg /> 或 <property /> 元素,同时提供错误验证功能。

使用 idref 表级允许容器在部署时,验证所被引用的 bean 是否存在。

如果被引用的 bean 在同一 XML 文件内,且 bean 名字就是 bean id,那么可以使用 local 属性。

idref元素允许将容器中另一个bean的bean id(这是字符串值不是引用)传递给一个<property />或<constructor-arg />。在给定的示例中,它清楚地显示了如何将bean id传递给另一个bean,并显示bean ID。(参考:http://www.roseindia.net/tutorial/spring/spring3/ioc/springidrefelement.html#

 1 package demo.ioc.di2;
 2 
 3 public class FirstBean {
 4 
 5     private String message = null;
 6 
 7     public String getMessage() {
 8         return message;
 9     }
10 
11     public void setMessage(String message) {
12         this.message = message;
13     }
14 
15 }
 1 package demo.ioc.di2;
 2 
 3 public class AnotherBean {
 4     private String amessage = null;
 5 
 6     public String getAmessage() {
 7         return amessage;
 8     }
 9 
10     public void setAmessage(String amessage) {
11         this.amessage = amessage;
12     }
13 
14     public void display() {
15         System.out.println(amessage);
16     }
17 }
 1 package demo.ioc.di2;
 2 
 3 import org.springframework.beans.factory.BeanFactory;
 4 import org.springframework.context.support.ClassPathXmlApplicationContext;
 5 
 6 public class IDREFMain {
 7     public static void main(String[] args) {
 8         BeanFactory beanfactory = new ClassPathXmlApplicationContext("applicationContextdi2.xml");
 9         AnotherBean bean = (AnotherBean) beanfactory.getBean("another");
10         bean.display();
11     }
12 }
1 <bean id="first" class="demo.ioc.di2.FirstBean">
2     <property name="message" value="Spring is simple." />
3 </bean>
4 
5 <bean id="another" class="demo.ioc.di2.AnotherBean">
6     <property name="amessage">
7     <idref bean="first" />
8     </property>
9 </bean>

3.3.2引用其他的 bean

在 <constructor-arg /><property /> 元素内部还可以使用 ref 元素。该元素用来将 bean 中指定属性的值设置为对容器中的另外一个 bean 的引用。如前所述,该引用 bean 将被作为依赖注入,而且在注入之前会被初始化(如果是 singleton bean 则已被容器初始化)。尽管都是对另外一个对象的引用,但是通过 id/name 指向另外一个对象却有三种不同的形式,不同的形式将决定如何处理作用域及验证。

第一种形式也是最常见的形式,是通过使用 <ref /> 标记指定 bean 属性的目标 bean,通过该标签可以引用同一容器或父容器内的任何 bean(无论是否在同一 XML 文件中)。XML bean 元素的值既可以是指定的 bean 的 id也可以是其 name 值。

1 <ref bean="someBean" />

第二种形式是使用 ref 的 local 属性指定目标的 bean,它可以利用 XML 解析器来验证所引用的 bean 是否存在同一文件中。local 属性值必须是目标 bean 的 id 属性值。如果在同一配置文件中没有找到引用的 bean,XML 解析器将抛出一个异常。如果目标 bean 是在同一文件内,使用 local 方式就是最好的选择。

1 <ref local="someBean" />

第三种方式是通过使用 ref 的 parent 属性来引用当前容器的父容器中的 bean。parent 属性值既可以是目标 bean 的 id,也可以是 name 属性值。而且目标 bean 必须在当前容器的父容器中。使用 parent 属性的主要用途是为了用某个与父容器中的 bean 同名的代理来包装父容器中的一个 bean。parent 属性的使用并不常见。

3.3.3内部 bean

所谓的内部 bean 是指在一个 bean 的 <property /> 或 <constructor-arg /> 元素中使用 <bean /> 元素定义的 bean。内部 bean 定义不需要有 id 或 name 属性,即使指定 id 或 name 属性值也将会被容器忽略。

内部 bean 中的 singleton 标记 及 id 或 name 属性将被忽略。内部 bean 总是匿名的且他们总是 prototype 模式的。同时将内部 bean 注入到包含该内部 bean 之外的 bean 是不可能的。

实例:http://www.yiibai.com/spring/spring-inner-bean-examples.html

注入的时候注意构造函数。Setter 注入的话别忘了默认的构造函数。

3.3.4集合

通过 <list />、<set />、<map /> 及 <props /> 元素可以定义和设置与 Java Collection 类型对应 List、Set、Map 及 Properties 的值。

实例:http://blog.csdn.net/thc1987/article/details/5790792

3.3.4.1集合合并

从 2.0 开始,Spring IoC 容器将支持集合的合并。这样我们可以定义 parent-style 和 child-style 的 <list />、<set />、<map /> 及 <props /> 元素,子集合的值从其父集合继承和覆盖二来;也就是说,父子集合元素合并后的值就是子集合中的最终结果,而且子集合中的元素值将覆盖父集合中对应的值。

 1 <bean id="father" abstract="true" class="demo.ioc.combine.Father">
 2     <property name="list">
 3         <list>
 4             <value>test1</value>
 5             <value>test2</value>
 6         <value>test3</value>
 7     </list>
 8     </property>
 9 </bean>
10     
11 <bean id="son" parent="father" class="demo.ioc.combine.Son">
12     <property name="list" >
13         <list merge="true">
14             <value>host1</value>
15             <value>host2</value>
16     </list>
17     </property>
18 </bean>                
 1 package demo.ioc.combine;
 2 
 3 import java.util.List;
 4 import java.util.Map;
 5 
 6 public class Father {
 7 
 8     private List<String> list;
 9 
10     private Map<Integer, String> map;
11 
12     public List<String> getList() {
13         return list;
14     }
15 
16     public void setList(List<String> list) {
17         this.list = list;
18     }
19 
20     public Map<Integer, String> getMap() {
21         return map;
22     }
23 
24     public void setMap(Map<Integer, String> map) {
25         this.map = map;
26     }
27 
28 }
 1 package demo.ioc.combine;
 2 
 3 import java.util.List;
 4 import java.util.Map;
 5 
 6 import org.springframework.context.ApplicationContext;
 7 import org.springframework.context.support.ClassPathXmlApplicationContext;
 8 
 9 public class Son extends Father {
10 
11     private List<String> list;
12 
13     public List<String> getList() {
14         return list;
15     }
16 
17     public void setList(List<String> list) {
18         this.list = list;
19     }
20 
21     public void print() {
22         if (list != null) {
23             for (String s : list) {
24                 System.out.println(s);
25             }
26         }
27     }
28 
29     public static void main(String[] args) {
30         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContextCombine.xml");
31         Son son = (Son) context.getBean("son");
32         son.print();
33     }
34 }

参考:http://blog.csdn.net/opnmzxcvb/article/details/4971799

   http://liyixing1.iteye.com/blog/1036520

对于 <list />、<map /> 及 <set /> 集合将从父 <props /> 继承所有属性元素。同时子 bean 的suppory 值将覆盖父集合的相应值。

对于 <list /> ,父 bean 的列表内容将排在子 bean 列表内容的前面。对于 Map、Set 及 Properties 集合类型没有顺序的概念,因此作为相关的 Map、Set 及 Properties 实现基础的集合类型在容器内部没有排序的语义。

不同的集合类型是不能合并的,否则会抛出相应的 Exception。merge 属性必须在继承的子 bean 中定义,而在父 bean 的集合属性上指定的 merge 属性将被忽略。

3.3.4.2强类型集合

将 value 元素值转换为相应的泛型类型的值。

3.3.5Nulls

<null /> 用于处理 null 值。Spring会把属性的空参数当做空字符串处理。而 null 值可以使用 <null /> 元素来表示。

3.3.6XML-based configura metada shortcus

针对常见的 value 值或 bean 的引用,Spring 提供了简化格式用于替代 <value /> 和 <ref /> 元素。<property />、<constructor-arg /> 及 <entry /> 元素都支持 value 属性,他可以替代内嵌的 <value /> 元素。

3.3.7组合属性名称

当设置 bean 的组合属性时,除了最后一个属性外,只要其他属性值不为 null,组合或嵌套属性名是完全合法的。

组合属性在 bean 被构造后必须非空,否则会抛出长异常。

实例:http://blog.csdn.net/confirmaname/article/details/9362379

3.4使用 depends-on

一个 bean 对另一个 bean 的依赖最简单的做法就是将一个 bean 设置为另外一个 bean 的属性。在 xml 配置文件中最常见的就是使用 <ref /> 元素。有时候它还有另外一种变体,如果一个 bean 能感知 IoC 容器,只要给出他所依赖的 id,那么久可以通过编程的方式从容器中取得它所依赖的对象。

无论采用哪一种方法,被依赖 bean 将在依赖 bean 之前被适当的初始化。

在少数情况下,有时候 bean 之间的依赖关系并不是那么的直接。depends-on 属性可以用于当前 bean 初始化之前显式强制一个或多个 bean 被初始化。

实例:http://blog.csdn.net/pzw_0612/article/details/48021509

3.3.5延迟初始化 bean

ApplicationContext 实现的默认行为就是在启动时将所有 singleton bean 提前进行实例化。提前实例化意味着作为初始化过程的一部分,ApplicationContext 实例会创建并配置所有的 singleton bean。

如果不想让一个 singleton bean 在 ApplicationContext 实现在初始化时被提前实例化,那么可以将 bean 设置为延迟实例化。一个延迟初始化 bean 将告诉 IoC 容器是在启动时还是在第一次被用到时实例化。

在 XML 配置文件中,延迟初始化将通过 <bean /> 元素中的 lazy-init 属性来进行控制。

如果一个 bean 被设置为延迟初始化,而另一个非延迟初始化的 singleton bean 依赖于它,那么当 ApplicationContext 提前实例化 singleton bean 时,它必须也确保所有上述 singleton 依赖也被预先初始化,当然也包括设置为延迟实例化的 bean。

在容器层次中通过在 <beans /> 元素上使用 'default-lazy-init' 属性来控制延迟初始化也是可能的。

1 <beans default-lazy-init="true">
2         ...
3 <beans>

3.3.6自动装配(autowire)协作者

实例:http://blog.csdn.net/fengyun111999/article/details/6320486

Spring IoC 容器可以自动装配相互协作 bean 之间的关联关系。因此,如果可能的话,可以自动让 Spring 通过检查 BeanFactory 中的内容,来替我们指定 bean 的协作者。由于 autowire 可以针对单个 bean 进行设置,因此可以让有些 bean 使用 autowire,有些 bean 不采用。autowire 的方便之处在减少或者消除属性或构造参数的设置,这样可以给我们的配置文件减减肥。在 xml 配置文件中,autowire 一共有五种类型,可以在 <bean /> 元素中使用 autowire 属性指定。

模式

说明

no

(默认)不采用autowire机制.。这种情况,当我们需要使用依赖注入,只能用<ref/>标签。

byName

通过属性的名称自动装配(注入)。Spring会在容器中查找名称与bean属性名称一致的bean,并自动注入到bean属性中。当然bean的属性需要有setter方法。例如:bean A有个属性mastermastersetter方法就是setMasterA设置了autowire="byName",那么Spring就会在容器中查找名为masterbean通过setMaster方法注入到A中。

byType

通过类型自动装配(注入)。Spring会在容器中查找类(Class)与bean属性类一致的bean,并自动注入到bean属性中,如果容器中包含多个这个类型的beanSpring将抛出异常。如果没有找到这个类型的bean,那么注入动作将不会执行。

constructor

类似于byType,但是是通过构造函数的参数类型来匹配。假设bean A有构造函数A(B b,   C c),那么Spring会在容器中查找类型为BCbean通过构造函数A(B b, C c)注入到A中。与byType一样,如果存在多个bean类型为B或者C,则会抛出异常。但时与byType不同的是,如果在容器中找不到匹配的类的bean,将抛出异常,因为Spring无法调用构造函数实例化这个bean

default

采用父级标签(即beans的default-autowire属性)的配置。

如果直接使用 property 和 consturctor-arg 注入依赖的话,那么将总是覆盖自动装配。而且目前也不支持简单类型的自动装配,这里所说的简单类型包括基本类型、String、Class 以及简单类型的数组。自动装配还可以与依赖检查结合使用,这样依赖检查将在自动装配完成之后被执行。

优点:自动装配能显著减少配置的数量。不过,采用 bean 模板也可以达到同样的目的。

   自动装配可以使配置与 java 代码同步更新。

缺点:Spring 会尽量避免在装配不明确的时候进行猜测,因为装配不明确可能出现难以预料的结果,而且 Spring 所管理的对象之间的关联关系也不再能清晰的进行文档化。

   对于那些根据 Spring 配置文件生成文档的工具来说,自动装配将会使这些工具没法生成依赖信息。

   如果采用 by type 方式自动装配,那么容器中类型与自动装配 bean 的属性或者构造函数参数类型一致的 bean 只能有一个,如果配置可能存在多个这样的 bean,那么就要考虑采用显示装配了。

3.6.1设置 bean 使自动装配失效

当采用 xml 格式配置 bean 时,<bean /> 元素的 autowire-candidate 属性可被设为 false,这样容器在查找自动装配对象时将不考虑该 bean。

对于那些从来就不会被其他 bean 采用自动装配的方式来注入的 bean 而言,这是有用而。不过这并不意味着被排除的 bean 自己就不能使用自动装配来注入其他 bean,他是可以的,或者更准确的说,应该是他不会被考虑作为其他 bean 自动装配的候选者。

1 <bean id="a" class="demo.ioc.autowire.ClassA" autowire-candidate="false">
2     <property name="stringa" value="testa"></property>
3     <property name="stringb" value="testb"></property>
4     <property name="a" value="10000"></property>
5 </bean>
6 
7 <bean id="b" class="demo.ioc.autowire.ClassB" autowire="byType"></bean>

 3.7依赖检查

Spring 除了能对容器中 bean 的依赖设置进行检查外。还可以检查 bean 定义中实际属性值的设置,当然也包括采用自动装配方式设置属性值的检查。

当需要确保 bean 的所有属性值(或者属性类型)被正确设置的时候,那么这个功能会非常有用。当然,在很多情况下,bean 类的某些属性会具有默认值,或者有些属性并不会在所有场景下使用,因此这项功能会存在一定的局限性。就像自动装配一样,依赖检查也可以针对每一个 bean 进行设置。依赖检查默认为 none,他有几种不同的使用模式,在 xml 配置文件中,可以在 bean 定义中为 dependency-check 属性使用以下几种值:

模式 说明
none 没有依赖检查,如果 bean 的属性没有值的话可以不用设置
simple 对于原始类型及集合(除协作者外的一切东西)执行依赖检查
object 仅对协作者执行依赖检查
all 对协作者,原始类型及集合执行依赖检查

资料:http://biancheng.dnbcw.net/linux/413491.html

Spring 3.0 已取消该属性。

在 spring 3 中替代 dependency-check 有4条建议:

  • Use constructors (constructor injection instead of setter injection) exclusively to ensure the right properties are set.
  • 使用构造方法(使用构造方法注入替代setter注入)专门用来确认特定属性被初始化
  • Create setters with a dedicated init method implemented.
  • 用init方法初始化setter的属性
  • Create setters with @Required annotation when the property is required.
  • 在需要强制进行初始化的setters上标注@Required,可以参考http://www.mkyong.com/spring/spring-dependency-checking-with-required-annotation/
  • Use @Autowired-driven injection which also implies a required property by default.
  • 使用@Autowired-driven 注入也可以实现

3.8方法注入

在大部分情况下,容器中的 bean 都是 singleton 类型的。如果一个 singleton bean 要引用另外一个 singleton bean,或者一个非 singleton bean 要引用另外一个非 singleton bean时,通常情况下将一个 bean 定义为另一个 bean 的 property 值就可以了。不过对于具有不同生命周期的 bean 来说这样做就会有问题了,比如在调用一个 singleton 类型 bean A 的某个方法时,需要引用另一个非 singleton(prototype)类型的 bean B,对于 bean A 来说,容器只会创建一次,这样就没法在需要的时候每次让容器为 bean A 提供一个新的的 bean B 实例。

对于上面的问题Spring提供了三种解决方案: 

  • 放弃控制反转。通过实现ApplicationContextAware接口让bean A能够感知bean 容器,并且在需要的时候通过使用getBean("B")方式向容器请求一个新的bean B实例。
  • Lookup方法注入。Lookup方法注入利用了容器的覆盖受容器管理的bean方法的能力,从而返回指定名字的bean实例。
  • 自定义方法的替代方案。该注入能使用bean的另一个方法实现去替换自定义的方法。

实例:http://flysnow.iteye.com/blog/733785

4bean 的作用域

Spring 支持五种作用域(其中有三种只能用在基于 web 的 Spring ApplicationContext)

内置支持的作用域分列如下:

singleton

在每个Spring IoC容器中一个bean定义对应一个对象实例。

prototype

一个bean定义对应多个对象实例。

request

在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。

session

在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。

global session

在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。

4.1Singleton作用域

当一个 bean 的作用域为 singleton,那么 Spring IoC 容器中只会存在一个共享的 bean 实例,并且所有对 bean 的请求,只要 id 与该 bean定义相匹配,则只会返回 bean 的同一实例。Singleton 作用域是 Spring 中的缺省作用域。

1 <bean id=".." class=".." scope="singleton">
2         ...
3 </bean>

4.2Prototype作用域

Prototype 作用域的 bean 会导致在每次对该 bean 请求时都会创建一个新的 bean 实例。根据经验,对所有有状态的 bean 应该使用 prototype 作用域,而对无状态的 bean 则应该使用 singleton 作用域。

1 <bean id=".." class=".." scope="prototype">
2         ...
3 </bean>

对于 prototype 作用域的 bean,有一点非常重要,那就是 Spring 不能对一个 prototype bean 的整个生命周期负责:容器在初始化、配置、装饰或者是装配玩一个 prototype 实例后,将它交给客户端,随后就对该 prototype 实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对 prototype 而言,任何配置好的析构生命周期毁掉方法都不会被调用。清除 prototype 作用域的对象并释放任何 prototype bean 所持有的昂贵资源,都是客户端代码的职责。(让 Spring 容器释放被 singleton 作用域 bean 占用资源的一种可行方式是,通过使用 bean 的后置处理器,该处理器持有要被清除的 bean 的引用。)

4.3其他作用域

其他作用域,即 request、session 以及 global session 仅在基于 web 的应用中使用。

下面介绍的作用域仅仅在使用基于 web 的 spring applicationcontext 实现(如 xmlwebapplicationcontext)时有用。如果在普通的 spring ioc 容器中,比如像 xmlbeanfactory 或 classpathxmlapplicationcontext,尝试使用这些作用域,将会得到一个 illegalstateexception 异常。

4.3.1初始化 web 配置

要使用 request、session 和 global session 作用域的 bean(即具有 web 作用域的 bean),在开始设置 bean 定义之前,还要做少量的初始配置。

如果使用的是 servlet 2.4 及以上的 web 容器,那么需要在 web 应用的 xml 声明文件 web.xml 中增加下述 ContextListener 

1 <web-app>
2     ...
3     <listener>
4         <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
5     </listener>
6     ...
7 </web-app>

如果使用的是早起版本的 web 容器(Servlet 2.4 以前),那么需要使用一个 javax.servlet.Filter 的实现

 1 <web-app>
 2     ...
 3     <filter>
 4         <filter-name>requestContextFilter</filter-name>
 5         <filter-class>org.springframework.web.filter.RequestFilter</filter-class>
 6     </filter>
 7     <filter-mapping>
 8         <filter-name>requestContextFilter</filter-name>
 9         <url-pattern>/*</url-pattern>
10     </filter-mapping>
11     ...
12 </web-app>

RequestContextListener 和 RequestContextFilter 两个类做的都是同样的工作:将 HTTP request 对象绑定到为该请求提供服务的 Thread。这使得具有 requset 和 session 作用域的 bean 能够在后面的调用链中被访问到。

4.3.2Request 作用域

5定制 bean 特性

5.1Lifecycle 接口

Spring 提供了几个标志接口,这些接口用来改变容器中 bean 的行为;它们包括 InitializingBean 和 DisposableBean。实现这两个接口的 bean 在初始化和析构时容器会调用前者的 afterPropertiesSet() 方法,以及后者的 destory() 方法。

Spring 在内部使用 BeanPostProcessor 实现来处理它能找到的任何标志接口并调用相应的方法。如果需要自定义特性或者生命周期行为,可以实现自己的 BeanPostProcessor。

5.1.1初始化回调

实现 org.springframework.beans.factory.InitializingBean 接口允许容器在设置好 bean 的所有必要属性后,执行初始化事宜。InitializingBean 接口仅指定了一个方法:

1 void afterPropertiesSet() throws Exception;

通常,要避免使用 InitializingBean 接口,而且不鼓励使用该接口,因为这样会将代码和 spring 耦合,可以在 Bean 定义中指定一个普通的初始化方法,即在 xml 配置文件中通过指定 init-method 属性来完成。

 1 package demo.ioc.callback;
 2 
 3 import org.springframework.context.ApplicationContext;
 4 import org.springframework.context.support.ClassPathXmlApplicationContext;
 5 
 6 public class A {
 7     
 8     private String string;
 9     private int i;
10 
11     public String getString() {
12         return string;
13     }
14     public void setString(String string) {
15         this.string = string;
16     }
17     public int getI() {
18         return i;
19     }
20     public void setI(int i) {
21         this.i = i;
22     }
23     
24     public void init() {
25         System.out.println("init");
26     }
27 
28     public static void main(String[] args) {
29         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContextdiCallback.xml");
30 //        A a = (A) context.getBean("a");
31     }
32 }
 1 package demo.ioc.callback;
 2 
 3 import org.springframework.beans.factory.InitializingBean;
 4 import org.springframework.context.ApplicationContext;
 5 import org.springframework.context.support.ClassPathXmlApplicationContext;
 6 
 7 public class A2 implements InitializingBean {
 8     
 9     private String string;
10     private int i;
11 
12     public String getString() {
13         return string;
14     }
15     public void setString(String string) {
16         this.string = string;
17     }
18     public int getI() {
19         return i;
20     }
21     public void setI(int i) {
22         this.i = i;
23     }
24     
25     public void init() {
26         System.out.println("init");
27     }
28 
29     public static void main(String[] args) {
30         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContextdiCallback.xml");
31 //        A a = (A) context.getBean("a");
32     }
33     public void afterPropertiesSet() throws Exception {
34         // TODO Auto-generated method stub
35         System.out.println("init--");
36         
37     }
38 }
1 <bean id="a" class="demo.ioc.callback.A" init-method="init">
2 </bean>
3     
4 <bean id="a2" class="demo.ioc.callback.A2">
5 </bean>

5.1.2析构回调

实现 org.springframework.beans.factory.DisposableBean 接口的 bean 允许在容器销毁该 bean 的时候获得一次回调。DisposableBean 接口也只规定了一个方法:

1 void destory() throws Exception;

通常,要避免使用 DisposableBean 标志接口,可以在 bean 定义中指定一个普通的析构方法,即在 xml 配置文件中通过 destory-method 属性来完成。

5.1.2.1缺省的初始化和析构方法

生命周期回调方法的名称最好在一个项目范围内标准化。

可以将 Spring 容器配置成在每个 bean 上查找实现指定好的初始化和析构回调方法名称。这样就可以简化 bean 定义,比如根据约定将初始化回调命名为 init(),然后在基于 xml 的配置中,就可以省略 init-method="init" 配置,而 Spring IoC 容器将会在 bean 被创建的时候调用该方法。

1 <beans default-init-method="init">
2     ...
3 </beans>

该属性的出现意味着 Spring IoC 容器会把 bean 上名为 init 的方法识别为初始化方法回调,并且当 bean 被创建和装配的时候,如果 bean 类具有这样的方法,他将会在适当的时候被调用。

类似的,配置析构方法回调是在顶层 <beans /> 元素上使用 default-destory-method 属性。

如果实际的回调方法与默认的命名约定不同,那么可以通过在 <bean /> 元素上使用 init-method 和 destory-method 属性指定方法名来覆盖缺省设置。

5.1.2.2在非 web 应用中优雅的关闭 spring ioc 容器

 在基于 web 的 ApplicationContext 实现中已有相应的代码来处理关闭 web 应用时如何恰当地关闭 Spring IoC 容器。

如果在非 web 应用的环境下使用 Spring 的 IoC 容器,则需要在 JVM 里注册一个关闭钩子(shutdown hook)。为了注册关闭钩子,需要简单地调用在 AbstractApplicationContext 实现中的 registerShutdownHook() 方法即可。

1 AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
2 context.registerShutdownHook();

5.2了解自己

5.2.1BeanFactoryAware

对于实现了 org.springframework.beans.factory.BeanFactoryAware接口的类,当它被 BeanFactory 创建后,他会拥有一个指向创建它的 BeanFactory 的引用。

1 public interface BeanFactoryAware {
2 
3     void setBeanFactory(BeanFactory beanFactory) throws BeansException;
4 
5 }

这样 bean 可以以编程的方式操控创建他们的 BeanFactory,当然我们可以将引用的 BeanFactory 造型为已知的子类型来获得更多的功能。它主要用于通过编程来取得 BeanFactory 所管理的其他 bean。虽然在有些场景下这个功能很有用,但是一般来说应该尽量避免使用,因为这样将使代码与 Spring 耦合在一起,而且也有违反控制的原则(协作者应该作为属性提供给 bean)。

与 BeanFactoryAware 等效的另一种选择是使用 org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean。不过该方法依然没有降低与 Spring 的耦合,但是它并没有像 BeanFactoryAware 那样,违反 IoC 原则。

ObjectFactoryCreatingFactoryBean 是 FactoryBean 的一个实现,它返回一个执行工厂对象的引用,该对象将执行 bean 的查找。OObjectFactoryCreatingFactoryBean 类实现了 BeanFactoryAware 接口;被实际注入到客户端 bean 的是 ObjectFactory 接口的一个实例。这是 Spring 提供的一个接口(因而依旧没有完全与 Spring 解耦),客户端可以使用 ObjectFactory 的 getObject() 方法来查找 bean。你要做的全部事情就是给 ObjectFactoryCreatingFactoryBean 提供待查找 bean 的名字。

5.2.2BeanNameAware

假如 bean 实现了 org.springframework.beans.factory.BeanNameAware 接口并被部署在一个 BeanFactory 中,BeanFactory 会通过该接口的 setBeanName() 方法以告知其被部署时的 bean id。在 bean 属性被设置完成之后,在向 InitializingBean 的 afterPropertiesSet 或是自定义 init-method 这样的初始化回调执行之前,该接口的回调方法会被调用。

6bean 定义的继承

当使用基于 XML 的配置元数据时,给 parent 属性指定值,意味着子 bean 定义的声明。

如果子 bean 定义没有指定 class 属性,它将使用父 bean 定义的 class 属性,当然也可以覆盖它。在后面一种情况下,子 bean 的 class 属性值必须同父 bean 兼容,也就是它必须接受父 bean 的属性值。

一个子 bean 定义可以从 bean 继承构造器参数值、属性值以及覆盖父 bean 的方法,并且可以有选择地增加新的值。如果制定了 init-method,desroty-method 或 static factory-method,他们就会覆盖父 bean 相应的设置。

剩余的设置总是从子 bean 定义处得到:依赖、自动装配模式、依赖检查、singleton、作用域和延迟初始爱护。

抽象 bean 定义可作为子 bean 定义的模板。如果尝试单独使用这样的父 bean,将会导致错误;同样,容器内部的 preInstantiateSingletons() 方法会完全忽略 abstract 的 bean 定义。

默认情况下,ApplicationContext(不是 BeanFactory)会预实例化所有 singleton 的bean。因此很重要的一点是:如果只想把一个父 bean 定义当做模板使用,而他又制定了 class 属性,那么就得将 abstract 属性设置为 true,否则应用上下文将会预实例化抽象 bean。

1  <bean id="currency" abstract="true">
2    <property name="name" value="Tom"></property>
3    <property name="age" value="26"></property>
4    <property name="sex" value="male"></property>
5  </bean>
6     
7  <bean id="son" parent="currency" class="demo.ioc.inherit.Son">
8    <property name="favourite" value="play games"></property>
9  </bean>

7容器扩展点

Spring 框架的 IoC容器被设计为可扩展的。通常我们并不需要子类化各个 BeanFactory 或 ApplicationContext 实现类。而通过 plugin 各种集成接口实现来进行扩展。

7.1用 BeanPostProcessor 定制 bean

BeanPostProcessor  定义了几个回调方法,实现该接口可提供自定义(或默认地来覆盖容器)的实例化逻辑、依赖解析逻辑等。如果想在 Spring 容器完成 bean 的实例化、配置和其他的初始化后执行一些自定义逻辑,你可以插入一个或多个的 BeanPostProcessor 实现。

如果配置了多个 BeanPostProcessor ,那么可以通过设置 order 属性来控制 BeanPostProcessor 的执行次序(仅当 BeanPostProcessor  实现了 Ordered 接口时,才可以设置此属性,因此在编写自己的 BeanPostProcessor  实现时,就得考虑是否需要实现 Ordered 接口)。

实例:http://winneryj.iteye.com/blog/307736

7.2用 BeanFactoryPostProcessor 定制配置元数据

这个接口跟 BeanPostProcessor 类似,BeanFactoryPostProcessor 可以对 bean 的定义进行处理。也就是说 Spring IoC 容器允许 BeanFactroyPostProcessor 在容器实际实例化任何其他的 bean 之前读取配置与数据,并有可能修改它。

实例:http://blog.csdn.net/caihaijiang/article/details/35552859

如果想改变实际的 bean 实例,那么最好使用 BeanPostProcessor。

BeanFactoryPostProcessor 的作用域范围是容器级的。它只和所使用的容器有关。如果在容器中定义一个 BeanFactoryPostProcessor,它仅仅对此容器中的 bean 进行后置处理。BeanFactoryPostProcessor 不会对定义在另一个容器中的 bean 进行后置处理,即使这两个容器都是在同一层次上。

不要将 BeanFactoryPostProcessors 标记为延迟加载。否则 Spring 容器将不会注册他们,自定义逻辑就无法实现。如果在 <beans /> 元素的定义中使用了 default-lazy-init 属性,请确信各个 BeanFactoryPostProcessor 标记为 lazy-init="false"

原文地址:https://www.cnblogs.com/microcat/p/6775119.html