Spring IoC源码学习:getBean 详解

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 接着 Spring IoC:finishBeanFactoryInitialization详解,我们正式开始学习获取 bean 实例方法,该方法是 Spring 最核心的方法。

目录

Spring IoC源码学习全系列

前言

正文

getBean

doGetBean

代码块1getObjectForBeanInstance

代码块2getObjectFromFactoryBean

代码3doGetObjectFromFactoryBean

代码块4postProcessObjectFromFactoryBean

代码块5markBeanAsCreated

代码6isDependent

代码块7registerDependentBean

代码块8getSingleton

代码块9beforeSingletonCreationafterSingletonCreation

代码块10addSingleton

代码块11beforePrototypeCreationafterPrototypeCreation

总结

相关文章


Spring IoC源码学习全系列

小白也看得懂的 Spring IoC 核心流程介绍

Spring IoC源码学习:总览

Spring IoC源码学习ApplicationContext刷新前的配置

Spring IoC源码学习obtainFreshBeanFactory详解

Spring IoC源码学习parseDefaultElement详解

Spring IoC源码学习parseCustomElement详解

Spring IoC源码学习:context:component-scan节点详解

Spring IoC源码学习invokeBeanFactoryPostProcessors详解

Spring IoC源码学习registerBeanPostProcessors详解

Spring IoC源码学习finishBeanFactoryInitialization详解

Spring IoC源码学习getBean详解

Spring IoC源码学习createBean详解(上)

Spring IoC源码学习createBean详解(下)

Spring IoC源码学习:@Autowire 详解

Spring IoC源码学习:finishRefresh 详解

 

前言


接着Spring IoCfinishBeanFactoryInitialization详解,我们正式开始学习获取 bean 实例方法,该方法是 Spring 最核心的方法。

 

正文


单击 preInstantiateSingletons 方法里的 getBean(beanName) 代码,进入该方法。

 

getBean


@Override
public Object getBean(String name) throws BeansException {
    // 获取name对应的bean实例,如果不存在,则创建一个
    return doGetBean(name, null, null, false);
}

doGetBean 方法详解。

 

doGetBean

