深入源码分析SpringIOC(二)

IOC之Bean的初始化(实例化与依赖注入)

文章目录

  • IOC之Bean的初始化(实例化与依赖注入)
    • 前情概要
    • 初始化Bean
    • 解决循环依赖的问题
      • 什么是循环依赖?
      • Spring中如何解决循环依赖
      • 循环依赖总结
    • FactoryBean
      • FactoryBean是什么
      • FactoryBean在IOC容器哪里用到
      • FactoryBean例子
    • 总结

前情概要

回顾之前的内容IOC初始化之准备工作(定位、加载、注册) ,说到在ApplicationContext初始化时,会先去根据资源路径去定位、加载并且注册Bean信息到BeanFactory中,但此过程并未实例化,在结尾也说了,在调用BeanFactorygetBean方法时Bean才会真正实例化。那么在ApplicationContext中是什么时候去初始化Bean的呢?回顾一下refresh方法:

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        
        // Tell the subclass to refresh the internal bean factory.
        //告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从
        //子类的refreshBeanFactory()方法启动
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        
		//略...
        
        // Instantiate all remaining (non-lazy-init) singletons.
        //初始化所有剩余的单例Bean
        finishBeanFactoryInitialization(beanFactory);

        //略...
}

由refresh方法可知,ApplicationContext将在方法接近末尾的时候去初始化Bean,但不是初始化所有Bean,而是作用域为singleton单例的且配置lazy-init=false才会进行初始化Bean的操作。

//对配置了lazy-init属性的Bean进行预实例化处理
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
   
	//略...

    // Instantiate all remaining (non-lazy-init) singletons.
    //对配置了lazy-init属性的单态模式Bean进行预实例化处理
    beanFactory.preInstantiateSingletons();
}

注意这里初始化方法还是委托给了我们上一篇文章说的BeanFactory去做,而不是ApplicationContext,对于很多操作Bean的场景大部分都是由DefaultListableBeanFactory去做。

//对配置lazy-init属性单态Bean的预实例化
@Override
public void preInstantiateSingletons() throws BeansException {

    // Iterate over a copy to allow for init methods which in turn register new bean definitions.
    // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // Trigger initialization of all non-lazy singleton beans...
    //遍历所有的beanNames
    for (String beanName : beanNames) {
        //获取指定名称的Bean定义
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        //Bean不是抽象的,是单态模式的,且lazy-init属性配置为false
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            //如果指定名称的bean是创建容器的Bean
            if (isFactoryBean(beanName)) {
                //FACTORY_BEAN_PREFIX=”&”,当Bean名称前面加”&”符号
                //时,获取的是产生容器对象本身,而不是容器产生的Bean.
                //调用getBean方法,触发容器对Bean实例化和依赖注入过程
                final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
                //标识是否需要预实例化
                boolean isEagerInit;
                if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                    //一个匿名内部类
                    isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) () ->
                                                                ((SmartFactoryBean<?>) factory).isEagerInit(),
                                                                getAccessControlContext());
                }
                else {
                    isEagerInit = (factory instanceof SmartFactoryBean &&
                                   ((SmartFactoryBean<?>) factory).isEagerInit());
                }
                if (isEagerInit) {
                    //调用getBean方法,触发容器对Bean实例化和依赖注入过程
                    getBean(beanName);
                }
            }
            else {
                getBean(beanName);
            }
        }
    }

    //略...
}

可以看到,这里会遍历所有的Bean,如果是单例且lazy-init=false才会进行初始化,而真正初始化的工作将从getBean方法 中展开。

初始化Bean

在BeanFactory继承体系结构中,可以看到AbstractBeanFactory这个抽象类实现了BeanFactory接口,自然在这个抽象类中会实现getBean方法:

