Spring之Bean创建流程

1 Bean创建的入口

  • 在AbstractApplicationContext的refresh()方法中有this.finishBeanFactoryInitialization(beanFactory)方法

  • 该方法中调用了DefaultListableBeanFactory的preInstantiateSingletons()方法,该方法会初始化所有非延时加载的Bean实例

  • preInstantiateSingletons()方法会调用getBean()方法创建出示例

    if (isEagerInit) {
        this.getBean(beanName);
    }
    
  • getBean()方法中调用 AbstractBeanFactory的doGetBean() 方法进行Bean的创建

    public Object getBean(String name) throws BeansException {
        return this.doGetBean(name, (Class)null, (Object[])null, false);
    }
    
  • 在doGetBean()方法中使用了一个匿名内部类来创建Bean

    // 这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
    sharedInstance = getSingleton(beanName, () -> {
    	try {
    		return createBean(beanName, mbd, args);
    	}
    	catch (BeansException ex) {
    		// Explicitly remove instance from singleton cache: It might have been put there
    		// eagerly by the creation process, to allow for circular reference resolution.
    		// Also remove any beans that received a temporary reference to the bean.
    		// 显式从单例缓存中删除 bean 实例
    		// 因为单例模式下为了解决循环依赖,可能它已经存在了,所以将其销毁
    		destroySingleton(beanName);
    		throw ex;
    	}
    });
    
  • AbstractAutowireCapableBeanFactory实现了createBean()方法,该类提供自动装配的服务

  • 在createBean()方法中找到了doCreateBean(),这就是创建Bean的入口

    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    

2 学习路线

在这里插入图片描述

3 doGetBean()

在这里插入图片描述

  • AbstractBeanFactory提供了doGetBean()方法,能够根据Scope去进行不同的处理,这里主要研究Singleton
  • 针对prototype的循环依赖,spring无解,直接抛出异常

3.1 尝试从缓存中获取Bean

3.1.1 获取BeanName - transformedBeanName(name)
3.1.2 尝试获取Bean实例 - getSingleton()
  • doGetBean()调用DefaultSingletonBeanRegistry类的getSingleton()方法尝试从缓存中获取单例实例
  • 该方法在DefaultSingletonBeanRegistry中,这里涉及到了 三级缓存
    • 注入属性的Bean存放在singletonObjects
    • 不完备的Bean存放在earlySingletonObjects 或者 singletonFactories
    /** Cache of singleton objects: bean name to bean instance. */
    //一级缓存:单例对象缓存池,beanName->Bean,其中存储的就是实例化,属性赋值成功之后的单例对象
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    
    /** Cache of singleton factories: bean name to ObjectFactory. */
    //三级缓存:单例工厂的缓存,beanName->ObjectFactory,添加进去的时候实例还未具备属性
    // 用于保存beanName和创建bean的工厂之间的关系map,单例Bean在创建之初过早的暴露出去的Factory,
    // 为什么采用工厂方式,是因为有些Bean是需要被代理的,总不能把代理前的暴露出去那就毫无意义了
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    
    /** Cache of early singleton objects: bean name to bean instance. */
    //二级缓存:早期的单例对象,beanName->Bean,其中存储的是实例化之后,属性未赋值的单例对象
    // 执行了工厂方法生产出来的Bean,bean被放进去之后,
    // 那么当bean在创建过程中,就可以通过getBean方法获取到
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
    

流程分析

  • 首先从以及缓存 singletonObjects 尝试获取Bean实例,那肯定是找不到
    • 该ConcurrentHashMap存储的是最终形态的Bean(填充了属性)
    //尝试从一级缓存里面获取完备的Bean,已经注入了属性
    Object singletonObject = this.singletonObjects.get(beanName);
    
  • 此时 singletonObject == null,再判断 isSingletonCurrentlyInCreation(beanName) ,即是否是正在创建的单例Bean实例,因为该方法执行是还未判断Bean的Scope属性所以这里未false,也就跳过了 if
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {}
    
  • 最终返回 null
3.1.2.2 三级缓存