protected <T> T doGetBean(
        final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
        throws BeansException {
    // 1.解析beanName,主要是解析别名、去掉FactoryBean的前缀“&”
    final String beanName = transformedBeanName(name);
    Object bean;
    // Eagerly check singleton cache for manually registered singletons.
    // 2.尝试从缓存中获取beanName对应的实例
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        // 3.如果beanName的实例存在于缓存中
        if (logger.isDebugEnabled()) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                        "' that is not fully initialized yet - a consequence of a circular reference");
            } else {
                logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        // 3.1 返回beanName对应的实例对象(主要用于FactoryBean的特殊处理,普通Bean会直接返回sharedInstance本身)
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    } else {
        // Fail if we're already creating this bean instance:
        // We're assumably within a circular reference.
        // 4.scope为prototype的循环依赖校验:如果beanName已经正在创建Bean实例中,而此时我们又要再一次创建beanName的实例,则代表出现了循环依赖,需要抛出异常。
        // 例子:如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还未创建完的时候因为对于B的创建再次返回创建A,造成循环依赖
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }
        // Check if bean definition exists in this factory.
        // 5.获取parentBeanFactory
        BeanFactory parentBeanFactory = getParentBeanFactory();
        // 5.1 如果parentBeanFactory存在,并且beanName在当前BeanFactory不存在Bean定义,则尝试从parentBeanFactory中获取bean实例
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // Not found -> check parent.
            // 5.2 将别名解析成真正的beanName
            String nameToLookup = originalBeanName(name);
            // 5.3 尝试在parentBeanFactory中获取bean对象实例
            if (args != null) {
                // Delegation to parent with explicit args.
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            } else {
                // No args -> delegate to standard getBean method.
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
        }
        if (!typeCheckOnly) {
            // 6.如果不是仅仅做类型检测,而是创建bean实例,这里要将beanName放到alreadyCreated缓存
            markBeanAsCreated(beanName);
        }
        try {
            // 7.根据beanName重新获取MergedBeanDefinition(步骤6将MergedBeanDefinition删除了,这边获取一个新的)
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            // 7.1 检查MergedBeanDefinition
            checkMergedBeanDefinition(mbd, beanName, args);
            // Guarantee initialization of beans that the current bean depends on.
            // 8.拿到当前bean依赖的bean名称集合,在实例化自己之前,需要先实例化自己依赖的bean
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                // 8.1 遍历当前bean依赖的bean名称集合
                for (String dep : dependsOn) {
                    // 8.2 检查dep是否依赖于beanName,即检查是否存在循环依赖
                    if (isDependent(beanName, dep)) {
                        // 8.3 如果是循环依赖则抛异常
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    // 8.4 将dep和beanName的依赖关系注册到缓存中
                    registerDependentBean(dep, beanName);
                    // 8.5 获取dep对应的bean实例,如果dep还没有创建bean实例,则创建dep的bean实例
                    getBean(dep);
                }
            }
            // Create bean instance.
            // 9.针对不同的scope进行bean的创建
            if (mbd.isSingleton()) {
                // 9.1 scope为singleton的bean创建(新建了一个ObjectFactory,并且重写了getObject方法)
                sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                    @Override
                    public Object getObject() throws BeansException {    //
                        try {
                            // 9.1.1 创建Bean实例
                            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;
                        }
                    }
                });
                // 9.1.2 返回beanName对应的实例对象
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            } else if (mbd.isPrototype()) {
                // 9.2 scope为prototype的bean创建
                // It's a prototype -> create a new instance.
                Object prototypeInstance = null;
                try {
                    // 9.2.1 创建实例前的操作(将beanName保存到prototypesCurrentlyInCreation缓存中)
                    beforePrototypeCreation(beanName);
                    // 9.2.2 创建Bean实例
                    prototypeInstance = createBean(beanName, mbd, args);
                } finally {
                    // 9.2.3 创建实例后的操作(将创建完的beanName从prototypesCurrentlyInCreation缓存中移除)
                    afterPrototypeCreation(beanName);
                }
                // 9.2.4 返回beanName对应的实例对象
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            } else {
                // 9.3 其他scope的bean创建,可能是request之类的
                // 9.3.1 根据scopeName,从缓存拿到scope实例
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
                    // 9.3.2 其他scope的bean创建(新建了一个ObjectFactory,并且重写了getObject方法)
                    Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
                            // 9.3.3 创建实例前的操作(将beanName保存到prototypesCurrentlyInCreation缓存中)
                            beforePrototypeCreation(beanName);
                            try {
                                // 9.3.4 创建bean实例
                                return createBean(beanName, mbd, args);
                            } finally {
                                // 9.3.5 创建实例后的操作(将创建完的beanName从prototypesCurrentlyInCreation缓存中移除)
                                afterPrototypeCreation(beanName);
                            }
                        }
                    });
                    // 9.3.6 返回beanName对应的实例对象
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                } catch (IllegalStateException ex) {
                    throw new BeanCreationException(beanName,
                            "Scope '" + scopeName + "' is not active for the current thread; consider " +
                                    "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                            ex);
                }
            }
        } catch (BeansException ex) {
            // 如果创建bean实例过程中出现异常,则将beanName从alreadyCreated缓存中移除
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }
    // Check if required type matches the type of the actual bean instance.
    // 10.检查所需类型是否与实际的bean对象的类型匹配
    if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
        try {
            // 10.1 类型不对,则尝试转换bean类型
            return getTypeConverter().convertIfNecessary(bean, requiredType);
        } catch (TypeMismatchException ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to convert bean '" + name + "' to required type '" +
                        ClassUtils.getQualifiedName(requiredType) + "'", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    // 11.返回创建出来的bean实例对象
    return (T) bean;
}

1.解析 beanName,主要是解析别名、去掉 FactoryBean 的修饰符 “&”,在Spring IoCfinishBeanFactoryInitialization详解中的代码块4已解析过。


2.尝试从缓存中获取 beanName 对应的实例,在Spring IoCfinishBeanFactoryInitialization详解中的代码块7已解析过。