//获取IOC容器中指定名称的Bean
@Override
public Object getBean(String name) throws BeansException {
    //doGetBean才是真正向IoC容器获取被管理Bean的过程
    return doGetBean(name, null, null, false);
}
//真正实现向IOC容器获取Bean的功能,也是触发依赖注入功能的地方
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                          @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

    //根据指定的名称获取被管理Bean的名称,剥离指定名称中对容器的相关依赖
    //如果指定的是别名,将别名转换为规范的Bean名称
    final String beanName = transformedBeanName(name);
    Object bean;

    // Eagerly check singleton cache for manually registered singletons.
    //先从缓存中取是否已经有被创建过的单态类型的Bean
    //对于单例模式的Bean整个IOC容器中只创建一次,不需要重复创建
    Object sharedInstance = getSingleton(beanName);
    //IOC容器创建单例模式Bean实例对象
    if (sharedInstance != null && args == null) {
        if (logger.isDebugEnabled()) {
            //如果指定名称的Bean在容器中已有单例模式的Bean被创建
            //直接返回已经创建的Bean
            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 + "'");
            }
        }
        //获取给定Bean的实例对象,主要是完成FactoryBean的相关处理
        //注意:BeanFactory是管理容器中Bean的工厂,而FactoryBean是
        //创建创建对象的工厂Bean,两者之间有区别
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    else {
        // Fail if we're already creating this bean instance:
        // We're assumably within a circular reference.
        //缓存没有正在创建的单例模式Bean
        //缓存中已经有已经创建的原型模式Bean
        //但是由于循环引用的问题导致实例化对象失败
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        // Check if bean definition exists in this factory.
        //对IOC容器中是否存在指定名称的BeanDefinition进行检查,首先检查是否
        //能在当前的BeanFactory中获取的所需要的Bean,如果不能则委托当前容器
        //的父级容器去查找,如果还是找不到则沿着容器的继承体系向父级容器查找
        BeanFactory parentBeanFactory = getParentBeanFactory();
        //当前容器的父级容器存在,且当前容器中不存在指定名称的Bean
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // Not found -> check parent.
            //解析指定Bean名称的原始名称
            String nameToLookup = originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                    nameToLookup, requiredType, args, typeCheckOnly);
            }
            else 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);
            }
        }

        //创建的Bean是否需要进行类型验证,一般不需要
        if (!typeCheckOnly) {
            //向容器标记指定的Bean已经被创建
            markBeanAsCreated(beanName);
        }

        try {
            //根据指定Bean名称获取其父级的Bean定义
            //主要解决Bean继承时子类合并父类公共属性问题
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            // Guarantee initialization of beans that the current bean depends on.
            //获取当前Bean所有依赖Bean的名称
            String[] dependsOn = mbd.getDependsOn();
            //如果当前Bean有依赖Bean
            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 + "'");
                    }
                    //递归调用getBean方法,获取当前Bean的依赖Bean
                    registerDependentBean(dep, beanName);
                    //把被依赖Bean注册给当前依赖的Bean
                    getBean(dep);
                }
            }

            // Create bean instance.
            //创建单例模式Bean的实例对象
            if (mbd.isSingleton()) {
                //这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        //创建一个指定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.
                        //显式地从容器单例模式Bean缓存中清除实例对象
                        destroySingleton(beanName);
                        throw ex;
                    }
                });
                //获取给定Bean的实例对象
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }

            //IOC容器创建原型模式Bean实例对象
            else if (mbd.isPrototype()) {
                // It's a prototype -> create a new instance.
                //原型模式(Prototype)是每次都会创建一个新的对象
                Object prototypeInstance = null;
                try {
                    //回调beforePrototypeCreation方法,默认的功能是注册当前创建的原型对象
                    beforePrototypeCreation(beanName);
                    //创建指定Bean对象实例
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    //回调afterPrototypeCreation方法,默认的功能告诉IOC容器指定Bean的原型对象不再创建
                    afterPrototypeCreation(beanName);
                }
                //获取给定Bean的实例对象
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            //要创建的Bean既不是单例模式,也不是原型模式,则根据Bean定义资源中
            //配置的生命周期范围,选择实例化Bean的合适方法,这种在Web应用程序中
            //比较常用,如:request、session、application等生命周期
            else {
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                //Bean定义资源中没有配置生命周期范围,则Bean定义不合法
                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);
                        }
                    });
                    //获取给定Bean的实例对象
                    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) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

    // Check if required type matches the type of the actual bean instance.
    //对创建的Bean实例对象进行类型检查
    if (requiredType != null && !requiredType.isInstance(bean)) {
        try {
            T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
            if (convertedBean == null) {
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
            return convertedBean;
        }
        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());
        }
    }
    return (T) bean;
}

