Spring源码中getBean实例的详细流程

本文主要研究getBean的流程。

1.首先尝试框架会从容器的缓存里获取单例Bean实例,这个单例Bean有可能是一个普通Bean,也有可能是一个FactoryBean,然后调用他的getObject方法返回。
2.如果这里1获取不到,不管是单例还是原型模式,都要框架另外创建实例了。然后进行循环依赖的判断逻辑,正是因为循环依赖,才会用到三级缓存,
3.如果该容器中没有该Bean的BeanDefiniton实例,则递归去父容器去查找。
4.如果该容器中有该Bean的BeanDefiniton实例,则获取Bean实例。
5.递归实例化显式依赖的Bean。显式依赖在其BeanDefiniton设置了Depends-On属性。假设A Depends - On B,那么B 就会先于A实例化。
6.根据不同的Scope选择不同的策略创建Bean实例。
7.对Bean经行类型检查。

下面直接看看代码吧
在这里插入图片描述
这行代码直接返回Bean的名字,这里支持别名获取,和加了&前缀获取生产的Bean的工厂类本身。
然后尝试从缓存中获取Bean实例。

	// Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);
	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	//尝试从一级缓存获取Bean实例,singletonObjects就是单例Bean的一级缓存
		Object singletonObject = this.singletonObjects.get(beanName);
		//如果完整的Bean实例美与被创建出来再一级缓存,那么就会将其加入到SingletonCurrentlyInCreation中 
		//如果一级缓存没有,且这个Bean正在创建
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		//对一级缓存加锁,防止几个线程对缓存同时 操作,导致数据对不上。
			synchronized (this.singletonObjects) {
			//尝试从二级缓存中获取Bean实例,注意这里的二级和后面的三级缓存不是ConcurrentMap,具体原因自己思考吧
				singletonObject = this.earlySingletonObjects.get(beanName);
				//如果二级缓存也没有,且存在早期引用,说明是循环依赖。
				if (singletonObject == null && allowEarlyReference) {
				//从三级缓存获取创建Bean实例的工厂
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					//如果哦从三级缓存获取到的工厂 不为空,则从工厂里面获取Bean实例
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						//放到二级缓存
						this.earlySingletonObjects.put(beanName, singletonObject);
						//从三级缓存删除,保证缓存的一致性
						//注意:只有一级缓存保存的是完整的Bean.
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

到了这里,逻辑上差不多结束了。然后Spring会根据FactoryBean前缀判断到底需要获取 的是工厂类还是.Bean本身。
在这里插入图片描述
以上逻辑是单例Bean的获取,和从缓存中获取到实例的情况。如果没有呢,那么就会继续就会执行下面的逻辑。

// 可以看到原型模式也有一个注册列表,如果此时还在注册表中,说明是循环依赖,原型模式的循环依赖误无解,直接抛出异常。而这里的注册表是ThreadLocal对象,也就是说在一个线程中出现了循环依赖,无解。
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

如果从当前容器中找不到这个Bean的BeanDefinition,且该容器存在父容器,则递归从父容器寻找。
找到BeanDefiniton,如果BeanDefiniton里面具有显示的循环依赖,抛出异常 。
在这里插入图片描述
然后根据不同的Scope的Bean创建。
创建完成后,在一级缓存中加入Bean实例,并且在二级三级删除。在已注册名单中加入这个Bean.正创建名单中清楚这个Bean

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章