spring的bean的创建

本文详细剖析Spring框架中Bean的创建过程,包括BeanFactory、BeanDefinition、创建流程及资源读取实现,揭示Spring框架的核心设计思想。

spring作为一个轻量级J2EE应用框架,已经被广大的开发人员认为是最优秀的框架之一,得到了广泛的应用,其基于IOC的设计理念使得开发人员可以不必过多的关注框架层面的实现,可以更加专注于业务逻辑的实现。对于spring的分析文章已有很多,本人就将根据这就的理解来一步一步的分析spring的源代码,其中有不正确的地方还请大家拍砖指出,初次编写,有不好的地方请大家多多指正。
在spring的模块图如下:

spring一共包含7大模块,其中Spring Core模块是整个框架的最基础的部分,提供了IOC基础。Spring包的总体架构图如下:


从以上spring包的命名上看我们可以看出spring对j2ee提供了相当完善的支持,基本上是一个一站式服务的解决方案。
其中Core,beans包和context包是Spring Ioc的基础,没有他们也就没有了spring的上层应用如AOP,ORM,DAO等。在spring中,bean是最基本的元素,属于基础设施。而bean的创建获取操作均在beans包中完成。而bean是如何创建的呢?众所周知,BeanFactory是IoC容器的核心接口,它的职责包括:实例化,定位,配置应用程序中的对象及建立这些对象间的依赖。进入BeanFactory中我们可以看到其提供的接口功能主要有:
//根据bean名字或者id获取bean实例对象
Object getBean(String name) throws BeansException;
//这里根据bean的名字或者id和Class类型来得到bean实例,
Object getBean(String name, Class requiredType) throws BeansException;
//根据bean的名称或者id和相应的参数获取bean的实例,此处对于作用域为singleton的会报错
Object getBean(String name, Object[] args) throws BeansException;
//检查容器中是否含有该名称或者id的bean
boolean containsBean(String name);
//根据bean的名称或者id判断该bean的作用域是否为singleton
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
//根据bean的名称或者id判断该bean的作用域是否为prototype
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
//根据所给的bean名称或者id和类类型来获取相应的bean实例
boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException;
//根据所给的bean名称或者id获取该bean的类类型
Class getType(String name) throws NoSuchBeanDefinitionException;
//根据所给的bean的名称来获取或者id来获取该bean的别名
String[] getAliases(String name);


从上图中我们可以看到BeanFactory在当前包中有两个子类及一个实现类,即接口HierarchicalBeanFactory及ListableBeanFactory和实现类SimpleJndiBeanFactory,且在config包中有一个子类AutowireCapableBeanFactory,关于SimpleJndiBeanFactory(由spring2.5以后添加)我们暂且不关注其作用,先来看看剩下的三个接口:

接口名
作用
HierarchicalBeanFactory
此方法提供了两个接口,主要功能有判断当前BeanFactory中是否含有指定名称的bean、获取父BeanFactory
ListableBeanFactory
提供对容器内的bean的枚举与遍历功能:
查找是否有指定名称bean的定义
获取容器内bean的数量及所有bean的名称
根据指定类型获取bean的集合

AutowireCapableBeanFactory
提供自动装配的功能,即bean的创建等功能均由该接口实现,如createBean,autowireBean,configureBean等方法
从以上接口功能的设计及继承体系上看我们可以发现spring有着良好的接口设计,很好的体现了接口分级,不同级别的接口面对的对象不同,所需要提供的功能也不尽相同,和单一职责原则,并且接口分工明确,通过继承来完善和扩展主要接口的功能。其中BeanFactory属于spring的顶级接口,主要提供了与bean的查找的相关方法。其他继承自BeanFactory的接口,并从不同的方面完善了BeanFactory的功能。
就让我们先来看看bean是如何创建出来的?
对于接口AutowireCapableBeanFactory来说有一个子继承接口ConfigurableListableBeanFactory和一个抽象实现类AbstractAutowireCapableBeanFactory,相对于两个的子类来说,其最终的实现均为XmlBeanFactory。
AbstractAutowireCapableBeanFactory的依赖关系图