在doGetBean方法中,其实做了很多事,这里一一解释:

  1. 首先调用 getSingleton(beanName); 方法,先尝试获取一个单例实例,这个方法解决了循环依赖的问题,下面我会详细的说明。
  2. 如果尝试获取的实例不存在当前IOC容器,如果父容器不为空会去父容器中获取Bean。
  3. 经过以上步骤都没有获取到Bean实例的话,先寻找所有依赖的Bean,对依赖的Bean循环调用getBean()方法(依赖Bean有可能为单例,此时如果是单例Bean的话这样做的目的第一是先将此Bean初始化,第二是会将其缓存下来,等之后依赖注入会用到)
    • 如果是单例Bean:调用getSingleton方法,其第二个参数ObjectFactory是一个功能接口,里面有一个模板提供方法,getObject,调用方法返回实例,所以在外面调用getSingleton方法时使用匿名类方式将子类createBean方法赋给ObjectFactory对象的getObject方法,便于在getSingleton方法中可以调用。这里是一个面向函数式编程思想 。这里多一层getSingleton方法是为了解决循环依赖问题 ,下面会详细解释。
    • 如果是原型Bean:直接调用子类createBean方法,因为其不需要经过一些循环依赖步骤,换言之,如果有原型Bean循环依赖了,是不能解决的,会抛出异常。
    • 如果是其他scope的Bean:会设置其scope,然后同样是调用createBean去创建。

到这里我们应该要明白了,真正去创建Bean的方法是createBean

//创建Bean实例对象
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    throws BeanCreationException {

    if (logger.isDebugEnabled()) {
        logger.debug("Creating instance of bean '" + beanName + "'");
    }
    RootBeanDefinition mbdToUse = mbd;

    // Make sure bean class is actually resolved at this point, and
    // clone the bean definition in case of a dynamically resolved Class
    // which cannot be stored in the shared merged bean definition.
    //判断需要创建的Bean是否可以实例化,即是否可以通过当前的类加载器加载
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

    //略...

    try {
        // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
        //如果Bean配置了初始化前和初始化后的处理器,则试图返回一个需要创建Bean的代理对象
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                                        "BeanPostProcessor before instantiation of bean failed", ex);
    }

    try {
        //创建Bean的入口
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) {
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }
    
    //略...
}

这里也分步骤进行解读:

  1. 首先会先判断此Bean是否可以实例化。
  2. 然后此时会调用resolveBeforeInstantiation方法,这是一个通知回调方法,会将此时的Bean的Class与BeanName传入容器中实现了InstantiationAwareBeanPostProcessor接口的方法postProcessBeforeInstantiation。举个例子AbstractAutoProxyCreator这个类实现了BeanPostProcessor这个接口来完成AOP代理,但它同时也实现了InstantiationAwareBeanPostProcessor这个接口,这个接口的方法调用时间即为上述Bean实例化与依赖注入之前(doCreateBean 才真正进行Bean实例化与依赖注入)。如果关于BeanPostProcessor的知识不懂的话,可以看看下一章我会讲到Spring的自定义扩展方式,然后下下章讲到AOP的时候也会详细讲解AbstractAutoProxyCreator实现InstantiationAwareBeanPostProcessor接口的真正作用,这里读者只要记住,InstantiationAwareBeanPostProcessor的调用时机是在Bean实例化以前。
  3. 如果此时InstantiationAwareBeanPostProcessor的回调方法没有获取到Bean(自定义扩展的内容,说明没有进行自定义扩展),那么进入真正创建Bean的方法doCreateBean
