美文网首页
Spring-IOC-getBean源码解析

Spring-IOC-getBean源码解析

作者: zhanglbjames | 来源:发表于2017-09-03 20:19 被阅读0次

    以XmlBeanFactory为例

    多个重载的getBean方法

    beans.factory.support.AbstractBeanFactory(XmlBeanFactory 继承自这个类,拥有这个方法)
        //---------------------------------------------------------------------
        // Implementation of BeanFactory interface
        //---------------------------------------------------------------------
        // 提供了getBean的多个重载方法,都是调用doGetBean主方法来实现的
        @Override
        public Object getBean(String name) throws BeansException {
            return doGetBean(name, null, null, false);
        }
    
        @Override
        public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
            return doGetBean(name, requiredType, null, false);
        }
    
        @Override
        public Object getBean(String name, Object... args) throws BeansException {
            return doGetBean(name, null, args, false);
        }
        
    

    doGetBean主方法

        @SuppressWarnings("unchecked")
        protected <T> T doGetBean(
                final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
                throws BeansException {
    
            final String beanName = transformedBeanName(name);
            Object bean;
    
            // Eagerly check singleton cache for manually registered singletons.
            // 1. 
            Object sharedInstance = getSingleton(beanName);
            if (sharedInstance != null && args == null) {
                if (logger.isDebugEnabled()) {
                    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 + "'");
                    }
                }
                // 2.
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
            }
    
            else {
                // Fail if we're already creating this bean instance:
                // We're assumably within a circular reference.
                if (isPrototypeCurrentlyInCreation(beanName)) {
                    throw new BeanCurrentlyInCreationException(beanName);
                }
    
                // Check if bean definition exists in this factory.
                BeanFactory parentBeanFactory = getParentBeanFactory();
                if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                    // Not found -> check parent.
                    String nameToLookup = originalBeanName(name);
                    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);
                    }
                }
    
                if (!typeCheckOnly) {
                    markBeanAsCreated(beanName);
                }
    
                try {
                    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                    checkMergedBeanDefinition(mbd, beanName, args);
    
                    // Guarantee initialization of beans that the current bean depends on.
                    String[] dependsOn = mbd.getDependsOn();
                    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 + "'");
                            }
                            registerDependentBean(dep, beanName);
                            getBean(dep);
                        }
                    }
    
                    // Create bean instance.
                    if (mbd.isSingleton()) {
                        sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                            @Override
                            public Object getObject() throws BeansException {
                                try {
                                    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.
                                    destroySingleton(beanName);
                                    throw ex;
                                }
                            }
                        });
                        bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                    }
    
                    else if (mbd.isPrototype()) {
                        // It's a prototype -> create a new instance.
                        Object prototypeInstance = null;
                        try {
                            beforePrototypeCreation(beanName);
                            prototypeInstance = createBean(beanName, mbd, args);
                        }
                        finally {
                            afterPrototypeCreation(beanName);
                        }
                        bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                    }
    
                    else {
                        String scopeName = mbd.getScope();
                        final Scope scope = this.scopes.get(scopeName);
                        if (scope == null) {
                            throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                        }
                        try {
                            Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                                @Override
                                public Object getObject() throws BeansException {
                                    beforePrototypeCreation(beanName);
                                    try {
                                        return createBean(beanName, mbd, args);
                                    }
                                    finally {
                                        afterPrototypeCreation(beanName);
                                    }
                                }
                            });
                            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.
            if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
                try {
                    return getTypeConverter().convertIfNecessary(bean, requiredType);
                }
                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;
        }
    

    XmlBeanFactory.doGetBean(...)的总流程

    1- 转换对应的beanName

    传入的name参数可能是别名,也可能是FactoryBean,所以还需要进行一系列的解析。

    • 去除FactoryBean的修饰符,也就是如果name = "&aBeanName",那么会首先去除&而使name = "aBeanName"
    • 将别名alias转换为最终指向的beanName,比如别名A执行名称为B的bean,而B没有指向任何其他的bean,即为最终的bean,则返回B;
      但是如果B又指向C,而是C是最终的bean,则返回C

    2- 尝试从缓存中加载原始单例

    Spring-IOC-尝试从缓存中加载单例

    3- 检测是否为FactoryBean并获取Bean以及初始化后处理

    在doGetBean方法中频繁出现getObjectForBeanInstance方法,它主要完成对获取的Bean Instance进行检测是否为FactoryBean,如果是FactoryBean则通过工厂方法获取Bean以及初始化后处理。
    Spring-IOC-FactoryBean检测与获取Bean

    4- 创建单例Bean

    如果缓存中没有单例Bean的缓存,则需要从头开始创建单例Bean,这主要是重载getSingleton的重载方法来实现单例Bean的加载。
    Spring-IOC-SingletonBean的创建过程

    4- 原型模式的依赖检查

    只有单例模式才会尝试解决循环依赖,如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候看,就会产生当A还未创建完的时候因为对于B的创建再次返回创建A,造成循环依赖,也就是情况:isPrototypeCurrentlyInCreation(beanName)判断为true

    5- 检测parentBeanFactory

    如果缓存中没有数据的话直接转到父类工厂上去加载

    parentBeanFactory != null && !containsBeanDefinition(beanName),parentBeanFactory != null
    上面的判断中containsBeanDefinition(beanName)是检测如果当前加载XML配置文件中不包含beanName所对应的配置,就只能到parentBeanFactory去尝试下,然后再递归的调用getBean方法

    6- 将注册的GenericBeanFactory转换为RootBeanDefinition

    因为从XML配置文件中读取到的Bean信息是存储在GernericBeanDefinition中的,但是所有的Bean后续处理都是针对于RootBeanDefinition的,所以这里需要进行一个转换,转换的同时如果父类bean不为空的话,则会一并合并父类的属性

    7- 属性依赖注入

    在bean的初始化过程会用到某些属性,而某些属性很可能是动态配置的,并且配置成依赖于其他的bean,那么这个时候就有必要先加载依赖的bean,所以在Spring的加载顺序中,在初始化某一个bean的时候首先会初始化这个bean所对应的依赖。

    8- 根据不同scope进行bean的创建

    默认的scope为singleton,但是还有些其他的配置注入prototype、request等,Spring会根据不同的配置进行不同的初始化策略。

    9- 类型转换

    到这里bean的获取基本就已经结束了,通常对该方法的调用参数requiredType是为空的,但是可能会存在这样的情况,返回bean其实是个String,但是requiredType却传入的Integer类型,此时本步骤就会起作用了,它的功能是将返回的bean转换为requiredType所指定的类型,当然,String转换为Integer是最简单的一种转换,在Spring中提供了各种各样的转换器,用户也可以自己拓展转换器来满足开发需求。

    相关文章

      网友评论

          本文标题:Spring-IOC-getBean源码解析

          本文链接:https://www.haomeiwen.com/subject/uovjjxtx.html