Springboot 源码分析 —— bean 初始化流程、beanPostProcessor 用法、循环依赖



1 问题来源

  • springbean 的初始化和各个 bean 之间的关系交给了框架来处理,大大了简化了项目搭建的流程
  • 但是在简化的同时也隐藏了 bean 之间初始化关系的流程
  • 熟悉 bean 初始化的流程可以更好的把握项目运行的顺序,也能够更好的把握 spring 中的一些扩展点


2 bean 初始化流程

  • spring 启动的整个过程可以最简化为 两个步骤
    1)获取所有的 beanDefinition
    2)遍历所有的 beanDefinition,实例化相应的 bean (非懒加载的 bean)
//AbstractApplicationContext类中的方法
public void refresh() {
   
	//这一步是:获取注册所有的 beanDefinition 
	this.invokeBeanFactoryPostProcessors(beanFactory);
	//这一步是:遍历所有的 beanDefinition,实例化相应的bean(非懒加载的bean)
	this.finishBeanFactoryInitialization(beanFactory);
}

2.1 getBean->doGetBean->createBean

  • 通过别名获取 beanName
  • 判断缓存中是否已经存在此实例,如果有,打出相应日志
  • 如果没有:按照 bean 的类型,分情况处理
  • 将父类属性合并到此类中
  • 递归初始化依赖类(这里是 xml 中定义的 depends-on 属性)
  • 初始化该类
//finishBeanFactoryInitialization最终会遍历beanDefinition,调用getBean方法初始化bean
public Object getBean(String name, Object... args) throws BeansException {
   
    return this.doGetBean(name, (Class)null, args, false);
}
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
   
	//这里是通过别名获取beanName(这样就可以注册别名了)
    String beanName = this.transformedBeanName(name);
    //检查缓存中是否已经存在了bean实例
    //在按beanDefinitions顺序实例化时,如果beanA内依赖了beanB,那么将会先去初始化beanB
    //当初始化beanA后,在往下初始化可能会又遍历到beanB,这时beanB就已经存在实例了
    Object sharedInstance = this.getSingleton(beanName);
    Object bean;
    //如果有,判断bean是否正在创建,打相应的日志
    if (sharedInstance != null && args == null) {
   
        if (this.logger.isTraceEnabled()) {
   
            if (this.isSingletonCurrentlyInCreation(beanName)) {
   
                this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
            } else {
   
                this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
    } else {
   
        //如果是多例模式,正在创建,那肯定有问题,因为多例是互不相关的,直接报错
        if (this.isPrototypeCurrentlyInCreation(beanName)) {
   
            throw new BeanCurrentlyInCreationException(beanName);
        }
        //在父类上下文中找该bean,找到了就返回(代码略)
        //获取缓存的BeanDefinition对象并合并其父类和本身的属性
        final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        
		String[] dependsOn = mbd.getDependsOn();//获取依赖类,这个属性是在xml中定义的,获取如上
		//递归初始化依赖类,注意这里的依赖类,只是说明在实例化本类之前,需要先实例化依赖类
		//xml中的 depends-on属性 主要是用来 指定 各个bean之间的初始化顺序
		//当然这里也会出现循环 dependsOn 的情况,如果出现,会有以下代码检测到,直接报错,不然不就死循环了嘛
		//if (this.isDependent(beanName, dep)) {
   
		// throw new BeanCreationException(...)
		//}
		  
        if (mbd.isSingleton()) {
   
            //单例初始化
            sharedInstance = createBean();
            bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        } else if (mbd.isPrototype()) {
   
            //多例初始化,差不多
        } else {
   
            //其它类型(如Session等)
            String scopeName = mbd.getScope();
            Scope scope = (Scope)this.scopes.get(scopeName);
            //初始化
        }
    }
    if (requiredType != null && !requiredType.isInstance(bean)) {
   
        //如果!requiredType.isInstance(bean),要做什么转换吧
        T convertedBean = this.getTypeConverter().convertIfNecessary(bean, requiredType);
        return convertedBean;
    } else {
   
        return bean;
    }
}

2.2 createBean->doCreateBean

  • 设置 override 属性
  • 调用所有 InstantiationAwareBeanPostProcessor,做一些扩展
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
   
    RootBeanDefinition mbdToUse = mbd;
	//设置一些mbdToUse属性(代码略)
    //如果有子父类有相同的方法,设置override属性
    mbdToUse.prepareMethodOverrides();
    Object beanInstance;
    //if (targetType != null) {
   
    //    bean = this.applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
    //    if (bean != null) {
   
    //        bean = this.applyBeanPostProcessorsAfterInitialization(bean, beanName);
    //    }
    // }
    //给beanPostProcessor一个返回代理而不是目标bean实例的机会,这里就是一个扩展点
    beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);
    //如果这边就已经可以初始化了,那就直接返回了,不会有依赖处理不来的问题(因为之前已经处理依赖了)
    if (beanInstance != null) {
   
        return beanInstance;
    }
	//4
    beanInstance = this.doCreateBean(beanName, mbdToUse, args);
    return beanInstance;
}

2.3 doCreateBean->(createBeanInstance,populateBean,initializeBean,registerDisposableBeanIfNecessary)

  • createBeanInstance:通过策略创建bean包装实例——这里可能回去递归初始化构造器中参数的类
  • 调用所有的 MergedBeanDefinitionPostProcessors,一个扩展点
  • 提前暴露引用,允许循环引用,一般为 true
  • populateBean:注入依赖类和相关属性——这里递归初始化注解的依赖类
  • initializeBean:调用初始化方法
  • registerDisposableBeanIfNecessary:搬到 bean 销毁的方法
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
   
    BeanWrapper instanceWrapper <
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值