zoukankan      html  css  js  c++  java
  • Spring源码分析(十四)从bean的实例中获取对象

    摘要:本文结合《Spring源码深度解析》来分析Spring 5.0.6版本的源代码。若有描述错误之处,欢迎指正。 

    在getBean方法中,getObjectForBeanlnstance是个髙频率使用的方法,无论是从缓存中获得bean还是根据不同的scope策略加载bean。总之,我们得到bean的实例后要做的第一步就是调用这个方法来检测一下正确性,其实就是用于检测当前bean是否是FactoryBean类型的bean,如果是,那么需要调用该bean对应的FactoryBean实例中的getObject()作为返回值。

    无论是从缓存中获取到的bean还是通过不同的scope策略加载的bean都只是最原始的bean状态,并不一定是我们最终想要的bean。举个例子,假如我们需要对工厂bean进行处理,那么这里得到的其实是工厂bean的初始状态,但是我们真正需要的是工厂bean中定义的 factory-method方法中返回的bean,而getObjectForBeanlnstance方法就是完成这个工作的。

    /**
     * Get the object for the given bean instance, either the bean
     * instance itself or its created object in case of a FactoryBean.
     * @param beanInstance the shared bean instance
     * @param name name that may include factory dereference prefix
     * @param beanName the canonical bean name
     * @param mbd the merged bean definition
     * @return the object to expose for the bean
     */
    protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
    
        // Don't let calling code try to dereference the factory if the bean isn't a factory.
        // 如果指定的name是工厂相关(以&为前缀)且 beanInstance又不是FactoryBean类型则验证不通过
        if (BeanFactoryUtils.isFactoryDereference(name)) {
            if (beanInstance instanceof NullBean) {
                return beanInstance;
            }
            if (!(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或者是FactoryBean
        // 如果是FactoryBean我们使用它创建实例,似是如果用户想要直接获取工厂实例而不是工厂的getObject方法对应的实例,那么传人的name应该加入前缀&
        if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
            return beanInstance;
        }
    
        // 加栽 FactoryBean
        Object object = null;
        if (mbd == null) {
            // 尝试从缓存中加栽bean
            object = getCachedObjectForFactoryBean(beanName);
        }
        if (object == null) {
            // Return bean instance from factory.
            //到这里已经明确知道beanInstance—定是FactoryBean类型
            FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
            // Caches object obtained from FactoryBean if it is a singleton.
            // containsBeanDefinition检测beanDefinitionMap中也就是在所有已经加载的类中检测是否定义beanName
            if (mbd == null && containsBeanDefinition(beanName)) {
                // 将存储 XML 配置文件的 GenericBeanDefinition 转换为 RootBeanDefinition, 如果指定beanName是子Bean的话同时会合并父类的相关属性
                mbd = getMergedLocalBeanDefinition(beanName);
            }
            // 是否是用户定义的而不是应用程序本身定义的
            boolean synthetic = (mbd != null && mbd.isSynthetic());
            object = getObjectFromFactoryBean(factory, beanName, !synthetic);
        }
        return object;
    }

    从上面的代码来看,其实这个方法并没有什么重要的信息,大多是些辅助代码以及一些功能性的判断,而真正的核心代码却委托给了getObjectFromFactoryBean,我们来看看 getObjectForBeanlnstance 所做的工作。

    (1)对FactoryBean正确性的验证。

    (2)对非FactoryBean不做任何处理。

    (3)对bean进行转换。

    (4)将从 Factory 中解析 bean 的工作委托给 getObjectFromFactoryBean。

    /**
     * Obtain an object to expose from the given FactoryBean.
     * @param factory the FactoryBean instance
     * @param beanName the name of the bean
     * @param shouldPostProcess whether the bean is subject to post-processing
     * @return the object obtained from the FactoryBean
     * @throws BeanCreationException if FactoryBean object creation failed
     * @see org.springframework.beans.factory.FactoryBean#getObject()
     */
    protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
        // 如果是单例模式
        if (factory.isSingleton() && containsSingleton(beanName)) {
            synchronized (getSingletonMutex()) {
                Object object = this.factoryBeanObjectCache.get(beanName);
                if (object == null) {
                    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) {
                            if (isSingletonCurrentlyInCreation(beanName)) {
                                // Temporarily return non-post-processed object, not storing it yet..
                                return object;
                            }
                            beforeSingletonCreation(beanName);
                            try {
                                // 调用ObjectFactory的后处理器
                                object = postProcessObjectFromFactoryBean(object, beanName);
                            }
                            catch (Throwable ex) {
                                throw new BeanCreationException(beanName,
                                        "Post-processing of FactoryBean's singleton object failed", ex);
                            }
                            finally {
                                afterSingletonCreation(beanName);
                            }
                        }
                        if (containsSingleton(beanName)) {
                            this.factoryBeanObjectCache.put(beanName, object);
                        }
                    }
                }
                return object;
            }
        }
        else {
            Object object = doGetObjectFromFactoryBean(factory, beanName);
            if (shouldPostProcess) {
                try {
                    object = postProcessObjectFromFactoryBean(object, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
                }
            }
            return object;
        }
    }

    很遗憾,在这个代码中我们还是没有看到想要看到的代码,在这个方法里只做了一件事情, 就是返回的bean如果是单例的,那就必须要保证全局唯一,同时,也因为是单例的,所以不必重复创建,可以使用缓存来提高性能,也就是说已经加载过就要记录下来以便于下次复用, 否则的话就直接获取了。

    在doGetObjectFromFactoryBean方法中我们终于看到了我们想要看到的方法,也就足object = factory.getObjcct(),是的,就是这句代码,我们的历程犹如剥洋葱一样,一层一层的直到最内部的代码实现,虽然很简单。

    /**
     * Obtain an object to expose from the given FactoryBean.
     * @param factory the FactoryBean instance
     * @param beanName the name of the bean
     * @return the object obtained from the FactoryBean
     * @throws BeanCreationException if FactoryBean object creation failed
     * @see org.springframework.beans.factory.FactoryBean#getObject()
     */
    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 {
                // 直接调用getObject方法
                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.
        if (object == null) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(
                        beanName, "FactoryBean which is currently in creation returned null from getObject");
            }
            object = new NullBean();
        }
        return object;
    }

    上面我们已经讲述了FactoryBean的调用方法,如果bean声明为FactoryBean类型,则当提取bean时提取的并不是FactoryBean,而是FactoryBean中对应的getObject方法返冋的bean,而doGetObjectFromFactoryBean正是实现这个功能的。但是,我们看到在上面的方法中除了调用object = factory.getObject()得到我们想要的结果后并没有直接返回,而是接下来又做了些后处理的操作,这个又是做什么用的呢?于是我们跟踪进入AbstractAutowireCapableBeanFactory 类的 postProcessObjectFromFactoryBean 方法:

    @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;
        for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
            Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }

    对于后处理器的使用我们还未过多接触,后续章节会使用大量篇幅介绍,这里,我们只需了解在Spring获取bean的规则中有这样一条:尽可能保证所有bean初始化后都会调用注册的BeanPostProcessor的postProcessAfterlnitialization方法进行处理,在实际开发过程中大可以针对此特性设计自己的业务逻辑。

  • 相关阅读:
    gain 基尼系数
    luogu P5826 【模板】子序列自动机 主席树 vector 二分
    牛客挑战赛39 树与异或 离线 树上莫队 树状数组 约数
    4.22 省选模拟赛 三元组 manacher 回文自动机
    4.22 省选模拟赛 最优价值 网络流 最大权闭合子图
    4.18 省选模拟赛 消息传递 树剖 倍增 线段树维护等比数列
    luogu P4008 [NOI2003]文本编辑器 splay 块状链表
    牛客挑战赛39 密码系统 后缀数组
    luogu P1526 [NOI2003]智破连环阵 搜索+最大匹配+剪枝
    luogu P4095 [HEOI2013]Eden 的新背包问题 多重背包 背包的合并
  • 原文地址:https://www.cnblogs.com/warehouse/p/9381976.html
Copyright © 2011-2022 走看看