由上图我们可以看到AbstractAutowireCapableBeanFactory还继承了AbstractBeanFactory,并且在这个类中我们可以看到
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
我们进入CglibSubclassingInstantiationStrategy类中可以看到注释中有一段话“BeanFactory的默认类初始化策略”,其继承自SimpleInstantiationStrategy方法,我们可以在CglibSubclassingInstantiationStrategy类的注释中看到如果我们在应用中启用了CGLIB之后则spring将采用CGLIB来动态生成类的方式来实现方法的动态代理以及类的注入,当然BeanFactory容器仍然能够在CGLB没有使用的情况下正常工作。即如果在classpath写明了CGLIB运行库时将会采用CGLIB的动态代理,否则将采用JDK的默认动态代理。
由此可见如果在声明了CGLIB的情况下spring的bean创建默认是采用CGLIB的方式进行类的生成的。
AbstractAutowireCapableBeanFactory实现了AutowireCapableBeanFactory的接口的很多方法,在这里我们主要看spring的bean的创建过程,所以就先看看关于createBean的方法:
//根据给出的类来创建bean的实例,该方法创建的是一个全新的bean实例
Object createBean(Class beanClass) throws BeansException;
//根据指定装载策略和类创建一个该类的实例,装载策略包括AUTOWIRE_NO,AUTOWIRE_BY_NAME,AUTOWIRE_BY_TYPE,AUTOWIRE_CONSTRUCTOR,AUTOWIRE_AUTODETECT
Object createBean(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
关于两个方法的实现如下:
public Object createBean(Class beanClass) throws BeansException {
// Use prototype bean definition, to avoid registering bean as dependent bean.
RootBeanDefinition bd = new RootBeanDefinition(beanClass);
bd.setScope(SCOPE_PROTOTYPE);
return createBean(beanClass.getName(), bd, null);
}

public Object createBean(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
// Use non-singleton bean definition, to avoid registering bean as dependent bean.
RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
return createBean(beanClass.getName(), bd, null);
}
两个实现类的唯一区别在于RootBeanDefinition bd = new RootBeanDefinition(beanClass);和RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck);上面。其中RootBeanDefinition继承自AbstractBeanDefiniton,而从下图我们可以看出:

RootBeanDefinition,ChildBeanDefinition,GenericBeanDefinition均继承了AbstractBeanDefiniton,其中BeanDefinition是配置文件<bean>元素标签在容器中内部表示形式。<bean>元素标签拥有class、scope、lazy-init等配置属性,BeanDefinition则提供了相应的beanClass、scope、lazyInit属性,BeanDefinition和<bean>中的属性是一一对应的。其中RootBeanDefinition是最常用的实现类,它对应一般性的<bean>元素标签,GenericBeanDefinition是自2.5以后新加入的bean文件配置属性定义类,是一站式服务类。在配置文件中可以定义父<bean>和子<bean>,父<bean>用RootBeanDefinition表示,而子<bean>用ChildBeanDefiniton表示,而没有父<bean>的<bean>就使用RootBeanDefinition表示。AbstractBeanDefinition对两者共同的类信息进行抽象。
Spring通过BeanDefinition将配置文件中的<bean>配置信息转换为容器的内部表示,并将这些BeanDefiniton注册到BeanDefinitonRegistry中。Spring容器的BeanDefinitionRegistry就像是Spring配置信息的内存数据库,主要是以map的形式保存,后续操作直接从BeanDefinitionRegistry中读取配置信息。一般情况下,BeanDefinition只在容器启动时加载并解析,除非容器刷新或重启,这些信息不会发生变化,当然如果用户有特殊的需求,也可以通过编程的方式在运行期调整BeanDefinition的定义。
创建最终的BeanDefinition主要包括两个步骤:
1)利用BeanDefinitionReader对配置信息Resource进行读取,通过XML解析器解析配置信息的DOM对象,简单地为每个<bean>生成对应的BeanDefinition对象。但是这里生成的BeanDefinition可能是半成品,因为在配置文件中,我们可能通过占位符变量引用外部属性文件的属性,这些占位符变量在这一步还没有被解析出来。
2)利用容器中注册的BeanFactoryPostProcessor对半成品的BeanDefinition进行加工处理,将以占位符表示的配置解析为最终的实际值,这样半成品的BeanDefinition就为成品的BeanDefinition。

ConfigurableListableBeanFactory介绍


该接口的主要提供了一些分析和更改BeanDefinition的方法以及单例bean的预创建功能。从该类的继承关系上看我们发觉该接口同时继承了ListableBeanFactory, AutowireCapableBeanFactory以及ConfigurableBeanFactory接口,而HierarchicalBeanFactory则继承了HierarchicalBeanFactory和 SingletonBeanRegistry接口,由此可见一个ConfigurableListableBeanFactory就拥有了所有的这些接口功能,而其为什么还要分出这么多的接口类出来呢!?这就是接口的分级设计及单一功能体现,不同的接口提供不同的功能,并通过接口的继承来完善和扩展功能。
该接口具有一个实现类DefaultListableBeanFactory,该类通过一系列的继承实现了这些接口的所有方法,至此有关spring bean的创建,定义以及bean间关系的建立等均已完成,但是对于资源的读取并没有实现,通过下图我们可以看出

