spring bean生命周期,spring框架老生常谈的话题,也是spring的基础知识。借此篇文章,结合spring框架部分源码,对spring针对bean的生命周期管理进行一个总结,加深记忆。
1. 概述
1.1 何为bean
在讲解bean的周期之前,我们先了解下什么是bean。自我们接触java开始,bean就无处不在。那么bean是什么?这里有两种解释,一种是狭义的,一种是广义的。在解释前,先简单介绍下bean的历史背景。
1.1.1 bean的来源与发展
在java诞生后不久,开发者为了让java更适用于桌面开发,借鉴vb等语言的特点,准备开发一套可视化ide。为了方便开发这款ide,开发者们为java定义了一套类定义规范:
1. 是public,有无参构造器
2. 有private属性
3. 有get/set方法,对属性进行访问和修改
4. 要能支持事件,如onClickListener等等
5. 要可序列化
6. ...
7. ...
这个规范就叫做bean,基于这个规范,sun公司推出了NetBeans IDE并风靡一时,直到后来,IBM推出了Visual Age for Java,Visual Age for Java就是eclipse的前身。
javabean的出现给java带来革命性的改变,但是依然没有人使用java进行桌面开发。直到在web开发领域,java才真正找到了自己的用武之地。javabean也没有被抛弃,人们将javabean作为数据传输介质,将控制器层(controller)和展示层(view)串联起来,这就是mvc框架。
在企业开发中当然不是这么简单,企业开发中可能需要事务、需要消息处理、需要分布式等等,为了满足企业开发要求,sun公司推出了J2EE规范,这个规范基本涵盖了java在web开发中的方方面面,如JDBC(Java Database Connectivity)、JDNI(Java Naming and Directory Interface)、JTA(Java Transaction API)等,还有最重要的,在javabean的基础之上,推出了EJB(Enterprise Java Beans),EJB规范因为可以无缝衔接其他规范,从而让开发人员无需关注事务处理、安全处理等琐碎的技术细节,所以在web开发中盛行起来。
随着互联网领域的规模越来越大,需求越来越多,迭代的速度越来越快,人们发现EJB已经无法适应当前的潮流,太繁琐、太笨重,人们开始给EJB进行瘦身,POJO(Plain Old Java Object)就诞生了。POJO摒弃了大部分EJB bean的规范,仅保留了简单的几条:
1. 是public,有无参构造器
2. 有private属性
3. 有get/set方法,对属性进行访问和修改
4. 可序列化
虽然抛弃了EJB,但是我们也想在使用POJO的时候?大神Rod Johnson推出了spring。通过将POJO委托给spring框架进行管理,我们依然可以实现在EJB时代的功能。当然,在spring生态中,不仅POJO是bean,被spring容器所管理的任意一个对象,都可以被称作bean。
spring的出现彻底改变了java开发圈子,所有人(至少是web开发者)大都会选择spring作为自己开发的首要框架。随着spring全家桶的完善,java开发者与spring生态绑定的越来越紧密。
1.1.2 bean的定义
介绍完历史,我们再说下何为bean。上文说过,bean可以从狭义和广义两个角度去看:
- 狭义的bean:即POJO或符合EJB规范的bean
- 广义的bean:即被spring容器所管理的所有对象
接下来,本篇文章中所描述的bean,皆为广义的bean。
1.2 spring bean模型
spring对所有的bean进行了一个统一的抽象建模,即BeanDefinition
,这里面包含了spring框架对bean的描述,如bean的class、bean的作用域、bean的依赖bean、bean是否是懒加载、bean的构造方法参数等等。spring通过这些信息,才能准确、无误、高效地管理一个bean。
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// 获取bean类名
@Nullable
String getBeanClassName();
// 获取bean的作用域
@Nullable
String getScope();
// 是否懒加载
boolean isLazyInit();
// 获取bean前置依赖的bean
@Nullable
String[] getDependsOn();
// 获取bean构造方法参数
ConstructorArgumentValues getConstructorArgumentValues();
// 获取bean的属性参数
MutablePropertyValues getPropertyValues();
...
1.3 bean创建前的流程
在spring容器启动后,会去扫描和解析我们配置的bean,包括注解和xml等方式配置的(扫描、解析过程这里暂不介绍)
并校验、创建BeanDefinition
,并交给BeanDefinitionHolder
持有:
public class BeanDefinitionHolder implements BeanMetadataElement {
private final BeanDefinition beanDefinition;
// bean名称
private final String beanName;
// bean的别名
@Nullable
private final String[] aliases;
...
到目前为止,spring并没有实例化任何一个bean,仅仅根据我们配置的信息创建了一个个BeanDefinition
,这里也体现了spring框架的基于元配置的编程思想。
以spring读取xml配置文件为例(注解配置细节有所不同,但基本流程是相似的):
spring容器(这里是ClassPathXmlApplicationContext
)启动时会去创建DefaultListableBeanFactory
/**
* This implementation performs an actual refresh of this context's underlying
* bean factory, shutting down the previous bean factory (if any) and
* initializing a fresh bean factory for the next phase of the context's lifecycle.
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建bean管理工厂
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
// 加载Bean配置
loadBeanDefinitions(beanFactory);
...
DefaultListableBeanFactory
实现了BeanDefinitionRegistry
接口,并持有所有注册的BeanDefinition
。
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
...
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
...
ClassPathXmlApplicationContext
会创建XmlBeanDefinitionReader
去加载bean
/**
* Loads the bean definitions via an XmlBeanDefinitionReader.
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see #initBeanDefinitionReader
* @see #loadBeanDefinitions
*/
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
// 使用xmlBeanDefinitionReader去加载配置的bean
loadBeanDefinitions(beanDefinitionReader);
}
XmlBeanDefinitionReader
会对我们提供的xml配置文件进行解析、校验等工作,然后遍历xml配置文件的每一个节点:
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
// 如果节点的标签是bean,则加载该节点所配置的bean数据
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
bean节点会被解析然后注册到DefaultListableBeanFactory
中
/**
* Process the given bean element, parsing the bean definition
* and registering it with the registry.
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 根据节点的配置,创建好BeanDefinitionHolder
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 将解析好的节点注册到DefaultListableBeanFactory当中
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
这里的代码进行实际的注册:
/**
* Register the given bean definition with the given bean factory.
* @param definitionHolder the bean definition including name and aliases
* @param registry the bean factory to register with
* @throws BeanDefinitionStoreException if registration failed
*/
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
// 注册bean
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
bean的注册还涉及到大段解析配置、校验逻辑,这里就不赘述了。上述代码得到的最终结果是,spring通过我们在xml文件中配置的bean创建了BeanDefinition
,至此,bean实例化的前置工作完成。
1.4 spring bean生命周期
spring bean被注册后,其生命周期才算正式开始。与普通的javabean生命周期不同,spring将bean的生命周期划分的更为细致,并且添加了多个扩展点(著名的BeanPostProcessor
接口),方便开发人员对bean的生命周期进行自定义扩展。上个图吧:
普通javabean生命周期