getBean()的执行逻辑

在getBean中调用doGetBean(),在doGetBean中首先通过name获取beanName,因为name 可能会以 & 字符开头,表明调用者想获取 FactoryBean 本身在 BeanFactory 中,FactoryBean 的实现类和其他的 bean 存储方式是一致的,即 beanName 中是没有 & 这个字符的。所以我们需要将 name 的首字符 & 移除,这样才能从缓存里取到 FactoryBean 实例,
然后调用**getSingleton(beanName)**尝试从单例池中获取bean,在正常情况下,该代码很普通,只是正常的检查下我们要拿的 bean 实例是否存在于缓存中,如果有就返回缓存中的 bean 实例,否则就返回 null。但这段代码是spring解决循环依赖的核心代码。
④getSingleton(String beanName, boolean allowEarlyReference)

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		//从map中获取bean如果不为空直接返回,不再进行初始化工作
		//讲道理一个程序员提供的对象这里一般都是为空的
		//检测缓存中是否存在该实例
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			//如果为空,则锁定全局变量并进程处理
			synchronized (this.singletonObjects) {
				//如果此bean正在加载则不处理
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					//当有些方法需要提前初始化的时候则会调用addSingletonFactory方法将对应的ObjectFactory初始化存储在singletonFactores
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						//调用预先设定的getObject方法
						singletonObject = singletonFactory.getObject();
						//记录在缓存中,earlySingletonobjects和singletonFactories互斥。
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

逻辑:他先尝试从单例池singletonObjects中获取,如果获取不到并且isSingletonCurrentlyInCreation()判断当前bean是不是正在创建,返回的是flase。
解决循环引用逻辑:使用构造函数创建一个 “不完整” 的 bean 实例(之所以说不完整,是因为此时该 bean 实例还未初始化),并且提前曝光该 bean 实例的 ObjectFactory(提前曝光就是将 ObjectFactory 放到 singletonFactories 缓存),通过 ObjectFactory 我们可以拿到该 bean 实例的引用,如果出现循环引用,我们可以通过缓存中的 ObjectFactory 来拿到 bean 实例,从而避免出现循环引用导致的死循环。这边通过缓存中的 ObjectFactory 拿到的 bean 实例虽然拿到的是 “不完整” 的 bean 实例,但是由于是单例,所以后续初始化完成后,该 bean 实例的引用地址并不会变,所以最终我们看到的还是完整 bean 实例。
如果调用getSingleton返回时null,说明在单例池中没有,在容器初始化的时候返回的一定是null,然后判断有没有父容器,父容器中有没有,如果没有,然后继续判断是不是原型模式的bean,如果是原型模式的bean,因为原型模式不应该在初始化的时候创建,是原型模式产生循环依赖,直接返回异常。他会在最后调用createBean(beanName, mbd, args);创建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.
				destroySingleton(beanName);
				throw ex;
			}
		});

然后在createBean()中还会调用createBean会调用doCreateBean(),在doCreateBean()中
在调用doCreateBean()创建bean之前他会先调用①resolveBeforeInstantiation()方法来在 bean 初始化前应用后置处理器,如果后置处理返回的 bean 不为空,这个代码现在没办法返回代理对象,因为现在我们的对象还没有实例化,但是他会找出来所有的切面和切点缓存起来
在②然后会调用doCreateBean()创建对象
在doCreateBean()中
①调用createBeanInstance(beanName, mbd, args);创建bean的实例,在createBeanInstance()会第二次执行后置处理器,会执行SmartInstantiationAwareBeanPostProcessor的determineCandidateConstructors(),目的是为了推断出bean应该使用哪一个构造器去实例化对象。
②调用applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);会执行第三次后置处理器,这一步的目的是为了缓存bena的注解元数据信息(用于后面在进行属性填充时使用),这一步会将加了@Autowird,@Resources等注解的属性解析出来,然后缓存这些信息,典型的代表类有CommonAnnotationBeanPostProcessor、AutowiredAnnotationBeanPostProcessor、RequireAnnotationBeanPostProcessor
③判断earlySingletonExposure是否提前曝光,默认为true,会调用addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));将bean提前暴露出去(注意:此时的bean并没有被赋值属性),这样做能解决循环依赖的问题,方法的第二个参数是一个lambda表达式,在表达式的方法体类,会再一次出现执行后置处理器的代码,SmartInstantiationAwareBeanPostProcessor,把这个对象提前暴露。
④调用populateBean()方法进行属性填充,在里面会执行两次后置处理器第一次调用InstantiationAwareBeanProcesssor.postProcessAfterInstantiation,判断bena是否需要填充属性,若返回false表示不需要填充属性,那么poplatebean方法直接结束,第二次调用InstantiationAwareBeanPostProcessor.postProcessPropertyValues()进行属性填充,完成自动装配
在调用完initializeBean()填充好属性,就会执行initializeBean(),在里面会第七次和第八次执行后置处理器。第一次执行了BeanPostProcessor.postProcessBeforeInitialization()方法,然后在依次执行InitializingBean接口的afterPropertiesSet()方法、InitMethod()方法。最后在执行后置处理器的applyBeanPostProcessorsAfterInitialization()方法。
注意:initMethod()放是开发人员的自己在xml文件中配置,或者通过@Bean注解的initMethod属性指定的。
⑤bean的实例化、初始化过程已经完成,创建好的bean会被返回,若是单例bean,会被存放到单例池中,至此结束

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值