3.1 返回 beanName 对应的实例对象(主要用于 FactoryBean 的特殊处理,普通 bean 会直接返回 sharedInstance本身),见代码块1详解


6.如果不是仅仅做类型检测,而是创建 bean 实例,这里要将 beanName 放到 alreadyCreated 缓存,见代码块5详解


7.根据 beanName 重新获取MergedBeanDefinition,在Spring IoCfinishBeanFactoryInitialization详解中的代码块2已解析过。


8.2 检查 dep 是否依赖于 beanName,即检查是否存在循环依赖,见代码块6详解


8.4 dep beanName 的依赖关系注册到缓存中,见代码块7详解


9.1 scope singleton bean 创建(新建了一个 ObjectFactory,并且重写了 getObject 方法),见代码块8详解


9.1.19.2.29.3.4 创建 bean 实例,限于篇幅,在下篇文章单独解析。


9.1.29.2.49.3.6 返回 beanName 对应的实例对象,见代码块1详解


9.2.1 scope prototype 时创建实例前的操作、9.2.3 scope prototype 创建实例后的操作,相对应的两个方法,见代码块11详解

 

代码块1getObjectForBeanInstance

protected Object getObjectForBeanInstance(
        Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
    // Don't let calling code try to dereference the factory if the bean isn't a factory.
    // 1.如果name以“&”为前缀,但是beanInstance不是FactoryBean,则抛异常
    if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
        throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
    }
    // 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.
    // 2.1 如果beanInstance不是FactoryBean(也就是普通bean),则直接返回beanInstance
    // 2.2 如果beanInstance是FactoryBean,并且name以“&”为前缀,则直接返回beanInstance(以“&”为前缀代表想获取的是FactoryBean本身)
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }
    // 3.走到这边,代表beanInstance是FactoryBean,但name不带有“&”前缀,表示想要获取的是FactoryBean创建的对象实例
    Object object = null;
    if (mbd == null) {
        // 4.如果mbd为空,则尝试从factoryBeanObjectCache缓存中获取该FactoryBean创建的对象实例
        object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
        // Return bean instance from factory.
        // 5.只有beanInstance是FactoryBean才能走到这边,因此直接强转
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // Caches object obtained from FactoryBean if it is a singleton.
        if (mbd == null && containsBeanDefinition(beanName)) {
            // 6.mbd为空,但是该bean的BeanDefinition在缓存中存在,则获取该bean的MergedBeanDefinition
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        // 7.mbd是否是合成的(这个字段比较复杂,mbd正常情况都不是合成的,也就是false,有兴趣的可以自己查阅资料看看)
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        // 8.从FactoryBean获取对象实例
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    // 9.返回对象实例
    return object;
}

如果对 FactoryBean 不熟悉的,可以回头去看Spring IoCfinishBeanFactoryInitialization详解中对FactoryBean 的简单介绍。

6.mbd 为空,但是该 bean BeanDefinition在缓存中存在,则获取该 bean MergedBeanDefinition,在Spring IoCfinishBeanFactoryInitialization详解中的代码块2已经解析过。

8. FactoryBean 获取对象实例,见代码块2详解

 

代码块2getObjectFromFactoryBean

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    // 1.如果是单例,并且已经存在于单例对象缓存中
    if (factory.isSingleton() && containsSingleton(beanName)) {
        synchronized (getSingletonMutex()) {
            // 2.从FactoryBean创建的单例对象的缓存中获取该bean实例
            Object object = this.factoryBeanObjectCache.get(beanName);
            if (object == null) {
                // 3.调用FactoryBean的getObject方法获取对象实例
                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);
                // 4.如果该beanName已经在缓存中存在,则将object替换成缓存中的
                if (alreadyThere != null) {
                    object = alreadyThere;
                } else {
                    if (object != null && shouldPostProcess) {
                        try {
                            // 5.对bean实例进行后置处理,执行所有已注册的BeanPostProcessor的postProcessAfterInitialization方法
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        } catch (Throwable ex) {
                            throw new BeanCreationException(beanName,
                                    "Post-processing of FactoryBean's singleton object failed", ex);
                        }
                    }
                    // 6.将beanName和object放到factoryBeanObjectCache缓存中
                    this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
                }
            }
            // 7.返回object对象实例
            return (object != NULL_OBJECT ? object : null);
        }
    } else {
        // 8.调用FactoryBean的getObject方法获取对象实例
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        if (object != null && shouldPostProcess) {
            try {
                // 9.对bean实例进行后置处理,执行所有已注册的BeanPostProcessor的postProcessAfterInitialization方法
                object = postProcessObjectFromFactoryBean(object, beanName);
            } catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            }
        }
        // 10.返回object对象实例
        return object;
    }
}