if 流程分析

  • 如果Bean是单例的并且是正在创建的,对singleObjects上同步锁

    • 上锁之后操作二级缓存和三级缓存是安全的,因此二级缓存和三级缓存都是用的是HashMap
    synchronized (this.singletonObjects)
    
  • 尝试从二级缓存earlySingletonObjects获取Bean实例,它存储的是还没进行属性添加操作的Bean实例

    singletonObject = this.earlySingletonObjects.get(beanName);
    
  • 如果获取到了就不进入if 直接返回了

    if (singletonObject == null && allowEarlyReference)
    
  • 如果没获取到并且 allowEarlyReference = true ,就进入if,根据beanName尝试从三级缓存 singletonFactories 中获取创建此Bean的单例工厂实例

    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
    
    • ObjectFactory是一个函数实接口,里面只有一个getObject()方法,后序能调用getObject()来创建Bean实例
    • 不使用FactoryBean是为了区分用户使用的和框架使用的,FactoryBean有它单独的处理逻辑
  • 如果没获取到该单例对应的对象工厂实例就返回null

  • 获取到了就会调用获取到的对象工厂实例的getObject()方法来创建Bean实例,由于这时Bean的属性可能还未注入,会将它先放入二级缓存earlySingletonObjects中。为了保证三级缓存中只有一级是有Bean实例的,所以创建完Bean实例后会将三级缓存中的对象工厂实例移除

    if (singletonFactory != null) {
    	//调用单例工厂的getObject方法返回对象实例
    	singletonObject = singletonFactory.getObject();
    	//将实例放入二级缓存里
    	this.earlySingletonObjects.put(beanName, singletonObject);
    	//从三级缓存里移除
    	// 保证三层缓存只有一层由Bean,也就是单例的
    	this.singletonFactories.remove(beanName);
    }
    
3.1.3 getObjectForBeanInstance() - TODO
  • 再听一遍 8 - 2
  • 此方法的作用时判断是否是如果是FactoryBean
    • 如果是普通bean,直接返回,如果是FactoryBean,则返回他的getObject生成的Bean实例
    // 如果先前已经创建过单例Bean的实例,并且调用的getBean方法传入的参数为空
    // 则执行if里面的逻辑
    // args之所以要求为空是因为如果有args,则需要做进一步赋值,因此无法直接返回
    if (sharedInstance != null && args == null) {
    	if (logger.isTraceEnabled()) {
    		//如果Bean还在创建中,则说明是循环引用
    		if (isSingletonCurrentlyInCreation(beanName)) {
    			logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
    					"' that is not fully initialized yet - a consequence of a circular reference");
    		}
    		else {
    			logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
    		}
    	}
    	// 此方法的作用时判断是否是如果是FactoryBean
    	// 如果是普通bean,直接返回,如果是FactoryBean,则返回他的getObject生成的Bean实例
    	bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    

3.2 Prototype循环依赖的判断

  • 3.1中讲的是能从缓存获取到Bean的逻辑,本节讲解的是scope不为singleton(是prototype)或者scope为sigleton但是Bean没有被创建(从缓存中获取不到值)
3.2.1 isPrototypeCurrentlyInCreation()
  • 如果scope为prototype并且显示还在创建中,则基本是循环依赖的情况

    • 针对prototype的循环依赖,spring无解,直接抛出 BeanCurrentlyInCreationException 异常,prototype 的循环依赖Spring是不支持的
    if (isPrototypeCurrentlyInCreation(beanName)) {
    	throw new BeanCurrentlyInCreationException(beanName);
    }
    
  • 该方法尝试从prototypesCurrentlyInCreation中获取

    Object curVal = this.prototypesCurrentlyInCreation.get();
    
    • prototypesCurrentlyInCreation是ThreadLocal类型的,也就是说仅仅是本次线程创建的Scope为prototype的Bean实例会放到这张存储正在创建的Bean的名字列表里
      /** Names of beans that are currently in creation. */
      private final ThreadLocal<Object> prototypesCurrentlyInCreation =
      		new NamedThreadLocal<>("Prototype beans currently in creation");
      

3.3 递归去父容器获取Bean实例 - TODO

  • 如果不是循环以来的情况,则递归去父容器中尝试获取Bean

  • 获取父容器

    BeanFactory parentBeanFactory = getParentBeanFactory();
    
  • 递归去父容器中尝试获取Bean

    //如果parent容器依旧是AbstractBeanFactory的实例
    //instanceof通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例
    if (parentBeanFactory instanceof AbstractBeanFactory) {
    	//直接递归调用方法来查找
    	return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
    			nameToLookup, requiredType, args, typeCheckOnly);
    }
    

