Spring源码分析之IOC(七)

本文详细分析了Spring IoC容器的核心方法doGetBean(),从bean的名称解析、从缓存获取bean、处理依赖关系到实例化bean的过程。文章深入探讨了Singleton和Prototype的实例化策略,以及如何处理循环依赖和初始化方法。通过对源码的解读,读者可以更深入理解Spring IoC的工作原理。

前面分析了finishBeanFactoryInitialization();留一下了doGetBean()这个方法,由于这个方法是Spring IOC的实例化真正工作的方法,所以特地拿出来单独来说。
doGetBean()方法太长,下面截图按照顺序剪下来的话不多说,翻源码
这里写图片描述
首先第一行就是根据传进来的name,来确定它的原始名称或者说将name的别名给它解析成规范的名字(beanName):如果name 以”&”开头,则去掉”&”

protected String transformedBeanName(String name) {
        return canonicalName(BeanFactoryUtils.transformedBeanName(name));
    }
public static String transformedBeanName(String name) {
        Assert.notNull(name, "'name' must not be null");
        String beanName = name;
        ////BeanFactory.FACTORY_BEAN_PREFIX ="&"
        while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
            beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
        }
        return beanName;
    }
    public String canonicalName(String name) {
        String canonicalName = name;
        // Handle aliasing...
        String resolvedName;
        do {
            resolvedName = this.aliasMap.get(canonicalName);
            if (resolvedName != null) {
                canonicalName = resolvedName;
            }
        }
        while (resolvedName != null);
        return canonicalName;
    }

再看getSingleton(beanName);首先从缓存中根据beanName去取,如果取到,则加载这个bean。Spring用DefaultSingletonBeanRegistry缓存本地来保存创建过的bean instance。使用singletonObjects 来实现SingleTon Bean instance的缓存

/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

然后进入getObjectForBeanInstance();得到bean。其源码如下图
这里写图片描述
如果通过上面getSingleton得到的实例是factory bean,则去创建一个factory bean instance。通过之前的getMergedLocalBeanDefintion得到一个合并后的RootBeanDefinition。
继续往下看源码
这里写图片描述
如果存在该父工厂,并且该beanDefinition不存在。则下面 originalBeanName(name)就是把之前beanName去掉的“&”再给它加上,然后用父工厂去getBean();循环重复调用doGetBean步骤,然后形成了递归处理。(注:个人理解是参照了 JVM中class的加载双亲委托模式就是class先交给 父类的类加载器去加载,如果在父类中没有找到该class ,则一级一级的向子类加载器传递来加载。有不同也有类似的点)。
否则则进入下面的步骤: 将当前beanName标记为已经创建或者正在创建。
这里写图片描述
这儿又看到getMergedLocalBeanDefinition();这个方法了。还是得到一个合并后的RootBeanDefinition mbd
检查 mbd 是否是抽象的,如果是报出异常。然后 开始处理Bean的依赖关系。
首先 mbd.getDependsOn();dependsOn表示与当前bean有依赖关系的,这段依赖关系是在bean的注册 阶段就是ObtainBeanFactory();方法里面先行生成的;然后循环遍历处理每个有依赖关系isDependent()。

这里写图片描述
上面这个检查依赖关系的方法中分为两段第一段是检查当前已缓存的dependentBeanMap(Map between dependent bean names: bean name –> Set of dependent bean names)中是否有存在循环依赖。第二段则是如果当前beanName没有存在循环依赖。则根据从dependentBeanMap得到的依赖Bean,检查是否与当前被依赖的Bean有循环依赖关系。(从beanName得到所有的依赖关系,然后检查每个依赖dep是否反向依赖beanName,因为要实例化beanName,先实例化它的依赖Bean dep。避免有循环依赖的关系)
eg:
    判断a —>b是否有循环依赖。如果根据a得到的Set A如果有b,则表示a有    循环依赖b。如果前面不存在循环依赖,然后就继续检查Set A中的每个bean是否有循环依赖b。如果存在,则表示a与b 之前存在循环依赖。

