工作生活

spring容器之从bean的实例中获取对象

2019-07-03  本文已影响0人  会上树的程序猿

我们还是回到spring加载的bean的原始入口,我们知道在BeanFactory#doGetBean方法中,当我们首先获取到单例的bean时,有可能不是我们想要的bean实例,当然这里spring这里给了我们一个方法,就是通过调用getObjectForBeanInstance方法来处理,该方法不论是从缓存中获取获取bean实例还是根据不同的scope获取到的bean,都要进行正确性的检查,可能是一个FactoryBean类型的bean,那么需要调用getObject来获取真正的bean实例,直接看代码:

首先是入口:

AbstractBeanFactory.java
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 + "'");
            }
        }
        //获取bean的实例
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

首先对获取到的单例bean进行简单的判null处理,接着是我们的核心方法getObjectForBeanInstance(sharedInstance, name, beanName, null),跟踪代码来到:

/**
 *
 * 该方法的主要作用是获取一个bean的实例,从FactoryBean中
 * @param beanInstance 共享bean的实例
 * @param name 普通bean和有Factory前缀的bean的name
 * @param beanName 去掉别名之后的bean的name
 * @param mbd  这个是合并之后的Bean的定义的文件--->beanDefinition
 * @return 返回一个bean的object对象
 */
