(spring-第6回)BeanDefinition——实例化Bean的第一大利器。

上节讲了Bean实例化的内部机制,这里再复述一遍:

  1. ResourceLoader从系统中加载XML配置信息,并由Resource来表示。
  2. BeanDefinitionReader从Resource中读取配置信息,把配置文件中的<bean>解析成一个BeanDefinition对象,然后把BeanDefinition对象放到BeanDefinitionRegistry注册表中。
  3. 容器从BeanDefinitionRegistry注册表中扫描出Bean工厂后处理器的Bean(该Bean实现了BeanFactoryPostProcessor),用这个工厂后处理器来加工BeanDefinitionRegistry注册表中的所有BeanDefinition对象。具体做了两件事:
    1.   对使用到<bean>元素的占位符的Bean进行解析,把占位符转换成具体值,从而把半成品的BeanDefinition对象转为成品的对象。
    2.   扫描BeanDefinitionRegistry注册表中的所有BeanDefinition对象,通过java反射机制找出所有属性编辑器的Bean(实现了PropertyEditor的Bean),然后把它放到属性编辑器注册表中(PropertyEditorRegistry)。
  4. 容器从BeanDefinitionRegistry中取出加工过的BeanDefinition,并调用InstantiationStrategy着手bean的实例化工作。
  5. 在实例化Bean时,Spring容器使用BeanWrapper对Bean进行封装,BeanWrapper结合BeanDefinition以及属性编辑器完成Bean属性的设置工作。
  6. 利用容器中注册的Bean后处理器(该Bean实现了BeanPostProcessor)对第五步生成的Bean进行后续加工。

从实例化的过程中可以看出,BeanDefinition起到中流砥柱的作用。因为BeanDefinition是配置文件<bean>元素标签在容器中的内部表示。比如,<bean>标签在XML中有class,scope,lazy-init等属性,那么在BeanDefinition中则有相应的beanClass,scope,lazyInit属性等。

BeanDefinition接口的继承结构如图:

顶级的BeanDefinition其实是个接口,下面的AbstractBeanDefinition实现了这个接口,而最下面的ChildBeanDefinition和RootBeanDefinition分别继承了AbstractBeanDefinition。来看一个XML配置:

 1  <!-- 父子<bean> -->
 2     <bean id="car0" class="com.baobaotao.tagdepend.Car"
 3           p:brand="红旗CA72" p:price="2000.00" p:color="黑色"
 4           abstract="true"/>
 5
 6     <bean id="car3" parent="abstractCar">
 7         <property name="color" value="红色"/>
 8     </bean>
        

car3继承了car0,对应继承结构图,car3使用的是ChildBeanDefinition,car0使用的是RootBeanDefinition,也就是说,car3的属性多于car0,而不管是car3还是car0,它们都有共性(即使配置文件中没写,也是隐形存在的,比如上面讲的scope,lazyInit等),这些共性将提取在AbstractBeanDefinition中。如果<bean>标签没有继承关系,那么它将使用默认的RootBeanDefinition,在2.5版本之后加了一个GenericBeanDefinition,因为自身优势而成为默认的使用类。