//真正创建Bean的方法
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
    throws BeanCreationException {

    // Instantiate the bean.
    //封装被创建的Bean对象
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    final Object bean = instanceWrapper.getWrappedInstance();
    //获取实例化对象的类型
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }

    // Allow post-processors to modify the merged bean definition.
    //调用PostProcessor后置处理器
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                                "Post-processing of merged bean definition failed", ex);
            }
            mbd.postProcessed = true;
        }
    }

    // Eagerly cache singletons to be able to resolve circular references
    // even when triggered by lifecycle interfaces like BeanFactoryAware.
    //向容器中缓存单例模式的Bean对象,以防循环引用
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                                      isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        if (logger.isDebugEnabled()) {
            logger.debug("Eagerly caching bean '" + beanName +
                         "' to allow for resolving potential circular references");
        }
        //这里是一个匿名内部类,为了防止循环引用,尽早持有对象的引用
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    // Initialize the bean instance.
    //Bean对象的初始化,依赖注入在此触发
    //这个exposedObject在初始化完成之后返回作为依赖注入完成后的Bean
    Object exposedObject = bean;
    try {
        //将Bean实例对象封装,并且Bean定义中配置的属性值赋值给实例对象
        populateBean(beanName, mbd, instanceWrapper);
        //初始化Bean对象
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {
        if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
            throw (BeanCreationException) ex;
        }
        else {
            //抛异常..略...
        }
    }

    if (earlySingletonExposure) {
        //获取指定名称的已注册的单例模式Bean对象
        Object earlySingletonReference = getSingleton(beanName, false);
        if (earlySingletonReference != null) {
            //根据名称获取的已注册的Bean和正在实例化的Bean是同一个
            if (exposedObject == bean) {
                //当前实例化的Bean初始化完成
                exposedObject = earlySingletonReference;
            }
            //当前Bean依赖其他Bean,并且当发生循环引用时不允许新创建实例对象
            else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                String[] dependentBeans = getDependentBeans(beanName);
                Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                //获取当前Bean所依赖的其他Bean
                for (String dependentBean : dependentBeans) {
                    //对依赖Bean进行类型检查
                    if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                        actualDependentBeans.add(dependentBean);
                    }
                }
                
                //略...
                
            }
        }
    }

    // Register bean as disposable.
    //注册完成依赖注入的Bean
    try {
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    }

    return exposedObject;
}
  1. 创建完成的Bean实例,其实又被Spring封装了一层,最终封装Bean为BeanWrapper,此封装类存放Bean实例对象、Bean的Class类型等。createBeanInstance(beanName, mbd, args) 方法会实例化Bean,并且封装成BeanWrapper返回。注意此时仅仅只是调用构造器实例化Bean而已。
  2. 在实例化Bean之后,如果该Bean是单例且允许循环依赖(可在配置中配置此属性),在此为了解决循环引用,提前将对象引用暴露出来,下面会提到循环引用的解决方法。
  3. 到这里Bean已经实例化好了,接下来调用populateBean(beanName, mbd, instanceWrapper) 方法进行依赖注入。
  4. 此时的Bean已是实例化且依赖注入好的Bean,接着会调用initializeBean(beanName, exposedObject, mbd) 方法,该方法是一个回调通知方法,在扩展Spring中会详细解释,这里只要记住,在这个时机Spring提供出了一个回调方法可供扩展。
  5. 调用 registerDisposableBeanIfNecessary(beanName, bean, mbd); 方法注册此Bean。

解决循环依赖的问题

什么是循环依赖?

假设aBean中需要依赖bBean,而bBean中也需要依赖aBean,这时初始化aBean时,需要进行依赖注入,所以需要初始化bBean,而在bBean初始化时又需要依赖注入,此时需要一个aBean,这就造成了一个死锁,aBean在等待bBean初始化好,才能完成aBean的初始化,而bBean又在等待aBean初始化好,才能完成bBean的初始化,那么在Spring中是如何解决这种循环依赖问题的呢?

Spring中如何解决循环依赖

