Spring 源码阅读笔记 (七)
您的点赞,是我更新下去的动力。
前篇导航
Spring 源码阅读笔记(一)
Spring 源码阅读笔记(二)
Spring 源码阅读笔记(三)
Spring 源码阅读笔记(四)
Spring 源码阅读笔记(五)
Spring 源码阅读笔记(六) 主线 registerBeanPostProcessors解读
前篇回顾
在上一章节中,阅读了registerBeanPostProcessors方法,因为在其中有遇到GetBean的方法,今天这篇文章中就来讲解一下这个方法,对后续可能会有帮助。
正式开始
GetBean方法位于AbstractBeanFactory的下面。由于我们调用的时候,通常只会传递一个name进入方法,所以很容易可以定位是哪个方法。
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
复制代码
有几个入参,这里需要记录一下。
- name 实际传入的对象名
- requiredType null
- args null
- typeCheckOnly false
后面来看一下代码。
方法的大概
String beanName = transformedBeanName(name);
Object beanInstance;
// Eagerly check singleton cache for manually registered singletons.
// 急切地检查单例缓存以获取手动注册的单例。
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
// ...
}
else {
//....
}
return adaptBeanInstance(name, beanInstance, requiredType);
复制代码
先看一下方法的整体逻辑,他分为两个部分,有一个If区分开来。
在方法的刚开始,尝试从单例缓存中获取我当前的Bean。
这样就分开了两个分支。
- 从缓存中获取到了对象
- 从缓存中没有获取到对象
方法最终返回的,就是一个实体的实例化过的Bean了。
If为True 代码片段
getSingleton方法
我在往下阅读的时候产生了一丝疑惑,我们看下代码。
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
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 + "'");
}
}
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
复制代码
在上方的代码中, 我产生的疑惑是getSingleton(beanName)明明获取到了一个Instance,为什么在下方又获取了一遍Instance赋值给了Bean Instance,而不是直接把刚刚获取到的shareInstance直接给BeanInstance,带着这个问题,我打开了getSingleton方法。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
复制代码
看这个方法,里面这么多if,看起来不用太害怕。这里关注的东西只有一个singletonObjects
/** 单例对象缓存:bean 名称到 bean 实例。 */
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
复制代码
就是从这个地方获取,然后返回回去的,当前Map存在的话,就把实例化的对象返回出去,不存在就返回Null值。
getObjectForBeanInstance方法
还记得我在上一段提的问题吗。
为什么在下方又获取了一遍Instance赋值给了Bean Instance,而不是直接把刚刚获取到的shareInstance直接给BeanInstance
在这个方法中会有揭晓。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
if (BeanFactoryUtils.isFactoryDereference(name)) {
// ... 假设代码块进不来
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean<?> factoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factoryBean, beanName, !synthetic);
}
return object;
}
复制代码
通过上面的代码可以看出来,好像他这里返回的Object,其实就是把穿进来的那个东西原封不动的返回回去了。
因此得知,shareInstance == BeanInstance。
If为False 代码片段
第一段代码
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
// prototypesCurrentlyInCreation 是一个ThreadLocal
Object curVal = this.prototypesCurrentlyInCreation.get();
return (curVal != null &&
(curVal.equals(beanName) || (curVal instanceof Set<?> set && set.contains(beanName))));
}
复制代码
这一段比较简单一点,只是判断一下当前的Bean是否在当前线程中正在创建。是的话抛出异常。
第二段代码
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
// 没有找到 -> 检查父级工厂
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory abf) {
return abf.doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
复制代码
方法刚进入,最外面的If,判断当前的工厂有没有父级工厂,没有的话,这个If就不走了,有的话,进行再次判断,判断当前工厂中的,BeanDefinition中有没有当前要获取的Bean信息,没有的话不进入If,有的话进入If。这里假设条件成立,往下看。
NameToLookup变量,就是把Name转换了一下。这个不用在意,把这个变量看成BeanName就可以了
在内部的第一个判断,判断父级工厂是不是继承自AbstractBeanFactory,如果是的话,调用父级工厂的doGetBean,也就是父级的当前方法。把他当成递归理解应该可以吧。
在内部的第二个、第三个、第四个判断,意思相同,通过不同的选择调用父级工厂不同的getBean方法。
第三段代码
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
protected void markBeanAsCreated(String beanName) {
if (!this.alreadyCreated.contains(beanName)) {
synchronized (this.mergedBeanDefinitions) {
if (!this.alreadyCreated.contains(beanName)) {
// Let the bean definition get re-merged now that we're actually creating
// the bean... just in case some of its metadata changed in the meantime.
clearMergedBeanDefinition(beanName);
this.alreadyCreated.add(beanName);
}
}
}
}
复制代码
这个方法,由于我们在调用doGetBean方法时。传入的typeCheckOnly为False,所以这里一定会进入,这个方法的最终的目的是,向alreadyCreated这个Set中去追加,意思就是设置当前的Bean已经是创建状态。
后面就是Bean创建的部分了。因为在当前的Bean工厂中和父级工厂中都没有找到已经创建好的,所以要去创建Bean
第四段代码
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
复制代码
requiredType在起初方法调用时传入的是Null,所以这个if不会进入。
下面这两行代码,一个看样子是获取BeanDefinition,一个是检查这个BeanDefintion,这里就不抠细节了。
第五段代码
// Guarantee initialization of beans that the current bean depends on.
// 保证当前 bean 所依赖的 bean 的初始化。
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
复制代码
这段代码的意思刚开始看起来比较繁琐,这里需要解释一下Spring的一个功能。在Bean标签上配置一个depends-on,这个就是配置依赖关系。
假设BeanB依赖BeanA那么,BeanA就要比BeanB先创建Bean。
这个方法的目的就是为了保证这样的顺序,可以看到在这个方法的中间,getBean(dep)就是关键。
第六段代码
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
复制代码
下面这一段代码很轻松就可以看出来了,他是根据xml中配置的scope作用域,来判断这么去创建Bean。创建Bean的方法就是createBean方法。
这个createBean涉及的知识点过多,我们这里先跳过,我在后面单开文章讲解。
第七段方法
return adaptBeanInstance(name, beanInstance, requiredType);
<T> T adaptBeanInstance(String name, Object bean, @Nullable Class<?> requiredType) {
// Check if required type matches the type of the actual bean instance.
// 检查所需类型是否与实际 bean 实例的类型匹配。
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
Object convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return (T) convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
复制代码
这里有一个if,但是很明显,通过我们的这个流程进到这里的,requiredType是Null,所以if不会进入,那么直接返回了Bean。
告一段落
这篇文章到这里就结束了,讲这个方法的目的呢很明显,如果不读的话,不知道getBean到底get的是什么,假设如果不看这个,我看到getBean,下意识就是获取了一个Bean,但是在初期这个Bean还没有实例化的话,下意识的以为这里会get出个null出来,所以这里也就先解析。
在这一篇文章中引出了一个点。getBean是先获取,如果获取不到的话,他回去创建。那么这个创建的流程是什么样的。很多文章都有讲到,Spring是先实例化Bean,在初始化Bean什么的,具体到底是不是这样的。在后面的文章拭目以待。
都看到这了,点个赞再走呗,宝~
结束语
写文章的目的是为了帮助自己巩固知识,写的不好或者错误的地方可以在评论区指出。如果您看了文章觉得对您有所帮助可以点个赞,如果发现有些问题产生了疑惑,或者不明白的可以评论、加我微信,一定知无不言。当然也希望和大家交个朋友,相互学习。