3.4 合并子类和父类的BeanDefination

  • 将父类的BeanDefinition与子类的BeanDefinition进行合并覆盖

    //将父类的BeanDefinition与子类的BeanDefinition进行合并覆盖
    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    
    • 尝试从 mergedBeanDefinitions 获取合并好的BeanDefination
      • 获取到直接返回
      • 获取不到从新合并一遍
    protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
    	// Quick check on the concurrent map first, with minimal locking.
    	RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
    	if (mbd != null && !mbd.stale) {
    		return mbd;
    	}
    	return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
    }
    
  • 对合并的BeanDefinition做验证,主要看属性是否为abstract的

    checkMergedBeanDefinition(mbd, beanName, args);
    

3.5 递归实例化显示依赖的Bean - depends-on

depends-on用来指定Bean初始化及销毁时的顺序

<bean id=a Class="com.njupt.A" depends-on="b" />
<bean id=b Class="com.njupt.B" />
  • 注意:Spring不支持定义显示的循环依赖
    <bean id="beanA" class="BeanA" depends-on="beanB">
    <bean id="beanB" class="BeanB" depends-on="beanA">
    
    • 如果有会直接抛出异常
    if (isDependent(beanName, dep)) {
    	throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    			"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
    }
    

执行流程

  • 从获取到的BeanDefination中查找有没有depend-on

    String[] dependsOn = mbd.getDependsOn();
    
  • 如果有显示的循环依赖则抛出异常

    if (isDependent(beanName, dep)) {
    	throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    			"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
    }
    
  • 如果有depends-on,并且不是循环依赖,则会先将依赖的Bean进行注册

    registerDependentBean(dep, beanName);
    
    public void registerDependentBean(String beanName, String dependentBeanName) {
    	// 获取到Bean的真实的名字
    	String canonicalName = canonicalName(beanName);
    	// 双重注册
    	synchronized (this.dependentBeanMap) {
    		/*
    		1.Map<String, Set<String>> dependentBeanMap: 存放着当前Bean被引用的Bean的集合
    			String: 被依赖的Bean的名字
    			Set<String>: value则是依赖于该bean的所有bean
    			  比如当前需要实例化的是Bean的名字是userInfo,userInfo中有个Human类型的属性human,
    		      那么就有human被userInfo引用的关系 human=[userInfo]
    	    2.computeIfAbsent:若key对应的value为空,会将第二个参数的返回值存入并返回
    		 */
    		Set<String> dependentBeans =
    				this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
    		if (!dependentBeans.add(dependentBeanName)) {
    			return;
    		}
    	}
    
    	synchronized (this.dependenciesForBeanMap) {
    		// dependenciesForBeanMap中存放的是当前Bean所依赖的Bean的集合
    		Set<String> dependenciesForBean =
    				this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
    		dependenciesForBean.add(canonicalName);
    	}
    }
    
  • 递归调用getBean方法,注册Bean之间的依赖

    // 递归调用getBean方法,注册Bean之间的依赖(如C需要晚于B初始化,而B需要晚于A初始化)
    // 初始化依赖的bean
    getBean(dep);
    

3.6 针对不同Scope进行Bean实例的创建

3.6.1 singleton
3.6.1.1 总体流程分析
  • 这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
    if (mbd.isSingleton()) {
    	// 这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
    	sharedInstance = getSingleton(beanName, () -> {
    		try {
    			return createBean(beanName, mbd, args);
    		}
    		catch (BeansException ex) {
    			// Explicitly remove instance from singleton cache: It might have been put there
    			// eagerly by the creation process, to allow for circular reference resolution.
    			// Also remove any beans that received a temporary reference to the bean.
    			// 显式从单例缓存中删除 bean 实例
    			// 因为单例模式下为了解决循环依赖,可能它已经存在了,所以将其销毁
    			destroySingleton(beanName);
    			throw ex;
    		}
    	});
    	// 如果是普通bean,直接返回,是FactoryBean,返回他的getObject
    	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }
    