让我们回顾一下时序,我们先是调用了getBean方法,接着调用doGetBean方法真正去获取Bean,不知读者是否还记得,此时会先去调用getSingleton(beanName) 方法,尝试获取一个单例实例:

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    //尝试先从singletonObjects获取实例
    Object singletonObject = this.singletonObjects获取实例.get(beanName);
    //如果singletonObjects没有存放此Bean的实例的话,获取早期暴露的实例
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            //先尝试从早期暴露缓存earlySingletonObjects中获取
            singletonObject = this.earlySingletonObjects.get(beanName);
            //早期暴露的缓存没有的话,去早期暴露的Map中获取
            if (singletonObject == null && allowEarlyReference) {
                //singletonFactories此Map即为早期暴露的Map
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                //如果可以获取到早期暴露的对象的话
                if (singletonFactory != null) {
                    //从此singletonFactory中获取Bean实例
                    singletonObject = singletonFactory.getObject();
                    //存放在早期暴露的缓存中,下次取只需要从earlySingletonObjects拿即可
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    //由于已经存放在缓存中,singletonFactories继续存放没有意义,移除
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

此时读者需要记住几个Map,关注接下来的方法它们的put时机和put的value到底是什么:

  1. singletonObjects:存放单例Bean的一个Map。
  2. earlySingletonObjects :早期暴露的缓存,在获取早期暴露对象之后会进行缓存。
  3. singletonFactories :关键解决了循环依赖问题的一个Map对象,方式是过早暴露Bean引用。需要关注的点是它的value是一个ObjectFactory对象,此时依然是面向函数式编程 ,此接口只是一个功能暴露接口,也就是最终调用singletonFactory.getObject(); 的方法为关键,该方法获取早期Bean实例。

接着回忆一下,在尝试调用getSingleton方法未获得对象时,会判断是否为单例,如果Bean为单例则会调用getSingleton(String beanName, ObjectFactory singletonFactory) 方法,注意此时的方法与上面的参数不一样,重载方法:

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    //此过程需要进行同步处理
    synchronized (this.singletonObjects) {
        //依然先尝试从singletonObjects中获取
        Object singletonObject = this.singletonObjects.get(beanName);
        //获取不到的话
        if (singletonObject == null) {
            //如果此时单例Bean已经是在创建了,由于是单例的Bean,所以需要抛出异常
            if (this.singletonsCurrentlyInDestruction) {
                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 + "'");
            }
            //此时就是上述提到的创建Bean的标识,在此标记此Bean已经正在创建
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<>();
            }
            try {
                //面向函数编程,调用功能接口中的方法获取单例Bean,getObject方法的实现
                //在调用getSingleton之前就已经使用匿名类的方式传入
                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;
                }
                //此时移除Bean创建的标识,表示此Bean不在创建时间了,已经创建完成
                afterSingletonCreation(beanName);
            }
            if (newSingleton) {
                //此时会将创建好了的Bean存入单例Map中
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}
protected void addSingleton(String beanName, Object singletonObject) {
    //需要同步处理
    synchronized (this.singletonObjects) {
        //加入singletonObjects以供后续getBean时直接获取实例
        this.singletonObjects.put(beanName, singletonObject);
        //将早期暴露的实例移除,就算不移除这里也没有用了,因为根本不会有进入此Map的时机
        this.singletonFactories.remove(beanName);
        //这里就更不用说了,不会有进入此Map的时机
        this.earlySingletonObjects.remove(beanName);
        this.registeredSingletons.add(beanName);
    }
}

由于此时已经将完整的Bean(实例化以及依赖注入完成)创建出来了,所以直接放入singletonObjects这个Map中,以供后续getBean时就可以直接取出。如果你还记得上面我让你记住的那几个Map的话,此时你应该可以有一个承上启下的感觉,singletonObjects是在初始化Bean完成时才会put实例

此时我们回到创建单例Bean中:

// Create bean instance.
//创建单例模式Bean的实例对象
if (mbd.isSingleton()) {
    //这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
    sharedInstance = getSingleton(beanName, () -> {
        try {
            //创建一个指定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.
            //显式地从容器单例模式Bean缓存中清除实例对象
            destroySingleton(beanName);
            throw ex;
        }
    });
    //获取给定Bean的实例对象
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

这里可以看得出来,此时将子类实现的createBean方法传入getSingleton中以供后续getObject调用,也就是说,真正创建Bean的方法是createBean(在上面说初始化的时候也有提到,所以这里只是提一下经过了哪些方法,不贴代码详细描述),而createBean中判断了一下此Bean是否可以实例化,接着调用真正干事情的doCreateBean方法去初始化Bean,此时会先调用构造器实例化此Bean,注意此时仅仅是实例化一个Bean对象出来,Bean实例还未依赖注入,此时会调用这样一段代码:

//向容器中缓存单例模式的Bean对象,以防循环引用
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                                  isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
    if (logger.isDebugEnabled()) {
        logger.debug("Eagerly caching bean '" + beanName +
                     "' to allow for resolving potential circular references");
    }
    //这里是一个匿名内部类,为了防止循环引用,尽早持有对象的引用
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

上面也有说过,这里会判断是否为单例,且允许循环依赖,才会进入addSingletonFactory方法:

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(singletonFactory, "Singleton factory must not be null");
    //同步处理
    synchronized (this.singletonObjects) {
        //如果singletonObjects不存在该Bean才进行早期暴露
        if (!this.singletonObjects.containsKey(beanName)) {
            //会put一个功能接口对象到singletonFactories这个Map中
            this.singletonFactories.put(beanName, singletonFactory);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }
}

此方法我称为一个早期暴露实例的方法,注意此时这里可以通过getEarlyBeanReference方法获得此时Bean的引用(Bean仅仅是实例化),然后将该方法传给ObjectFactory这个功能接口的getObject方法,此时只需要将ObjectFactory这个具有获取早期Bean引用的方法的对象put进singletonFactories这个Map中,读到这里,聪明的读者应该已经知道了Spring到底是如何解决循环依赖问题的了。

循环依赖总结

心中需要有一个时序图,你将会看的更清晰

getBean -> doGetBean -> 先去singletonObjects这个Map中查看是否已经有Bean实例,如果没有 -> 此Bean为单例的情况下,查看singletonFactories此Map是否有早期暴露的单例Bean引用 -> 如果有证明此时这个单例Bean在其他地方已经在创建了,此时只需要返回此引用作为Bean实例即可。

  1. singletonObjects时机:会在完整创建完一个单例Bean时,存放起来,容器即为singletonObjects这个Map,并且会移除早期暴露 singletonFactories 这个Map中关于该Bean的引用。
  2. singletonFactories时机:在单例Bean情况下,在仅仅是实例化还未依赖注入此Bean时提前将Bean引用早期就存放在singletonFactories这个Map中,所以在doGetBean 尝试获取Bean实例时即可拿到一个Bean引用。

此时就来回顾一下上述的循环依赖问题:

当创建aBean时,先去看看singletonObjects是否已经有实例,显然是没有,然后就会实例化此Bean,在这之后,依赖注入之前,将aBean的引用存放在singletonFactories这个Map中,然后进行依赖注入,此时发现aBean依赖bBean,所以需要去初始化bBean,依然是先看看singletonObjects是否有bBean,显然也没有,然后就实例化bBean,在bBean依赖注入时,发现此Bean依赖aBean,所以又去初始化aBean了,然后aBean又去singletonObjects看是否存在实例,显然此时还是没有的,然后去singletonFactories这个Map查找的时候,发现存在一个Bean引用,所以获取该引用作为aBean,将此引用注入到bBean完成bBean依赖注入的过程,bBean初始化结束,然后回到aBean依赖注入,初始化bBean成功,将bBean注入到aBean,然后aBean初始化也成功,没有循环依赖问题。

为什么早期暴露一个引用就可以解决循环依赖问题呢?

还是看这个例子,在bBean中注入的aBean依赖仅仅是一个aBean实例化之后还未依赖注入(不完整aBean)引用,但当aBean也初始化好了,bBean中的aBean(此时是完整的aBean)不也初始化好了吗?因为引用指向的对象都是同一个地址,这样bBean就能提前初始化好,只有bBean初始化好了aBean才能初始化好,所以解决了循环依赖的问题。

但此时有一个问题,在上面介绍的所有的过程都是针对于单例Bean的,如果不是单例Bean根本都不会进行上述操作,如果是原型Bean循环依赖另一个原型Bean怎么办呢?目前我所知道的这个应该是解决不了的,在初始化的过程中就会报循环依赖的异常,所以要保证Bean为单例,才可以循环依赖。

FactoryBean

FactoryBean是Spring定义的一个特殊的Bean,先来看看它定义了什么方法:

//工厂Bean,用于产生其他对象
public interface FactoryBean<T> {

	//获取容器管理的对象实例
	@Nullable
	T getObject() throws Exception;

	//获取Bean工厂创建的对象的类型
	@Nullable
	Class<?> getObjectType();

	//Bean工厂创建的对象是否是单态模式,如果是单态模式,则整个容器中只有一个实例
	//对象,每次请求都返回同一个实例对象
	default boolean isSingleton() {
		return true;
	}
}

如果此Bean是FactoryBean,就必须实现FactoryBean接口。通过该接口可以看出FactoryBean的一些特性:

  1. getObeject:定义了一个获取Bean对象的方法。
  2. getObjectType:定义了一个获取Bean的Class对象的方法。
  3. isSingleton:判断此Factory生成的Bean是否为单例Bean,默认为true。

FactoryBean是什么

它是一个特殊的Bean,从名字就可以看出来,它是由Bean结尾的,意味着是一个Bean,但此Bean是工厂类型的Bean,什么意思呢?普通Bean只是IOC容器管理的真正代码中使用的对象,但工厂Bean不是我们要使用的对象,它负责生产真正的Bean,它是一个工厂,但它也是由工厂(BeanFactory)生产出来的,也就是说,FactroyBean是用来生产Bean而生的

FactoryBean在IOC容器哪里用到

BeanFactory接口中,定义了一个静态变量:

//对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,
//如果需要得到工厂本身,需要转义
String FACTORY_BEAN_PREFIX = "&";

这个用处是用来区分要获取的是FactoryBean本身还是FactoryBean生产出来的Bean。假设有一个FactoryBean,BeanName=“demo”,你调用getBean方法希望获取到它的本身,你需要加一个符号:getBean("&demo"),此时你get到的对象会是FactoryBean本身,如果不加此符号,会获取此FactoryBean的方法getObject生产出来的Bean作为返回值。没听懂?看看下面就懂了。

回顾以上初始化Bean的过程,我们回到getBean之后的doGetBean这个一开始的起点方法中:

// Create bean instance.
//创建单例模式Bean的实例对象
if (mbd.isSingleton()) {
    //这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
    sharedInstance = getSingleton(beanName, () -> {
        try {
            //创建一个指定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.
            //显式地从容器单例模式Bean缓存中清除实例对象
            destroySingleton(beanName);
            throw ex;
        }
    });
    //获取给定Bean的实例对象
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

这里举一个创建单例Bean过程的一段代码。我们上面介绍了createBean的流程,此时返回一个Bean是已经是实例化好了并且依赖注入完成,各种回调方法完成之后的一个Bean实例sharedInstance,但是它没有真正的返回出去,而是又执行了一个方法getObjectForBeanInstance

//获取给定Bean的实例对象,主要是完成FactoryBean的相关处理
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.
    //容器已经得到了Bean实例对象,这个实例对象可能是一个普通的Bean,
    //也可能是一个工厂Bean,如果是一个工厂Bean,则使用它创建一个Bean实例对象,
    //如果调用本身就想获得一个容器的引用,则指定返回这个工厂Bean实例对象
    //如果指定的名称是容器的解引用(dereference,即是对象本身而非内存地址),
    //且Bean实例也不是创建Bean实例对象的工厂Bean
    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.
    //如果Bean实例不是工厂Bean,或者指定名称是容器的解引用,
    //调用者向获取对容器的引用,则直接返回当前的Bean实例
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }

    //处理指定名称不是容器的解引用,或者根据名称获取的Bean实例对象是一个工厂Bean
    //使用工厂Bean创建一个Bean的实例对象
    Object object = null;
    if (mbd == null) {
        //从Bean工厂缓存中获取给定名称的Bean实例对象
        object = getCachedObjectForFactoryBean(beanName);
    }
    //让Bean工厂生产给定名称的Bean对象实例
    if (object == null) {
        // Return bean instance from factory.
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // Caches object obtained from FactoryBean if it is a singleton.
        //如果从Bean工厂生产的Bean是单态模式的,则缓存
        if (mbd == null && containsBeanDefinition(beanName)) {
            //从容器中获取指定名称的Bean定义,如果继承基类,则合并基类相关属性
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        //调用FactoryBeanRegistrySupport类的getObjectFromFactoryBean方法,
        //实现工厂Bean生产Bean对象实例的过程
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}

也就是说,每一个Bean在初始化完成时,都会进入这个方法,这个方法会判断该Bean是否是FactoryBean,如果是的话,我们需要get的并不是这个FactoryBean,而是FactoryBean生产出来的Bean

  1. 先是判断get的名称是否为 “&” 符号开头,如果是的话就是指获取FactoryBean本身即可,但此Bean又没有实现FactoryBean,也就是说在不是FactoryBean的Bean上获取本身("&")将会抛出异常
  2. 再是判断该Bean如果不是FactoryBean,说明是普通Bean,直接返回本身即可,亦或是以"&"开头的,上面也说了,以“&"开头的话获取的是本身,所以也是直接返回本身即可。
  3. 如果程序运行到了这里,我们可以知道,此Bean是一个FactoryBean且并不是获取本身,而是获取FactoryBean生产出来的Bean,此时会先去FactoryBean缓存中获取是否有已经创建好了的Bean实例。
  4. 缓存如果有返回缓存即可,缓存没有就调用getObjectFromFactoryBean方法,从FactoryBean中生产Bean
//Bean工厂生产Bean实例对象
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    //Bean工厂是单态模式,并且Bean工厂缓存中存在指定名称的Bean实例对象
    if (factory.isSingleton() && containsSingleton(beanName)) {
        //多线程同步,以防止数据不一致
        synchronized (getSingletonMutex()) {
            //直接从Bean工厂缓存中获取指定名称的Bean实例对象
            Object object = this.factoryBeanObjectCache.get(beanName);
            //Bean工厂缓存中没有指定名称的实例对象,则生产该实例对象
            if (object == null) {
                //调用Bean工厂的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) {
                        try {
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        }
                        catch (Throwable ex) {
                            throw new BeanCreationException(beanName,
                                                            "Post-processing of FactoryBean's singleton object failed", ex);
                        }
                    }
                    //将生产的实例对象添加到Bean工厂缓存中
                    this.factoryBeanObjectCache.put(beanName, object);
                }
            }
            return object;
        }
    }
    //调用Bean工厂的getObject方法生产指定Bean的实例对象
    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;
    }
}
  1. 首先判断FactoryBean生产的Bean是否为单例的,判断方法在FactoryBean接口中就已经定义此方法,并且要在熟悉的singletonObjects这个存放单例Bean的Map中存在此Bean,就可以判断生产的Bean为单例,所以需要缓存它,这个过程需要同步控制,接下来就调用doGetObjectFromFactoryBean方法去获取真正的Bean,并将其放入缓存中factoryBeanObjectCache.put(beanName, object),以便下一次获取。然后返回真正生产出来的Bean。
  2. 此时如果走到这里,说明生产出来的Bean为非单例的,所以不需要缓存,只需要简单的调用doGetObjectFromFactoryBean方法去获取真正的Bean返回即可