3.调用 FactoryBean getObject 方法获取对象实例,见代码块3详解

5. bean 实例进行后续处理,执行所有已注册的BeanPostProcessor postProcessAfterInitialization 方法,见代码块4详解

 

代码块3doGetObjectFromFactoryBean

private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
        throws BeanCreationException {
    Object object;
    try {
        // 1.调用FactoryBean的getObject方法获取bean对象实例
        if (System.getSecurityManager() != null) {
            AccessControlContext acc = getAccessControlContext();
            try {
                object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                    @Override
                    public Object run() throws Exception {
                        // 1.1 带有权限验证的
                        return factory.getObject();
                    }
                }, acc);
            } catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        } else {
            // 1.2 不带权限
            object = factory.getObject();
        }
    } catch (FactoryBeanNotInitializedException ex) {
        throw new BeanCurrentlyInCreationException(beanName, ex.toString());
    } catch (Throwable ex) {
        throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
    }
    // Do not accept a null value for a FactoryBean that's not fully
    // initialized yet: Many FactoryBeans just return null then.
    // 2.getObject返回的是空值,并且该FactoryBean正在初始化中,则直接抛异常,不接受一个尚未完全初始化的FactoryBean的getObject返回的空值
    if (object == null && isSingletonCurrentlyInCreation(beanName)) {
        throw new BeanCurrentlyInCreationException(
                beanName, "FactoryBean which is currently in creation returned null from getObject");
    }
    // 3.返回创建好的bean对象实例
    return object;
}

很简单的方法,就是直接调用 FactoryBean getObject 方法来获取到对象实例。

细心的同学可以发现,该方法是以 do 开头,看过Spring IoC:源码学习总览的同学知道,我在总览里就特别提到以 do 开头的方法是最终进行实际操作的方法,例如本方法就是 FactoryBean 最终实际进行创建 bean 对象实例的方法。

 

代码块4postProcessObjectFromFactoryBean

@Override
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
    return applyBeanPostProcessorsAfterInitialization(object, beanName);
}
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {
    Object result = existingBean;
    // 1.遍历所有注册的BeanPostProcessor实现类,调用postProcessAfterInitialization方法
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        // 2.在bean初始化后,调用postProcessAfterInitialization方法
        result = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (result == null) {
            // 3.如果返回null,则不会调用后续的BeanPostProcessors
            return result;
        }
    }
    return result;
}

这边走的是 AbstractAutowireCapableBeanFactory 里的方法。通过前面的介绍,我们知道创建的 BeanFactory DefaultListableBeanFactory,而DefaultListableBeanFactory 继承了 AbstractAutowireCapableBeanFactory,因此这边会走 AbstractAutowireCapableBeanFactory 的重写方法。

Spring IoCregisterBeanPostProcessors详解中已经学过 BeanPostProcessor,在创建完 bean 实例后,会执行 BeanPostProcessor postProcessAfterInitialization 方法。

 

代码块5markBeanAsCreated

protected void markBeanAsCreated(String beanName) {
    if (!this.alreadyCreated.contains(beanName)) {
        synchronized (this.mergedBeanDefinitions) {
            // 1.如果alreadyCreated缓存中不包含beanName
            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.
                // 2.将beanName的MergedBeanDefinition从mergedBeanDefinitions缓存中移除,
                // 在之后重新获取MergedBeanDefinition,避免BeanDefinition在创建过程中发生变化
                clearMergedBeanDefinition(beanName);
                // 3.将beanName添加到alreadyCreated缓存中,代表该beanName的bean实例已经创建(或即将创建)
                this.alreadyCreated.add(beanName);
            }
        }
    }
}
protected void clearMergedBeanDefinition(String beanName) {
    this.mergedBeanDefinitions.remove(beanName);
}