getSingleton()方法流程

  • getSingleton()由DefaultSingletonBeanRegistry类实现,发现匿名内部类也是ObjectFactory

    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {}
    
    • 首先尝试从一级缓存中获取Bean

      Object singletonObject = this.singletonObjects.get(beanName);
      
  • 获取不到,判断容器是否正在销毁单例,如果不是,就开始真正的创建

  • 调用beforeSingletonCreation(beanName)将当前beanName加入正在创建的Bean列表中

    this.singletonsCurrentlyInCreation.add(beanName)
    
  • 调用ObjectFactory的getObject来进行Bean的创建,也就是最开始的那个匿名内部类,创建完成后将newSingleton 设为 true

    singletonObject = singletonFactory.getObject();
    newSingleton = true;
    
    sharedInstance = getSingleton(beanName, () -> {
    	try {
    		return createBean(beanName, mbd, args);
    	}
    	catch (BeansException ex) {
    		// Explicitly remove instance from singleton cache: It might have been put there
    		// eagerly by the creation process, to allow for circular reference resolution.
    		// Also remove any beans that received a temporary reference to the bean.
    		// 显式从单例缓存中删除 bean 实例
    		// 因为单例模式下为了解决循环依赖,可能它已经存在了,所以将其销毁
    		destroySingleton(beanName);
    		throw ex;
    	}
    });
    
  • 调用afterSingletonCreation(beanName);将beanName从正在创建的名字列表中移除

    this.singletonsCurrentlyInCreation.remove(beanName)
    
  • 调用 addSingleton(beanName, singletonObject) 方法

    • 将新创建的Bean加入一级缓存,移除二三级缓存的Bean
    • 将beanName添加到单例Bean的名单列表
    protected void addSingleton(String beanName, Object singletonObject) {
    	synchronized (this.singletonObjects) {
    		//Bean实例完成创建之后,只保留一级缓存以及注册beanName的顺序,其余的清除
    		this.singletonObjects.put(beanName, singletonObject);
    		this.singletonFactories.remove(beanName);
    		this.earlySingletonObjects.remove(beanName);
    		this.registeredSingletons.add(beanName);
    	}
    }
    
  • 最终返回Bean实例

getObjectForBeanInstance()

  • 调用该方法返回Bean实例本身。如果是普通bean,直接返回,是FactoryBean,返回他的getObject
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    
3.6.2 prototype
  • 首先将当前Bean的beanName注册进类型为ThreadLoacl表示当前线程正在创建的prototype的Bean的名字列表,防止循环依赖

    beforePrototypeCreation(beanName);
    
    • 这也就解释了为什么一开始会判断Bean是否在创建中
    if (isPrototypeCurrentlyInCreation(beanName)) {
    	throw new BeanCurrentlyInCreationException(beanName);
    }
    
  • 调用createBean()方法创建对象

    prototypeInstance = createBean(beanName, mbd, args);
    
  • 清楚保存beanName的缓存

    // 默认的功能是将先前注册的正在创建中的Bean信息给抹除掉
    afterPrototypeCreation(beanName);
    
  • 获取到创建的Bean实例或者BeanFactory创建的Bean实例

    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
    
3.6.3 !singleton && !prototype
  • 要创建的Bean既不是单例模式,也不是原型模式,则根据Bean定义资源中配置的生命周期范围,选择实例化Bean的合适方法,这种在Web应用程序中 比较常用,如:request、session、application等生命周期
    • request:每次请求都创建一个新的实例
    • session:在session的有效期内使用的是同一个Bean实例
  • 在匿名参数中调用createBean()方法
    Object scopedInstance = scope.get(beanName, () -> {
    	beforePrototypeCreation(beanName);
    	try {
    		return createBean(beanName, mbd, args);
    	}
    	finally {
    		afterPrototypeCreation(beanName);
    	}
    });
    
  • 匿名参数实现的是ObjectFactory接口的getObject()逻辑
    Object get(String name, ObjectFactory<?> objectFactory);
    

3.7 对创建的Bean进行类型检查

补充

为什么要去考虑Bean有可能已经被创建

  • 因为容器均是通过getBean方法从容器获取bean实例的,而有的bean在容器初始化的时候就会被创建,有的是延迟加载的。
  • 比如说,我们某个Service类在容器初始化的时候就已经被容器通过getBean方法提前创建出来了。而在我们的某个Controller类下面如果拥有该Service类作为成员变量,并标记上@Autowired标签,并且该controller类咱们将其设置成延迟加载的。此时该Controller类只有在首次被调用的时候才会创建出对应的Bean实例来,而创建的过程中,就会调用getBean去获取这个Service的Bean,此时Service的Bean由于已经创建好,就可以直接从容器的缓存里返回
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熠熠98

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值