以上两种可能性都调用了同一个方法doGetObjectFromFactoryBean

//调用Bean工厂的getObject方法生产指定Bean的实例对象
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
    throws BeanCreationException {

    Object object;
   
    //安全验证,略...

    //调用BeanFactory接口实现类的创建对象方法
    object = factory.getObject();
    
    //略...
    
    return object;
}

为了凸显出主线,我删减了一些支线代码,在这里可以看出来,最终调用的是FactoryBean的getObject方法,正是FactoryBean接口定义的这个方法,此方法为生产Bean的方法。

FactoryBean例子

为了加深理解,我举一个生产环境都会用到的一个FactoryBean来演示到底FactoryBean有什么用。

这里我拿MyBatis与Spring整合包下的一个类MapperFactoryBean作为例子讲解一下:

/**
   * {@inheritDoc}
   */
@Override
public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
}

/**
   * {@inheritDoc}
   */
@Override
public boolean isSingleton() {
    return true;
}

这里贴两个主要方法(需要有一点MyBatis的基础),我在分析MyBatis那篇文章中有提到,我们定义的那些Mapper接口,其实是SqlSession调用getMapper方法创建出来的,从以上getObject中可以看出,MapperFactoryBean是一个专门生产Mapper的一个FactoryBean,从isSingleton方法中可以看出,获取的Mapper都为单例。我们回忆一下在使用SSM的时候,如果是一个一个Mapper去配置成Bean放在IOC容器中,需要这样写:

<bean id="demoMapper" class="org.mybatis.Spring.mapper.MapperFactoryBean">
	<property name="mapperInterface" value="com.demo.DemoMapper">property>
    <property name="sqlSessionFactory" ref="sqlSessionFactory">property>
bean>

请注意,此Bean的class类型就是我们上面介绍的MapperFactoryBean,其中有属性mapperInterface ,根据此属性去使用getObject方法获取真正的Mapper对象,就算你直接配置一个Mapper扫描路径,它的底层也是将扫描到的每一个mapper接口类型作为MapperFactoryBean,以一个FactoryBean的形式存放在IOC容器中,当getBean的时候其实是调用MapperFactoryBean这个FactoryBean的getObject方法:

@Autowired
private DemoMapper demoMapper

也就是说,你这样使用一个Mapper的时候,Spring容器其实是先获取MapperFactoryBean,然后调用所有Bean都会调用的方法getObjectForBeanInstance去进行判断,发现此Bean为一个FactoryBean,调用此Bean的getObject方法,也就是委派其中的SqlSession去getMapper,从而获取真正的Mapper。

总结

到此就结束了初始化Bean的全过程,我们可以总结出来几件事:

  1. 在Spring中有一个特殊的单例模式,称为注册式单例,往Map中put那些Bean实例达到单例的效果(过程进行同步处理,解决并发问题)。
  2. 在初始化IOC容器时就会初始化Bean( 单例且lazy-init = false ),并将这些Bean存放在(BeanFactory的)Map中,这可以节省时间,一些单例Bean在启动时就已经创建好,使用时只需获取Map中实例即可。
  3. 与上一个类似的,如果Bean是除了单例之外的scope,在getBean时同样会走doCrateBean去创建实例,但区别在于不会对其进行缓存,也就是说,除单例之外的scope,可以达到每次getBean都是不同实例的Bean的效果。
  4. 循环依赖问题只在单例Bean 上被解决,原型Bean之间的循环依赖会抛出异常
  5. 在初始化Bean时多次出现回调通知方法,这个特性展现了Spring框架的易扩展性,这是非常强大的设计,将在下一章中对其进行讲解,AOP的实现也依赖于此。
  6. Factory是一个特殊的Bean ,主要用途是用来生产Bean的,请注意IOC容器中singletonObjects这个Map将会存放所有初始化好的单例Bean(包括那些单例的FactoryBean),而factoryBeanObjectCache存放的则是那些FactoryBean生产出来的Bean,也就是说,IOC容器不仅会存放FactoryBean在容器中,还会存放FactoryBean生产的Bean在容器中,双重缓存加快获取Bean的效率。这里读者要理清两者的关系。

你可能感兴趣的:(spring)