DefaultListableBeanFactory还有一个子类XmlBeanFactory,XmlBeanFactory是BeanFactory的一个常用实现,
进入该子类可以看出里面仅有两个构造方法:
//根据给出的资源创建XmlBeanFactory
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
//根据给出的资源以及父 BeanFactory创建XmlBeanFactory
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
现在我们可以总结出整个bean的生成过程了:
1:生成xml格式的配置文件
2:通过ResourceLoader将配置文件读入
3:通过BeanDefinitionReader将配置信息转换程BeanDefinition
4:在通过BeanFactory根据BeanDefinition信息创建bean实例
5:将bean实例放入SingletonBeanRegistry中以供使用
现在我们来看看bean的产生过程中这些接口,类的功能的划分,继承的层级可以发现spring对每一个功能都进行了很好的抽象,并进行了良好的接口功能划分,如BeanFactory接口,及其子类接口,虽然在最终我们看到只有一个类即DefaultListableBeanFactory通过继承实现了这些所有的接口。但是从这一点上我们可以看出spring将类的功能划分的非常细致,并不是讲所有的功能通过一个接口来体现,而是一步一步的分层级来实现这些功能,尽可能高度的抽象。

 

Spring框架Bean创建过程是其核心机制之一,涉及多个关键步骤和组件。整个流程由Spring容器管理,从读取配置信息开始,到最终生成可用的Bean实例。 ### BeanDefinition 的解析与注册 在Spring启动过程中,首先会根据配置(XML文件注解)加载并解析出`BeanDefinition`对象。`BeanDefinition`是一个接口,用于封装Bean的元数据信息,包括Bean的类名、作用域、生命周期回调、构造参数、属性设置等[^2]。例如,当使用基于注解的方式时,Spring会扫描带有@Component、@Service等注解的类,并将其转换为`BeanDefinition`对象。 接下来,这些`BeanDefinition`会被注册到`BeanFactory`中的`DefaultListableBeanFactory`实例里,以便后续创建Bean时使用。 ```java // 示例:手动注册一个BeanDefinition DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); RootBeanDefinition beanDefinition = new RootBeanDefinition(MyBean.class); beanFactory.registerBeanDefinition("myBean", beanDefinition); ``` ### 单例Bean的预实例化 一旦所有的`BeanDefinition`都已注册完毕,Spring容器将进入预实例化阶段。在这个阶段,默认情况下,所有非懒加载的单例Bean都会被创建并初始化。这一过程主要通过以下步骤完成: 1. **实例化Bean**:根据`BeanDefinition`中的类信息,调用构造函数工厂方法来创建Bean实例。 2. **填充属性**:如果Bean有依赖其他Bean,则Spring会自动注入这些依赖项。这一步骤涉及到自动装配(Autowiring)逻辑。 3. **设置Bean名称和BeanFactory**:将Bean的名称和当前使用的`BeanFactory`设置到Bean实例中,使其可以访问容器的相关资源。 4. **应用BeanPostProcessors**:在Bean初始化前后,调用`BeanPostProcessor`接口的方法,允许对Bean进行自定义处理。 5. **初始化Bean**:调用Bean的初始化方法,比如通过`@PostConstruct`注解标记的方法在`BeanDefinition`中指定的初始化方法。 6. **注册销毁方法**:确保Bean容器关闭时能够正确释放资源,如通过`@PreDestroy`注解指定的销毁方法。 ### 依赖注入与循环依赖处理 Spring框架支持多种类型的依赖注入,包括构造器注入、设值注入以及字段注入。对于复杂的依赖关系,特别是存在循环依赖的情况,Spring内部有一套完善的解决方案。它利用三级缓存机制来解决单例Bean之间的循环依赖问题,确保即使两个多个Bean相互依赖也能顺利创建。 ### 懒加载Bean的延迟实例化 除了默认的单例Bean外,还可以为某些Bean配置懒加载模式。这类Bean不会容器启动时立即被创建,而是等到第一次被请求时才进行实例化。这种方式有助于减少应用启动时间和内存占用。 ### 总结 综上所述,Spring框架中的Bean创建流程是一个高度自动化且复杂的过程,涵盖了从配置解析到最终Bean可用的所有必要步骤。理解这个过程不仅有助于更好地掌握Spring的工作原理,还能帮助开发者更有效地设计和调试应用程序。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值