下面是BeanDefinition的API:(在线文档:http://tool.oschina.net/apidocs/apidoc?api=Spring-3.1.1)

在方法概述中,我们可以看到这个接口中定义了所有<bean>属性的方法接口,比如singleton、prototype,lazyInit等。

下面是AbstractBeanDefinition的结构图和API:

由于API里的方法很多,我截取几个例子:

这些get方法是获取共性类的属性值,实际上,共性属性的默认值在定义成员变量时就已经默认给定了,请看代码:

 1 private volatile Object beanClass;
 2
 3     private String scope = SCOPE_DEFAULT;
 4
 5     private boolean singleton = true;
 6
 7     private boolean prototype = false;
 8
 9     private boolean abstractFlag = false;
10
11     private boolean lazyInit = false;
12
13     private int autowireMode = AUTOWIRE_NO;
14
15     private int dependencyCheck = DEPENDENCY_CHECK_NONE;
16
17     private String[] dependsOn;
18
19     private boolean autowireCandidate = true;
20
21     private boolean primary = false;

上面代码截取的是AbstractBeanDefinition的源码,可以看到许多<bean>标签的属性默认值。

一开始创建的BeanDefinition由于占位符的原因是个半成品,需要用Bean工厂后处理器对Bean进行处理,处理完之后由InstantiationStrategy对BeanDefinition进行实例化。后面我们会详细介绍InstantiationStrategy。

BeanDefinition是如何创建的,XML又是如何被解析的?这些问题需要深入到源码中去寻求答案,在讲完IoC部分之后,我将对源码进行剖析,深入探究其奥妙,希望大家继续支持并关注我的博客。

时间: 2024-10-10 06:07:46

(spring-第6回)BeanDefinition——实例化Bean的第一大利器。的相关文章

Spring 使用静态工厂方式实例化Bean

知识点介绍: 静态工厂顾名思义,就是通过调用静态工厂的方法来获取自己需要的对象,为了让spring管理所有对象,我们不能直接通过"工程类.静态方法()"来获取对象,而是依然通过spring注入的形式获取. [转载使用,请注明出处:http://blog.csdn.net/mahoking] 操作步骤: 1.创建Speaker对象. /** * 静态工厂类 * */ public class Speaker { private String name ; private String t

Spring 使用实例工厂方法实例化Bean

知识点介绍: 实例工厂的意思是获取对象实例的方法不是静态的,所以你需要首先new工厂类,再调用普通的实例方法. [转载使用,请注明出处:http://blog.csdn.net/mahoking] 操作步骤: 1.创建Speaker对象. public class Speaker { //使用实例工厂方法实例化Bean private String speakerName; public Speaker(String speakerName) { this.speakerName = speak

spring在IoC容器中装配Bean详解

1.Spring配置概述 1.1.概述 Spring容器从xml配置.java注解.spring注解中读取bean配置信息,形成bean定义注册表: 根据bean定义注册表实例化bean: 将bean实例放入bean缓存池: 应用程序使用bean. 1.2.基于xml的配置 (1)xml文件概述 xmlns------默认命名空间 xmlns:xsi-------标准命名空间,用于指定自定义命名空间的schema文件 xmlns:xxx="aaaaa"-------自定义命名空间,xx

【Spring源码分析】原型Bean实例化过程、byName与byType及FactoryBean获取Bean源码实现

原型Bean加载过程 之前的文章,分析了非懒加载的单例Bean整个加载过程,除了非懒加载的单例Bean之外,Spring中还有一种Bean就是原型(Prototype)的Bean,看一下定义方式: 1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi=&qu

(spring-第9回【IoC基础篇】)BeanFactoryPostProcessor,实例化Bean之前的第二大利器

继承结构图如上.在加载XML,注册bean definition之后,在实例化bean definition之前,必要的时候要用到BeanFactoryPostProcessor.它负责把XML中有些占位符式的属性还原成真实值.意思是说,有时候,XML中<bean>的属性值不固定,会随着外界因素变化,这时候,在<bean>中配置占位符,而另外定义一个属性文件来控制<bean>的属性.比如下面是一个数据库连接的XML配置: 1 <bean id="data

Spring实例化bean顺序问题,导致注入失败

我们可以通过Spring进行非常方便的管理bean,只需要在类上面加一个注解就可以进行bean的注入,也就是所谓的DI.今天碰到了个小问题,来总结一下. 问题如下: public abstract class TestBean { public String str; public TestBean(){ this.str = initStr(); } protected abstract String initStr(); } public class TestSon extends Test

(spring-第13回【IoC基础篇】)PropertyEditor(属性编辑器)--实例化Bean的第五大利器

上一篇讲到JavaBeans的属性编辑器,编写自己的属性编辑器,需要继承PropertyEditorSupport,编写自己的BeanInfo,需要继承SimpleBeanInfo,然后在BeanInfo中把特定的属性编辑器和需要编辑的属性绑定起来(详情请查看上一篇). Spring的属性编辑器仅负责将配置文件中的字面值转换成Bean属性的对应值.(而JavaBean的属性编辑器能够通过界面来手动设置bean属性的值).如果属性的类型不同,转换的方法就不同.正如javabean的属性编辑器一样,

spring什么时候实例化bean

简要说明spring什么时候实例化bean,首先要分2种情况  第一:如果你使用BeanFactory作为Spring Bean的工厂类,则所有的bean都是在第一次使用该Bean的时候实例化  第二:如果你使用ApplicationContext作为Spring Bean的工厂类,则又分为以下几种情况:       (1):如果bean的scope是singleton的,并且lazy-init为false(默认是false,所以可以不用设置),则ApplicationContext启动的时候就

Spring 实例化bean的方式

实例化bean的方式有三种: 1.用构造器来实例化 2.使用静态工厂方法实例化 3.使用实例工厂方法实例化 当采用构造器来创建bean实例时,Spring对class并没有特殊的要求, 我们通常使用的class都适用 基于XML的元数据配置文件,可以这样来指定bean类: 当采用静态工厂方法创建bean时,除了需要指定class 属性外,还需要通过factory-method属性来指定创建bean实例 的工厂方法.Spring将调用此方法(其可选参数接下来介绍)返回实例对象,就此而言, 跟通过普