zoukankan      html  css  js  c++  java
  • [转]spring 学习-bean创建-循环依赖-2

    转载自 https://www.iflym.com/index.php/code/201208280001.html

    上文中对涉及到循环引用的3个方法作了陈述。

    在方法1中,对象信息对beanFactory的形式被放入singletonFactories中,这时earlySingletonObjects中肯定没有此对象(因为remove)。

    在方法2中,在一定条件下(allowEarlyReference为true)的条件下,对象从singleFactories中的objectFactory中被取出来,同时remove掉,被放入earlySingletonObjects中。这时,earlySingletonObjects就持有对象信息了;当然,如果allowEarlyReference为false的情况下,且earlySingletonObjects本身就没有持有对象的情况下,肯定不会将对象从objectFactory中取出来的。这个很重要,因为后面将根据此信息进行循环引用处理。

    在方法3中,对象被加入到singletonObjects中,同时singletonFactories和earlySingletonObjects中都remove掉持有的对象(不管持有与否),这就表示在之前的处理中,这只相当于一个临时容器,处理完毕之后都会remove掉。

    那么,我们来看这3个方法是不是按照先后顺序被调用的呢。代码顺序如下所示:

    类AbstracBeanFactory获取bean。M-1

    protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
    if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                        public Object getObject() throws BeansException {
                            try {
                                return createBean(beanName, mbd, args);
                            }               ……
    }
    

    进入getSingleton方法M-2

    Object singletonObject = this.singletonObjects.get(beanName);
                    try {
    //首先执行getObject方法,再执行finnaly中的addSingleton方法,即上文中的方法3
                        singletonObject = singletonFactory.getObject();
                    }finally {
    addSingleton(beanName, singletonObject);
                }
                return (singletonObject != NULL_OBJECT ? singletonObject : null);
            }
    

    查看singletonFactory.getObject(),即createBean(beanName, mbd, args),最终转向doCreateBean方法M-3

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
            // Instantiate the bean.
            BeanWrapper instanceWrapper = null;
                        instanceWrapper = createBeanInstance(beanName, mbd, args);
                addSingletonFactory(beanName, new ObjectFactory() {
                    public Object getObject() throws BeansException {
                        return getEarlyBeanReference(beanName, mbd, bean);
                    }
                });
            }
    

    上面代码会调用方法addSingletonFactory,即上文所说的方法1。
    那么方法2会在什么地方调用呢。答案在两个地点。

    第一个地方,称之为调用点A,即在最开始获取bean时,会调用。

    Object sharedInstance = getSingleton(beanName);
    

    此方法最终会调用到

    getSingleton(beanName, true)
    

    这里传递了参数true。即会尝试解析singletonFactories。然而,在最开始创建对象时,singletonFactories中肯定不会持有对象信息,所以会返回null。

    第二个地方,称之为调用点B,即在完成bean创建时,会有一个验证过程。即在方法M-3中,即在调用方法2之前。代码如下:

    if (earlySingletonExposure) {
                Object earlySingletonReference = getSingleton(beanName, false);
                if (earlySingletonReference != null) {
                    if (exposedObject == bean) {
                        exposedObject = earlySingletonReference;
                    }
                    else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                        String[] dependentBeans = getDependentBeans(beanName);
                        Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
                        for (String dependentBean : dependentBeans) {
                            if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                                actualDependentBeans.add(dependentBean);
                            }
                        }
                        if (!actualDependentBeans.isEmpty()) {
                            throw 文章开头的异常。
                        }
                    }
                }
    

    调用点B的逻辑有点多,后面的逻辑主要是作循环引用验证。注意在调用点B传递参数为false,即不会解析singletonFactories。

    详细见下一篇

  • 相关阅读:
    mybatis:SQL拦截器
    eclipse:插件安装总结
    eclpse:安装explorer或eExplorer插件
    Spring Tools4
    nginx+tomcat:动静分离+https
    Tomcat:3DES解密时中文乱码
    wireshark如何抓取localhost包
    nginx: 应用访问默认采用https
    windows :config windows update … 一直处于假死状态
    EHCache:Eelment刷新后,timeToLiveSeconds失效了?
  • 原文地址:https://www.cnblogs.com/Benjious/p/15183075.html
Copyright © 2011-2022 走看看