2.这边会将 beanName 对应的 MergedBeanDefinition移除,然后在之后的代码重新获取,主要是为了使用最新的MergedBeanDefinition 来进行创建操作。

 

代码块6isDependent

private boolean isDependent(String beanName, String dependentBeanName, Set<String> alreadySeen) {
    // 已经检查过的直接跳过
    if (alreadySeen != null && alreadySeen.contains(beanName)) {
        return false;
    }
    // 1.将别名解析为真正的名称
    String canonicalName = canonicalName(beanName);
    // 2.拿到依赖canonicalName的beanName集合
    Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
    // 3.如果dependentBeans为空,则两者必然还未确定依赖关系,返回false
    if (dependentBeans == null) {
        return false;
    }
    // 4.如果dependentBeans包含dependentBeanName,则表示两者已确定依赖关系,返回true
    if (dependentBeans.contains(dependentBeanName)) {
        return true;
    }
    // 5.循环检查,即检查依赖canonicalName的所有beanName是否存在被dependentBeanName依赖的(即隔层依赖)
    for (String transitiveDependency : dependentBeans) {
        if (alreadySeen == null) {
            alreadySeen = new HashSet<String>();
        }
        // 6.已经检查过的添加到alreadySeen,避免重复检查
        alreadySeen.add(beanName);
        if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
            return true;
        }
    }
    return false;
}

这边引入了一个缓存 dependentBeanMapbeanName -> 所有依赖 beanName 对应的 bean beanName 集合。内容比较简单,就是检查依赖 beanName 的集合中是否包含 dependentBeanName,隔层依赖也算。例如:A 依赖了 BB 依赖了 C,则 A 也算依赖了 C

 

代码块7registerDependentBean

public void registerDependentBean(String beanName, String dependentBeanName) {
    // A quick check for an existing entry upfront, avoiding synchronization...
    // 1.解析别名
    String canonicalName = canonicalName(beanName);
    // 2.拿到依赖canonicalName的beanName集合
    Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
    // 3.如果dependentBeans包含dependentBeanName,则表示依赖关系已经存在,直接返回
    if (dependentBeans != null && dependentBeans.contains(dependentBeanName)) {
        return;
    }
    // No entry yet -> fully synchronized manipulation of the dependentBeans Set
    // 4.如果依赖关系还没有注册,则将两者的关系注册到dependentBeanMap和dependenciesForBeanMap缓存
    synchronized (this.dependentBeanMap) {
        // 4.1 将dependentBeanName添加到依赖canonicalName的beanName集合中
        dependentBeans = this.dependentBeanMap.get(canonicalName);
        if (dependentBeans == null) {
            dependentBeans = new LinkedHashSet<String>(8);
            this.dependentBeanMap.put(canonicalName, dependentBeans);
        }
        dependentBeans.add(dependentBeanName);
    }
    synchronized (this.dependenciesForBeanMap) {
        // 4.2 将canonicalName添加到dependentBeanName依赖的beanName集合中
        Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName);
        if (dependenciesForBean == null) {
            dependenciesForBean = new LinkedHashSet<String>(8);
            this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);
        }
        dependenciesForBean.add(canonicalName);
    }
}

这边又引入了一个跟 dependentBeanMap 类似的缓存,dependenciesForBeanMapbeanName -> beanName 对应的 bean 依赖的所有 bean beanName 集合。

这两个缓存很容易搞混,举个简单例子:例如 B 依赖了 A,则 dependentBeanMap 缓存中应该存放一对映射:其中 key Avalue 为含有 B Set;而 dependenciesForBeanMap 缓存中也应该存放一对映射:其中 key 为:Bvalue 为含有 A Set

 

