Spring源码解析二十二

上一篇,我们分析了Spring是如果通过多级缓存来解决循环依赖的,其实思路还挺简单的,就是将还未完全创建好的bean先暴露在缓存中,这样的话,当其他的bean实例化需要依赖bean时,可以提前从缓存中获取还未实例化好的bean,从而解决循环依赖的问题。接下来我们继续接着doGetBean方法的主流程分析下后面的逻辑。
在这里插入图片描述
如果一个单例bean实例化好了,或者在实例化过程中提前暴露在对象工厂缓存中了,我们可以通过方法getSingleton,从缓存中获取单例对象。我们假设我们可以从缓存中获取到单例bean,也就是bean已经实例化了,使用sharedInstance不为空,且参数args在doGetBean方法传进来时默认就是为空的,所以接下来就会调用方法getObjectForBeanInstance,进一步处理单例sharedInstance。大家需要注意的是,在方法getObjectForBeanInstance传入的参数中,name是在调用getBean方法时传入的。是最原始的bean名称,而beanName是name转换后的bean名称,并且mbd默认值为null。我们了解这些参数有助于分析下面的逻辑。我们进入到方法getObjectForBeanInstance 中看下:

protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

		// Don't let calling code try to dereference the factory if the bean isn't a factory.
		// 判断参数传入进来的name,是否以&为前缀
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			// 如果name 以 & 为前缀,那必须得要是FactoryBean的实例,否则就抛出异常

			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
			}
			if (mbd != null) {
				// 通过BeanDefinition中的属性isFactoryBean来标记BeanDefinition对应的是FactoryBean类型的Bean
				mbd.isFactoryBean = true;
			}
			// 直接返回FactoryBean的实例
			return beanInstance;
		}

		// Now we have the bean instance, which may be a normal bean or a FactoryBean.
		// If it's a FactoryBean, we use it to create a bean instance, unless the
		// caller actually wants a reference to the factory.
		// 如果单例Bean 的beanInstance的名称name,既不是以&为前缀的并且 beanInstance 也不是FactoryBean的实例,直接返回单例bean
		if (!(beanInstance instanceof FactoryBean)) {
			return beanInstance;
		}

		/**
		 *  下面是对name不是以&为前缀,且beanInstance为FactoryBean的实例的处理情况,
		 *  如果beanInstance 为FactoryBean的实例,会通过FactoryBean来实例化一个bean
		 *
		 */
		Object object = null;
		if (mbd != null) {
			//  通过BeanDefinition中的属性isFactoryBean来标记BeanDefinition对应的是FactoryBean类型的Bean
			mbd.isFactoryBean = true;
		}
		else {
			// 从缓存中,获取FactoryBean实例化好的bean
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			// Return bean instance from factory.
			// 强制转换为FactoryBean
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// Caches object obtained from FactoryBean if it is a singleton.
			if (mbd == null && containsBeanDefinition(beanName)) {
				// 获取BeanDefinition,并封装为RootBeanDefinition
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			// 通过FactoryBean来实例化bean
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

在这里插入图片描述
首先会调用BeanFactoryUtils的方法isFactoryDereference,对bean原始的名称name进行判断,我们进去看下:
在这里插入图片描述
这个里面的逻辑也是判断name是否以符号&为前缀的,要是我们通过调用genBean方法传进来的name,如果是以符号&为前缀会怎么样呢?我们通过这个注解可以知道,getBean方法传入的name如果以符号&为前缀,就是为了获取一个工厂的引用也就是获取一个工厂bean,那什么是工厂bean呢?提到这个工厂bean,我们就要知道Spring中比较重要的一个接口FactoryBean,我们可以通过实现FactoryBean接口中的getObject方法,在getObject方法中定义如何创建一个对象,而实现FactoryBean接口的实现类,就是这里的工厂bean。前面将的bena的后处理器BeanPostProccessor是通过实现BeanPostProcessor接口中的方法,来实现对bean实例化的过程的控制,这个控制只是初步介入了bean的实例化过程,而FactoryBean就是全盘操办bean的实例化。我们先了解下FactoryBean的接口:
在这里插入图片描述
可以看到,FactoryBean接口中的东西并不多,主要提供可几个比较简单的方法,并且FactoryBean是支持泛型的。其中,isSingleton方法是用来判断实例化是否为单例类型,getObjectType用来获取bean的类型,而getObeject方法,就是专门用来定义bean实例化逻辑的,我们到FactoryBean接口中看下:
在这里插入图片描述
可以看到isSingleton的返回值,默认为true,也就是说FactoryBean默认是实例化单例类型的bean。

我们通过案例简单的了解下FactoryBean:
先创建一个User类
在这里插入图片描述
注意,此时我们不用在xml配置User对象,我们通过FactoryBean来实例化对象User。
在这里插入图片描述
可以看到UserFactoryBean实现接口FactoryBean,同时UserFactoryBean实现了getObject方法以及getObjectType方法,其中,getObjectType方法返回的是bean类型也就是User.class,而getObject方法则包含可创建User对象的核心逻辑。在getObject方法中,我直接new 了一个User对象。
我们在xml配置 UserFactoryBean。
在这里插入图片描述
最后,我们测试一下:
我们直接从容器中获取bean即可,我们这里不仅可以通过user来获取bean,同时,我们还手动在名称user前面添加了符号&
在这里插入图片描述
执行结果:
在这里插入图片描述
可以看到通过名称user,Spring内部就会通过UserFactoryBean的getObject方法,为我们创建一个对象,也就是User对象,而这个User对象的创建逻辑,完全是由我们自己自定义的。而在我们的名称user前添加了符号&之后,直接就获取到了创建User对象的工厂bean,也就是UserFactoryBean对象。
了解完FactoryBean以及如果通过FactoryBean实例化bean之后,我们在回到刚才的方法:
在这里插入图片描述
刚才已经看到了,这个逻辑中的判断,其实就是判断name是否以符号&为前缀,首先,我们假设name就是以符号&为前缀的,比如name为&user,根据我们刚才的案例,现在就是要获取创建bean的工厂bean,也就是实现了FactoryBean接口的对象。看下Spring具体是怎么处理的:
在这里插入图片描述
如果获取到的单例beanInstance是nullBean的实例就直接返回,接着会判断,如果beanInstance不是FactoryBean的实现类,此时就会抛出异常。从这里可以看出,如果一个bean的名称以&为前缀,那它必须是FactoryBean接口的实现类。接下来,我们可以看到如果name以&为前缀,且同时是FactoryBean接口实例,此时就会将单例beanInstance返回了,就是直接返回FactoryBean的实现类了。
我们知道我们需要通过FactoryBean来实例化一个bean,就要剔除bean名称name的前缀符号&,同时,如果这个name对应的bean实现了BeanFactory接口,就会通过getObject方法实例化一个bean,我们也来看下spring是如何处理的:
在这里插入图片描述
可以看到,如果bean的名称name不是以&为前缀的,此时就会走到这段代码,这里判断如果beanInstance不是FactoryBean的实例,直接就将beanInstance返回了。也就是说,一个bean的名称既不是以&为前缀,同时也不是接口FactoryBean的实现类,此时Spring就会认为这个bean没有定义相关的FactoryBean来自定义实例化的bean,这个bean就是一个非常普通的bean,就会将bean实例返回了。也就是说,在默认的情况下,我们是不需要根据FactoryBean来实例化bean的,只有当我们需要全权控制bean的实例化时,才需要自定义FactoryBean的实现类,并且在getObject方法中定义好bean的实例化逻辑。
我们案例中的bean已经实现了FactoryBean,我们看下Spring会如何处理:
在这里插入图片描述
接下来就会标记当前mbd的类型,也就是将BeanDefinition的属性isFactoryBean值设置为true,表示当前BeanDefinition为工厂bean了。前面我们看到了参数mbd的值为null,所以mbd.isFactoryBean = true的这行代码,在本次逻辑中是不会只执行的,而是执行方法getCachedObjectForFactoryBean。通过方法名称我们知道,这里应该是尝试先从缓存中获取FactoryBena实例化好的bean实例,我们进去看下:
在这里插入图片描述
这里就是通过beanName缓存FactoryBeanObjectCache中获取单例,第一次获取,缓存中也是没有的,所以返回空。我们继续往下看:
在这里插入图片描述
从缓存获取不到bean时,此时object为空,就会走到上图中的分支。接下来将beanInstance强转为FactoryBean了,刚才我们已经知道参数mbd传进来的时候是空的,而方法containsBeanDefinition则是判断Spring容器中,是否存在beanName对应的BeanDefinition。其实beanName对应BeanDefinition,其实就是FactoryBean实现类对应的BeanDefinition,我们在xml文件中已经配置好了FactoryBean对应的实现类了,所以在Spring容器初始时,就会解析并将FactoryBean对应的BeanDefinition注册到Spring容器中。所以方法containsBeanDefinition的返回结果为true,接着就会调用方法getMergedLocalBeanDefinition获取FactoryBean对应的BeanDefinition,接着会调用方法getObjectFromFactoryBean。为了方便我们分析getObjectFromFactoryBean方法中的逻辑,我们有必要了解这些参数的值,对于boolean类型的synthetic,因为mbd此时不为空,且在RootBeanDefinition中方法synthetic的返回值默认为false,所以传递到方法getObjectFromFactoryBean中的!synthetic值为true。

我们现在已经获取到了FactoryBean的实现类了,我们其实就可以知道getObjectFromFactoryBean方法中,其实就是通过FactoryBean中的getObject方法来实例化bean的。我们到方法getObjectFromFactoryBean中看下:

	protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
		// 如果FactoryBean默认是单例,并且单例缓存中存在beanName对应的单例
		if (factory.isSingleton() && containsSingleton(beanName)) {
			synchronized (getSingletonMutex()) {
				// 第一次来创建时,缓存中肯定找不到
				Object object = this.factoryBeanObjectCache.get(beanName);
				if (object == null) {
					// 通过调用FactoryBean的getObject方法,创建bean实例
					object = doGetObjectFromFactoryBean(factory, beanName);
					// Only post-process and store if not put there already during getObject() call above
					// (e.g. because of circular reference processing triggered by custom getBean calls)
					Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
					if (alreadyThere != null) {
						object = alreadyThere;
					}
					else {
						if (shouldPostProcess) {
							// beanName对应的单例bean,是否正在实例化
							if (isSingletonCurrentlyInCreation(beanName)) {
								// Temporarily return non-post-processed object, not storing it yet..
								// 如果正在实例化的话,直接返回通过FactoryBean.getObject方式得到的bean
								return object;
							}
							// bean开始创建之前
							beforeSingletonCreation(beanName);
							try {
								// 在FactoryBean创建实例bean之后,进行一些后处理操作,默认什么也没有做
								object = postProcessObjectFromFactoryBean(object, beanName);
							}
							catch (Throwable ex) {
								throw new BeanCreationException(beanName,
										"Post-processing of FactoryBean's singleton object failed", ex);
							}
							finally {
								// 移除bean正在创建的标记
								afterSingletonCreation(beanName);
							}
						}
						// 如果beanName对应的单例bean,也就是FactoryBean存在,此时就把FactoryBean创建出来的bean实例添加到缓存中
						if (containsSingleton(beanName)) {
							this.factoryBeanObjectCache.put(beanName, object);
						}
					}
				}
				return object;
			}
		}
		else {
			Object object = doGetObjectFromFactoryBean(factory, beanName);
			if (shouldPostProcess) {
				try {
					object = postProcessObjectFromFactoryBean(object, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
				}
			}
			return object;
		}
	}

在这里插入图片描述
我们知道FactoryBean中的isSingleton方法返回值默认为true,并且在单例缓存中是存在beanName对应的单例bean的,所以会进入到上图这个分支,接着我们到doGetObjectFromFactoryBean方法中看下:
在这里插入图片描述
我们终于看到了我们想要看到的代码,也就是调用FactoryBean的getObject方法实例化bean。
我们回退到上一步看下还有哪些东西:
在这里插入图片描述
我们这个FactoryBean是第一次创建实例,所以FactoryBean的实例缓存中是没有数据的,所以会进入到上图这个分支,我们之前看过了这个shouldPostProcess参数它的值为true,所以会进入到方法isSingletonCurrentlyInCreation 进行判断当前是否有名称beanName的bean正在实例化,现在这里暂时是没有的。
我们继续向下看:
在这里插入图片描述
我们看下beforeSingletonCreation和afterSingletonCreation的逻辑:
在这里插入图片描述
在这里插入图片描述
bean开始实例化时,先将beanName记录到集合inCreationCheckExclusion和集合singletonsCurrentlyInCreation中。其中,一旦bean开始实例化,就会将bean的名称添加到集合inCreationCheckExclusion中,很明显这个集合是用来去重的,避免同一个bean重复被实例化,而集合singletonsCurrentlyInCreation,则是用来存放当前正在创建的bean名称,用来检测bean是否处于正在创建的状态。

在afterSingletonCreation方法中相应的就会将beanName。从集合singletonsCurrentlyInCreation中移除,表示这个bean已经实例化好了。

最后,我们再来看下,这个postProcessObjectFromFactoryBean方法:
在这里插入图片描述
可以看到,方法postProcessObjectFromFactoryBean默认就将对象object返回了。
我们在来看最后的一些逻辑:
在这里插入图片描述
可以看到,最后会把FactoryBean创建好的实例bean,存放在FactoryBean的实例缓存factoryBeanObjectCache中,然后直接就返回了。

最后,我们梳理一下流程图:
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring源码解析是指对Spring框架的源代码进行深入分析和解读的过程。Spring框架是一个开源的Java企业级应用程序框架,提供了高度灵活和可扩展的开发环境。 Spring框架的源代码解析涉及了众多的模块和组件,包括核心容器、AOP(面向切面编程)、数据访问、Web开发等。通过对这些模块和组件的源代码进行解析,我们可以更加深入地了解Spring框架的工作原理和设计思想。 Spring源码解析的好处在于,可以帮助我们更好地理解Spring框架的各种功能和特性,并且能够帮助开发人员更加高效地使用和定制Spring框架,解决实际项目开发中的问题。 在进行Spring源码解析时,我们可以关注一些关键的概念和类,比如BeanFactory、ApplicationContext、BeanPostProcessor、AOP代理等。这些核心类和概念是理解Spring框架工作机制的重要基础。 进行Spring源码解析时,我们可以使用一些常见的工具和方法,比如IDE(集成开发环境)的调试功能、查看和分析源代码的注释和文档、调试和运行项目的示例代码等。 通过Spring源码解析,我们可以学到很多有关软件开发的知识和经验,比如面向对象编程、设计模式、依赖注入、控制反转等。这些知识和经验对于我们提升自己的技术水平和解决实际项目中的问题都有很大的帮助。 总之,Spring源码解析是一项非常有价值的学习和研究工作,可以帮助我们更好地理解和应用Spring框架,提高自己的技术能力和软件开发水平。希望以上的回答能够满足您的需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

youngerone123

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

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

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

打赏作者

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

抵扣说明:

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

余额充值