searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

浅析Spring单例bean的创建过程

2024-06-27 03:35:35
35
0

前置准备

首先,准备一点必要的代码:

  1. 定义ServiceA类:
@Service
public class ServiceA {
}
  1. 定义MyConfig类, 用于Spring能扫描到ServiceA类
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(value = "com.dcj.spring.circulardependency")
public class MyConfig {

}
  1. 定义Test类
public class Mytest {
    public static void main(String[] args) {
        // 通过MyConfig配置类,扫描对应包的类
        AnnotationConfigApplicationContext applicationContext
                = new AnnotationConfigApplicationContext(MyConfig.class);
        ServiceA serviceA = applicationContext.getBean(ServiceA.class);
    }
}

执行流程

  1. new AnnotationConfigApplicationContext(MyConfig.class)开始

说明: refresh()方法其实是父类AbstractApplicationContext.refresh()方法。

  1. 进入AbstractApplicationContext.finishBeanFactoryInitialization()方法,在此方法中,完成单例bean的实例化。

  1. 进入beanFactory.preInstantiateSingletons()方法,此方法定义为:确定所有非懒加载的单例bean能够被实例化。

备注:preInstantiateSingletons方法是ConfigurableListableBeanFactory接口中定义, 由DefaultListableBeanFactory类实现。

  1. 进入AbstractBeanFactory.getBean(name)方法。

  1. 进入AbstractBeanFactory.doGetBean(...)方法,此方法逻辑很关键。也是代码重点解读的部分。

doGetBean核心逻辑:

  1. Object sharedInstance = getSingleton(beanName)先依次尝试从一级缓存、二级缓存、三级缓存中拿bean实例。特别说明的是:如果一级缓存、二级缓存不存在,但是三级缓存存在的话,则从三级缓存中拿bean, 此时本质执行的是getEarlyReference方法,拿到后,将三级缓存中拿到的bean上移到二级缓存。
  2. 如果步骤1没返回,就执行getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法。此方法大致分为如下几步:
  • 2.1: 标记当前bean正在创建中,其实就是往singletonsCurrentlyInCreation集合中设置当前beanName
  • 2.2: 执行singletonObject = singletonFactory.getObject();方法,其实等价于执行createBean(beanName, mbd, args)方法
    • 2.2.1 创建出原始bean, 也就是instanceWrapper
    • 2.2.2 将当前bean的ObjectFactory实例,添加到三级缓存,仅仅是添加进去,三级缓存的方法并未执行
    • 2.2.3 填充原始bean的属性
    • 2.2.4 初始化原始bean
      • 2.2.4.1 执行aware方法
      • 执行bean的后置处理器逻辑
      • 执行初始化方法
      • 执行bean的后置处理器逻辑
      • 2.2.5 返回真正可以使用的bean
  • 2.3:清除singletonsCurrentlyInCreation标记,表示当前bean已创建完成
  • 2.4:清空对应bean的三级缓存,清空对应bean的二级缓存,并将其放入一级缓存

也就是说:DefaultSingletonBeanRegistry.getSingleton(beanName, singletonFactory)这个方法返回的,是已经可以直接拿来用的bean。

此时上面的步骤2.2再细分,createBean(beanName, mbd, args)做了如下几件事:

一些结论

  1. 任何一个单例bean, 首先对应的ObjectFactory实例, 一定会被加入到三级缓存。
  2. 该bean只有被循环依赖时,三级缓存的getEarlyBeanReference方法才会被执行,它返回真实bean或者对应代理bean(有AOP时);
  3. 只有被循环依赖时,bean才会进入二级缓存,否则没机会进二级缓存
  4. 如果bean没有被循环依赖, 但是有AOP代理, 代理bean是通过后置处理器的逻辑产生的。

 

0条评论
0 / 1000
dchangjian
2文章数
0粉丝数
dchangjian
2 文章 | 0 粉丝