代码块8getSingleton

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "'beanName' must not be null");
    // 1.加锁,避免重复创建单例对象
    synchronized (this.singletonObjects) {
        // 2.首先检查beanName对应的bean实例是否在缓存中存在,如果已经存在,则直接返回
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            // 3.beanName对应的bean实例不存在于缓存中,则进行Bean的创建
            if (this.singletonsCurrentlyInDestruction) {
                // 4.当bean工厂的单例处于destruction状态时,不允许进行单例bean创建,抛出异常
                throw new BeanCreationNotAllowedException(beanName,
                        "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                                "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
            }
            // 5.创建单例前的操作
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            // suppressedExceptions用于记录异常相关信息
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<Exception>();
            }
            try {
                // 6.执行singletonFactory的getObject方法获取bean实例
                singletonObject = singletonFactory.getObject();
                // 标记为新的单例对象
                newSingleton = true;
            } catch (IllegalStateException ex) {
                // Has the singleton object implicitly appeared in the meantime ->
                // if yes, proceed with it since the exception indicates that state.
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    throw ex;
                }
            } catch (BeanCreationException ex) {
                if (recordSuppressedExceptions) {
                    for (Exception suppressedException : this.suppressedExceptions) {
                        ex.addRelatedCause(suppressedException);
                    }
                }
                throw ex;
            } finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }
                // 7.创建单例后的操作
                afterSingletonCreation(beanName);
            }
            if (newSingleton) {
                // 8.如果是新的单例对象,将beanName和对应的bean实例添加到缓存中(singletonObjects、registeredSingletons)
                addSingleton(beanName, singletonObject);
            }
        }
        // 9.返回创建出来的单例对象
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }
}

5.创建单例前的操作,7.创建单例后的操作,这两个方法是对应的,见代码块9详解

6.执行 singletonFactory getObject 方法获取 bean 实例,该方法会走文章开头doGetBean 方法的注释 9.1.1

8.如果是新的单例对象,将 beanName 和对应的单例对象添加到缓存中,见代码块10详解

 

代码块9beforeSingletonCreationafterSingletonCreation

protected void beforeSingletonCreation(String beanName) {
    // 先校验beanName是否为要在创建检查排除掉的(inCreationCheckExclusions缓存),如果不是,
    // 则将beanName加入到正在创建bean的缓存中(Set),如果beanName已经存在于该缓存,会返回false抛出异常(这种情况出现在构造器的循环依赖)
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
    }
}
protected void afterSingletonCreation(String beanName) {
    // 先校验beanName是否为要在创建检查排除掉的(inCreationCheckExclusions缓存),如果不是,
    // 则将beanName从正在创建bean的缓存中(Set)移除,如果beanName不存在于该缓存,会返回false抛出异常
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
        throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
    }
}

inCreationCheckExclusions 是要在创建检查排除掉的 beanName 集合,正常为空,可以不管。这边主要是引入了 singletonsCurrentlyInCreation 缓存:当前正在创建的 bean beanName 集合。在 beforeSingletonCreation 方法中,通过添加 beanName 到该缓存,可以预防出现构造器循环依赖的情况。


为什么无法解决构造器循环依赖?

我们之前在Spring IoCfinishBeanFactoryInitialization详解中的代码块7提过,getSingleton 方法是解决循环引用的核心代码。解决逻辑的第一句话:我们先用构造函数创建一个不完整 bean 实例,从这句话可以看出,构造器循环依赖是无法解决的,因为当构造器出现循环依赖,我们连不完整 bean 实例都构建不出来。Spring 能解决的循环依赖有:通过 setter 注入的循环依赖、通过属性注入的循环依赖。

 

代码块10addSingleton

protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
        // 1.添加到单例对象缓存
        this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
        // 2.将单例工厂缓存移除(已经不需要)
        this.singletonFactories.remove(beanName);
        // 3.将早期单例对象缓存移除(已经不需要)
        this.earlySingletonObjects.remove(beanName);
        // 4.添加到已经注册的单例对象缓存
        this.registeredSingletons.add(beanName);
    }
}

代码块11beforePrototypeCreationafterPrototypeCreation

