Spring Bean实例化过程

檀云
• 阅读 4278

上篇《Spring类扫描器记录》中, 记录了Spring扫描Class, 封装成一个个BeanDefinition的过程, ApplicationContext后续将根据这些Bean定义来创建Bean实例, BeanDefinition和Bean实例保存在的位置如下:

BeanDefinition保存到的实例变量(DefaultListableBeanFactory):

/** List of bean definition names, in registration order */
List<String> beanDefinitionNames

/** Map from bean name to merged RootBeanDefinition */
Map<String, RootBeanDefinition> mergedBeanDefinitions

Bean实例保存到的成员变量(DefaultListableBeanFactory):

/** 保存单例对象: bean名 --> bean实例 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

一个[BeanDefinition]到一个[Bean实例]是通过BeanFactory#getBean方法完成的:

BeanFactory#getBean方法执行过程:

Tags:(BeanFactory具体对应的子类是DefaultListableBeanFactory)

  1. 从单例缓存singletonObjects查找, 有则直接返回

没有则

  1. 创建实例
  2. 执行bean后置处理器,调用Bean初始化方法
    依赖注入是后置处理完成的,也是调用BeanFactory#getBean获取依赖对象
  3. 保存实例到singletonObjects中

参考百度脑图: [调用beanFactory.getBean获取/创建实例]节点

问题记录

1. 实例化Bean的位置

在上下文刷新时AbstractApplicationContext#refresh

// 执行完全部的BeanFactory后置处理
// ConfigurationClassPostProcessor会加载工程下的class到BeanDefinition
// 注册Bean后置处理器

// 根据BeanDefinition实例化所有单例Bean.
finishBeanFactoryInitialization(beanFactory);

2. 对象循环引用问题

getBean方法通过Bean后置处理器AutowiredAnnotationBeanPostProcessor注入依赖, 该后置处理器又将调用getBean获取依赖Bean, 例如有如下代码:

@Service
public class ServiceA {
    @Autowired
    ServiceB serviceB;
}

@Service
public class ServiceB {
    @Autowired
    ServiceA serviceA;
}

BeanFactory会将创建中的bean名保存到singletonsCurrentlyInCreation, 创建中的bean实例保存到singletonFactories。

getBean("serviceA")的过程:

  1. 创建ServiceA实例
  2. 创建ServiceB实例
  3. 实例ServiceA注入到ServiceB (实例ServiceA仍在初始化中)
  4. ServiceB完成创建
  5. 实例ServiceB注入到ServiceA
  6. ServiceA完成创建

被依赖的Bean会先完成初始化
参考图片链接: Spring循环引用逻辑结构图

3. 单例Bean创建后注册到哪了?

DefaultSingletonBeanRegistry对象的singletonObjects字段, 这里注册的都是依赖已经注入, 且执行完Bean后置处理器的实例

/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

4. 对象循环依赖异常

BeanCreationException: Circular depends-on relationship between
循环依赖会导致该异常, 如使用@DependsOn注解配置了依赖:

@Service
@DependsOn("permission")
public class Role {
    @Autowired
    private Permission permission;
}


@Service
@DependsOn("role")
public class Permission {
    @Autowired
    private Role role;
}

Permission,Role互相依赖, 谁无法被创建, BeanFactory将抛出异常
BeanCreationException:
Circular depends-on relationship between 'role' and 'permission'

点赞
收藏
评论区
推荐文章
Easter79 Easter79
4年前
spring源码解析
前言上篇我们介绍了spring容器加载的方式,并重点介绍了基于xml配置解析和注解扫描两种容器加载的方式,封装和注册beandefinition的过程。今天我们分享BeanDefinition注册后的另一个重要过程bean的实例化过程的源码。容器加载流程!spring源码解析spring容器加载源码(bean实
Easter79 Easter79
4年前
spring注解
随着越来越多地使用Springboot敏捷开发,更多地使用注解配置Spring,而不是Spring的applicationContext.xml文件。Configuration注解:Spring解析为配置类,相当于spring配置文件Bean注解:容器注册Bean组件,默认id为方法名@Configurat
从源码层面深度剖析Spring循环依赖
作者:郭艳红以下举例皆针对单例模式讨论图解参考1、Spring如何创建Bean?对于单例Bean来说,在Spring容器整个生命周期内,有且只有一个对象。Spring在创建Bean过程中,使用到了三级缓存,即DefaultSingletonBeanRegi
Easter79 Easter79
4年前
Spring使用静态工厂方法创建Bean
1\.使用静态工厂方法创建Bean    使用静态工厂方法创建Bean实例时,class属性也必须指定,但此时class属性并不是指定Bean实例的实现类,而是静态工厂类。因为Spring需要知道是用哪个工厂来创建Bean实例。另外,还需要使用factorymethod来指定静态工厂方法名,Spring将调用静态工厂方法(可能包含一组参数),
Stella981 Stella981
4年前
Spring Bean注册解析(一)
       Spring是通过IoC容器对Bean进行管理的,而Bean的初始化主要分为两个过程:Bean的注册和Bean实例化。Bean的注册主要是指Spring通过读取配置文件获取各个bean的声明信息,并且对这些信息进行注册的过程。Bean的实例化则指的是Spring通过Bean的注册信息对各个Bean进行实例化的过程。本文主要讲解Spring是如何
Wesley13 Wesley13
4年前
Spring学习详解(1)——Spring入门详解
一:spring的基本用法:1,关于spring容器:spring容器是Spring的核心,该容器负责管理spring中的java组件,ApplicationContextctx newClassPathXmlApplicationContext("bean.xml");//这种方式实例化容器,容器会自动预初始化所有Bean实例
Easter79 Easter79
4年前
Spring容器中Bean的作用域
当通过Spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。Spring支持如下5种作用域:singleton:单例模式,在整个SpringIoC容器中,使用singleton定义的Bean将只有一个实例prototype:原型模式,每次通过容器
Stella981 Stella981
4年前
Spring Bean创建过程
    通过前面几篇文章的分析,我们对Spring框架,Bean,Context和Core都有了一定了解,结合之前的基础,我们研究下ApplicationContext创建Bean的的过程。  Bean的创建过程可以分为两类:第一类是容器创建时就创建,这类Bean必须是Singleton的,并且lazyinit为false,这也是Bean的默认配
Easter79 Easter79
4年前
Spring高级应用之注入嵌套Bean
在Spring中,如果某个Bean所依赖的Bean不想被Spring容器直接访问,可以使用嵌套Bean。和普通的Bean一样,使用<bean元素来定义嵌套的Bean,嵌套Bean只对它的外部的Bean有效,Spring容器无法直接访问嵌套的Bean,因此定义嵌套Bean也无需指定id属性。如下配置片段是一个嵌套Bean的示例:<bean id
Easter79 Easter79
4年前
Spring对configuration class的加载
前言本文不讲解源码,仅记录加载过程中的一部分。看本文需要先知道spring对BeanDefinition的处理,对bean的实例化。单元测试和配置publicclassConfig{}publicclassContextLoadTest{privateA
带着问题去分析:Spring Bean 生命周期 | 京东物流技术团队
1:Bean在Spring容器中是如何存储和定义的Bean在Spring中的定义是org.springframework.beans.factory.config.BeanDefinition接口,BeanDefinition里面存储的就是我们编写的Jav