如果当前beanName与dependsOn不存在循环依赖关系,接着把当前的依赖关系缓存到dependentBeanMap中。然后先去getBean(dep)这个被依赖的dep。
当处理完所有的依赖Bean后, 就要实例化自己了。
这里写图片描述
这里写图片描述
这里写图片描述
上面的源码就是如果bean是singleton和prototype分别进行不同的处理去实例化()这个bean,然后对实例化的bean进行类型检查。
所以接下来就详细分析下createBean()这个方法。

    //---------------------------------------------------------------------
    // Implementation of relevant AbstractBeanFactory template methods
    //---------------------------------------------------------------------

    /**
     * Central method of this class: creates a bean instance,
     * populates the bean instance, applies post-processors, etc.
     * @see #doCreateBean
     */
    @Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, 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.
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        // Prepare method overrides.
        try {
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            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);
        }

        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) {
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }

上面代码中先做了根据class属性或者className 属性来解析Bean,然后对重写方法的进行校验和标记。如果有代理就直接返回代理 ,否则就进行常规的doCreateBean(),又看到doXXX了这种命名,进行实际的处理工作。个人觉得可以加到自己的命名规范中^_^;
这里写图片描述
这里写图片描述
这里写图片描述
这个方法很长,分开来看。

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
        Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
        mbd.resolvedTargetType = beanType;

factoryBeanInstanceCache这个集合呢是 缓存未实例化尚未完成的bean。这里先清除缓存,然后根据RootBeanDefinition生成一个BeanWrapper(用来分析和操作 JavaBean的)。createBeanInstance这个方法的说明就是采用Factory(工厂方法),自动装配,或者简单的实例化策略来创建某个bean的实例。

        // Allow post-processors to modify the merged bean definition.
        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;
            }
        }

前面注册的postProcessors在这里用到了,用于修改BeanDefintion的定义属性。例如AutowiredAnnotationBeanPostProcessor用来修改autoWired的属性。

// Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        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, new ObjectFactory() {
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }

这里检查当前bean是否满足提前曝光或者缓存(eagerly cache)原则:是否有循环引用,是否支持循环引用(默认是支持),必须是单例。提前曝光的是为了避免在循环引用的时候引发死循环,或者因为初始化复杂bean的时候引发性能问题。

// Initialize the bean instance.
        Object exposedObject = bean;
        try {
            populateBean(beanName, mbd, instanceWrapper);
            if (exposedObject != null) {
                exposedObject = initializeBean(beanName, exposedObject, mbd);
            }
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }

这里是初始化上面创建的bean 。populateBean()完成属性注入,接着就是initializeBean();bean配置中有一个用户的init-method的方法。而initializeBean()这个方法就是进入init-method指定的方法来调用完成用户设置的初始化方法(Spring中已经执行过内部的初始化方法,这是用户层面的初始化)。

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 new BeanCurrentlyInCreationException(beanName,
                                "Bean with name '" + beanName + "' has been injected into other beans [" +
                                StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                "] in its raw version as part of a circular reference, but has eventually been " +
                                "wrapped. This means that said other beans do not use the final version of the " +
                                "bean. This is often the result of over-eager type matching - consider using " +
                                "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

这里是处理之前提前曝光的bean,如果之前该bean被提前曝光了,那就从已经完成实例化的bean集合中得到真实对象的引用,如果新的bean对象和之前的放入单例池中的对象是同一实例,也就是经过后置处理器等操作的都是同一实例bean,则把最新bean指向真实的对象应用。 2.如果已经改变了这个单例bean,则把单例池中的依赖关系解除掉,即从map中清除依赖。这段话来源于这位大牛的博客,我见解有限,引用了他的。

// Register bean as disposable.
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;

这段则是注册销毁方法。然后返回已经完成实例化的Bean。

===================================
这样Spring IOC的过程基本就走了一遍了。作为新手的我又有了一些深的认识

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值