protected Object getObjectForBeanInstance(
        Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

    //首先对name进行检查
    //如果name是Factory类型的(即有&开头)
    if (BeanFactoryUtils.isFactoryDereference(name)) {
        //如果beanInstance是一个空bean类型的,直接返回一个空bean的对象
        if (beanInstance instanceof NullBean) {
            return beanInstance;
        }
        //如果beanInstance不是FactoryBean类型的,抛异常
        if (!(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
        }
    }

    //这里的bean可能是factory类型,也可能是正常的bean
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }

    Object object = null;
    //如果是factory类型的bean
    if (mbd == null) {
        //尝试从getCachedObjectForFactoryBean获取
        object = getCachedObjectForFactoryBean(beanName);
    }
    //如果从缓存中没拿到
    if (object == null) {
        //这里确定的是beanInstance是FactoryBean类型的了
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // Caches object obtained from FactoryBean if it is a singleton.
        //通过containsBeanDefinition方法检测
        if (mbd == null && containsBeanDefinition(beanName)) {
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        //判断bean的定义是否是合并之后的,不是由application容器来定义,而是用户自己定义的
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        //从FactoryBean中通过调用getObject返回一个Object对象
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    //将实例object返回
    return object;
}

简单的来串一下该方法的流程,我们看到首先一进来对bean的检验

  1. 首先是对FactoryBean的正确性的检验
如果name是Factory类型的(即有&开头)
    if (BeanFactoryUtils.isFactoryDereference(name)) {
        //如果beanInstance是一个空bean类型的,直接返回一个空bean的对象
        if (beanInstance instanceof NullBean) {
            return beanInstance;
        }
        //如果beanInstance不是FactoryBean类型的,抛异常
        if (!(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
        }
    }

可以看到的是,如果beanInstance为NullBean时,直接返回,以及不是一个FactoryBean时直接抛异常

  1. 对于非FactoryBean或者是跟factory不相关的bean,不做任何处理
//这里的bean可能是factory类型,也可能是正常的bean
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }
  1. 进行上述的检验之后,接着是对bean的转换工作
//如果从缓存中没拿到
    if (object == null) {
        //这里确定的是beanInstance是FactoryBean类型的了
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // Caches object obtained from FactoryBean if it is a singleton.
        //通过containsBeanDefinition方法检测
        if (mbd == null && containsBeanDefinition(beanName)) {
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        //判断bean的定义是否是合并之后的,不是由application容器来定义,而是用户自己定义的
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        //从FactoryBean中通过调用getObject返回一个Object对象
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
  1. 将bean的获取工作委托给 getObjectFromFactoryBean(factory, beanName, !synthetic)方法去完成

上面的方法简单的就是这四步,实际上三步,到工作的末尾我们才发现将核心的方法委托给getObjectFromFactoryBean方法来完成,接着看:

/**
 * 从给定的factory中获取暴露的object
 * @param factory FactoryBean的具体实例
 * @param beanName bean的name
 * @param shouldPostProcess 是否需要后置处理
 * @return
 */
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {

    //先就是简单的判断,是否是单例和包含该单例bean
    if (factory.isSingleton() && containsSingleton(beanName)) {
        synchronized (getSingletonMutex()) {
            //先从缓存中去拿
            Object object = this.factoryBeanObjectCache.get(beanName);
            //这里表示没有拿到
            if (object == null) {
                //实质还是去调用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);
                if (alreadyThere != null) {
                    object = alreadyThere;
                }
                else {
                    //后置处理
                    if (shouldPostProcess) {
                        //通过传入的beanName来判断当前bean是否正在创建中
                        if (isSingletonCurrentlyInCreation(beanName)) {
                            // Temporarily return non-post-processed object, not storing it yet..
                            //这里返回的是临时的非后置处理的object,并不保存它
                            return object;
                        }
                        //当前单例bean创建之前的回调该方法处理
                        beforeSingletonCreation(beanName);
                        try {

                            //对object进行后置处理,如果在FactoryBean找不到该object抛如下异常
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        }
                        catch (Throwable ex) {
                            throw new BeanCreationException(beanName,
                                    "Post-processing of FactoryBean's singleton object failed", ex);
                        }
                        finally {
                            //当所有的条件具备完成,最后调用该方法对单例bean创建之后的一些处理,如:不能重复创建,
                            afterSingletonCreation(beanName);
                        }
                    }
                    //进行缓存该对象
                    if (containsSingleton(beanName)) {
                        this.factoryBeanObjectCache.put(beanName, object);
                    }
                }
            }
            //返回从FactoryBean拿到的bean
            return object;
        }
    }
    //这里说明是factory不是单例且beanName在缓存中找不到
    else {
        //1.从factoryBean中去拿
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        //需要后置处理
        if (shouldPostProcess) {
            try {
                //从factoryBean拿到object后对其后置处理逻辑,如暴露该bean
                object = postProcessObjectFromFactoryBean(object, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            }
        }
        //最后返回该object
        return object;
    }
}

在上面的方法中看似很复杂实际上通过一个条件来判断分为了两部分来处理:

  1. 如果我们的传过来的factoryBean是单例的且在singletonObjects缓存中包含bean
    1.1. 首先是获取同步锁,也就是singletonObjects,其主要的目的是为了保证全局的唯一性
DefaultSingletonBeanRegistry.java
/** 保存单例对象的map*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/**
 * Exposes the singleton mutex to subclasses and external collaborators.
 * <p>Subclasses should synchronize on the given Object if they perform
 * any sort of extended singleton creation phase. In particular, subclasses
 * should <i>not</i> have their own mutexes involved in singleton creation,
 * to avoid the potential for deadlocks in lazy-init situations.
 */
public final Object getSingletonMutex() {
    return this.singletonObjects;
}

1.2. 接着是从factoryBeanObjectCache缓存中通过beanName来获取object对象

/** 通过FactoryBeans创建的单例bean的缓存,其中FactoryBean是作为对象的名称*/
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);

//先从缓存中去拿
Object object = this.factoryBeanObjectCache.get(beanName);

1.3. 如果获取到的object为null,调用doGetObjectFromFactoryBean(factory, beanName)方法来获取object,实际上还是调用的FactoryBean#getObject()方法来获取

/**
 * 从factory(该factory实质是FactoryBean的实例)获取暴露的object对象
 * @param factory
 * @param beanName
 * @return
 * @throws BeanCreationException
 */
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
        throws BeanCreationException {

    Object object;
    try {
        //进行权限验证
        if (System.getSecurityManager() != null) {
            AccessControlContext acc = getAccessControlContext();
            try {
                object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
            }
            catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        else {
            //这里是真正的获取object的方法入口
            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);
    }

    //这里表明从FactoryBean没拿到,调用isSingletonCurrentlyInCreation判断该bean是否在创建中:
    //1.1.如果返回true,抛以下异常,当前bean在创建中
    if (object == null) {
        if (isSingletonCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(
                    beanName, "FactoryBean which is currently in creation returned null from getObject");
        }
        //1.1.2.返回false话,创建一个空bean返回
        object = new NullBean();
    }
    return object;
}

在上面的方法实际上就一个核心就是通过调用factory.getObject()方法来获取bean对象

1.4. 之后是当shouldPostProcess为true时,进一步的处理:
1.4.1. 首先是通过isSingletonCurrentlyInCreation(String beanName)方法判断当前的bean是否在创建中,直接返回,不需要进行处理.
1.4.2. 接着通过beforeSingletonCreation(beanName)方法进行bean创建之前的处理操作

/** Names of beans currently excluded from in creation checks. */
private final Set<String> inCreationCheckExclusions =
        Collections.newSetFromMap(new ConcurrentHashMap<>(16));

/**
 * 单例bean创建之前的回调方法
 *
 * @param beanName
 */
protected void beforeSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
    }
}

1.4.3. 紧接着调用postProcessObjectFromFactoryBean(object, beanName)方法对获取到的bean对象进行后置处理,关于该过程后续详解
1.4.4. 最后调用afterSingletonCreation(String beanName)方法进行对bean创建之后的一些处理,如将bean进行标记为不能重复创建等操作.

/**
 * 单例对象创建之后会调用该方法,会对已创建的单例bean进行标记,下次无需再创建
 * @param beanName 已创建完的单例bean
 */
protected void afterSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
        throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
    }
}

1.4.5. 之后是将bean对象保存到对应的缓存中

  1. 当我们的factoryBean不是单例的时候的处理过程:
    2.1. 首先是调用doGetObjectFromFactoryBean(factory, beanName)方法获取bean对象.
    2.2. 后置处理操作同时将我们的object暴露出来
/**
 * 1.通过给定的object(object是从FactoryBean获取到的)去从FactoryBean获取然后进行后置处理
 * 1.1.通过拿到的object将暴露给bean的引用
 * 1.1.2.如果仅仅是实现只会返回原来的object对象
 * @param object
 * @param beanName 当前bean的名字
 * @return
 * @throws BeansException
 */
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) throws BeansException {
    return object;
}

可以看到后置处理时并没有实现,这里我们可以在实际的开发中根据自己的需求来自己实现,这也是spring做的很好的一个点.到这里我们从bean的实例中获取object对象分析完了.

上一篇下一篇

猜你喜欢

热点阅读