protected void beforePrototypeCreation(String beanName) {
    // 1.拿到当前线程中正在创建的prototype的bean的beanName集合
    Object curVal = this.prototypesCurrentlyInCreation.get();
    // 2.如果为空,则将ThreadLocal设置成当前的beanName
    if (curVal == null) {
        this.prototypesCurrentlyInCreation.set(beanName);
    }
    // 3.如果不为空,并且是String类型,则代表目前只有一个beanName,将之前和当前的一起封装成Set<String>,设置到ThreadLocal中
    else if (curVal instanceof String) {
        Set<String> beanNameSet = new HashSet<String>(2);
        beanNameSet.add((String) curVal);
        beanNameSet.add(beanName);
        this.prototypesCurrentlyInCreation.set(beanNameSet);
    }
    // 4.如果不为空,并且不是String,则必然是Set<String>类型,将当前的beanName加到Set中去
    else {
        Set<String> beanNameSet = (Set<String>) curVal;
        beanNameSet.add(beanName);
    }
}
protected void afterPrototypeCreation(String beanName) {
    // 1.拿到当前线程中正在创建的prototype的bean的beanName集合
    Object curVal = this.prototypesCurrentlyInCreation.get();
    // 2.如果是String类型,则代表目前只有一个beanName,则直接移除
    if (curVal instanceof String) {
        this.prototypesCurrentlyInCreation.remove();
    }
    else if (curVal instanceof Set) {
        // 3.如果是Set类型,则从Set从移除beanName
        Set<String> beanNameSet = (Set<String>) curVal;
        beanNameSet.remove(beanName);
        if (beanNameSet.isEmpty()) {
            this.prototypesCurrentlyInCreation.remove();
        }
    }
}

该方法和代码块9的两个方法类似。主要是在进行 bean 实例的创建前,将 beanName 添加到 prototypesCurrentlyInCreation 缓存;bean 实例创建后,将 beanName prototypesCurrentlyInCreation 缓存中移除。这边 prototypesCurrentlyInCreation 存放的类型为 Object,在只有一个 beanName 的时候,直接存该 beanName,也就是 String 类型;当有多个 beanName 时,转成 Set 来存放。

 

总结


本文介绍了获取 bean 实例的大部分内容,包括先从缓存中检查、 FactoryBean bean 创建、实例化自己的依赖(depend-on 属性)、创建 bean 实例的前后一些标记等,在下篇文章中,将解析创建 bean 的内容。

 

相关文章
|
3天前
|
前端开发 Java 数据库
SpringBoot学习
【10月更文挑战第7天】Spring学习
24 9
|
4天前
|
JavaScript Java 关系型数据库
自主版权的Java诊所管理系统源码,采用Vue 2、Spring Boot等技术栈,支持二次开发
这是一个自主版权的Java诊所管理系统源码,支持二次开发。采用Vue 2、Spring Boot等技术栈,涵盖患者管理、医生管理、门诊管理、药店管理、药品管理、收费管理、医保管理、报表统计及病历电子化等功能模块。
|
4天前
|
XML Java 数据格式
Spring学习
【10月更文挑战第6天】Spring学习
14 1
|
9天前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
|
9天前
|
XML Java 数据格式
Spring底层架构源码解析(二)
Spring底层架构源码解析(二)
|
9天前
|
Java 测试技术 开发者
springboot学习四:Spring Boot profile多环境配置、devtools热部署
这篇文章主要介绍了如何在Spring Boot中进行多环境配置以及如何整合DevTools实现热部署,以提高开发效率。
27 2
|
9天前
|
前端开发 Java 程序员
springboot 学习十五:Spring Boot 优雅的集成Swagger2、Knife4j
这篇文章是关于如何在Spring Boot项目中集成Swagger2和Knife4j来生成和美化API接口文档的详细教程。
24 1
|
9天前
|
Java API Spring
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中拦截器的入门教程和实战项目场景实现的详细指南。
13 0
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
|
9天前
|
Java API Spring
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中过滤器的基础知识和实战项目应用的教程。
12 0
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
|
9天前
|
Java 关系型数据库 MySQL
springboot学习五:springboot整合Mybatis 连接 mysql数据库
这篇文章是关于如何使用Spring Boot整合MyBatis来连接MySQL数据库,并进行基本的增删改查操作的教程。
14 0
springboot学习五:springboot整合Mybatis 连接 mysql数据库