zoukankan      html  css  js  c++  java
  • Spring加载Bean的流程(源码分析)

    Spring加载Bean的流程(源码分析)

    2018-08-06 10:23:47 食鱼酱 阅读数 204 文章标签: SpringBean加载Spring源码Spring Bean加载流程 更多

    版本

    4.3.10

    入口

    public class Application {
    
        public static void main(String[] args) {
    
            ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
            Person person = context.getBean("person", Person.class);
            System.out.println(person.toString());
        }
    }

    对上面的getBean方法进行跟踪,最终到达AbstractBeanFactory类下面的doGetBean()方法 

     

    Bean加载源码分析

    public abstract class AbstractBeanFactory 
        extends FactoryBeanRegistrySupport 
        implements ConfigurableBeanFactory {
        //以下三个方法是重写父类的getBean方法
        @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);
        }
    
        //这个方法是bean加载的关键
        protected <T> T doGetBean(
                final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
                throws BeansException {
            /*
            1、转换beanName(别名转换)  
    
            平时开发中传入的参数name可能只是别名,也可能是FactoryBean,所以需要进行解析转换:
            (1)消除修饰符,比如name="&test",会去除&使name="test";
            (2)解决spring中alias标签的别名问题
            */      
            final String beanName = transformedBeanName(name);
            Object bean;
    
            //2、尝试从缓存中加载实例,如果获取不到就从singletonFactories中加载
            Object sharedInstance = getSingleton(beanName);
            //如果缓存中存在对应的bean
            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 + "'");
                    }
                }
                //从缓存中获取的bean是原始状态的bean,需要在这里对bean进行bean实例化
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
            }
    
            else {
                // 如果缓存中没有对应bean
                //4、循环依赖检查
                if (isPrototypeCurrentlyInCreation(beanName)) {
                    throw new BeanCurrentlyInCreationException(beanName);
                }
    
                // 5、如果缓存中没有数据,就会转到父类工厂去加载
                //获取父工厂
                BeanFactory parentBeanFactory = getParentBeanFactory();
                /*
                    !containsBeanDefinition(beanName)就是检测如果当前加载的xml配置文件中不包含beanName所对应的
                    配置,就只能到parentBeanFacotory去尝试加载bean。
                */
                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);
                }
    
                //6、存储XML配置文件的GernericBeanDefinition转换成RootBeanDefinition
                /*
                    XML配置文件中读取到的bean信息是存储在GernericBeanDefinition中的,但Bean的后续处理是针
                    对于RootBeanDefinition的,所以需要转换后才能进行后续操作。
                */
                try {
                    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                    checkMergedBeanDefinition(mbd, beanName, args);
    
                    // Guarantee initialization of beans that the current bean depends on.
                    //7、初始化依赖的bean
                    //bean中可能依赖了其他bean属性,在初始化bean之前会先初始化这个bean所依赖的bean属性。
                    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);
                        }
                    }
    
                    //8、创建bean
                    //下面这一大段是Spring容器根据不同scope创建bean实例。
                    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;
        }
    }

    总结

    1、转换beanName(别名转换)

    要知道平时开发中传入的参数name可能只是别名,也可能是FactoryBean,所以需要进行解析转换,一般会进行以下解析:

    (1)消除修饰符,比如name=”&test”,会去除&使name=”test”;

    (2)解决spring中alias标签的别名问题

    2、尝试从缓存中加载实例

    实例在Spring的同一个容器中只会被创建一次,后面再想获取该bean时,就会尝试从缓存中获取;如果获取不到的话再从singletonFactories中加载,再存入到缓存中。

    3、实例化bean(构建实例)

    缓存中记录的bean一般只是最原始的bean状态,这时就需要对bean进行实例化。如果得到的是bean的原始状态,但又要对bean进行处理,这时真正需要的是工厂bean中定义的factory-method方法中返回的bean,上面源码中的getObjectForBeanInstance就是来完成这个工作的。

    4、循环依赖检查

    5、检测parentBeanFactory

    从源码可以看出如果缓存中没有数据会转到父类工厂去加载,源码中的!containsBeanDefinition(beanName)就是检测如果当前加载的xml配置文件中不包含beanName所对应的配置,就只能到parentBeanFacotory去尝试加载bean。

    6、存储XML配置文件的GernericBeanDefinition转换成RootBeanDefinition;

    XML配置文件中读取到的bean信息是存储在GernericBeanDefinition中的,但Bean的后续处理是针对于RootBeanDefinition的,所以需要转换后才能进行后续操作。

    7、初始化依赖的bean

    这里应该比较好理解,就是bean中可能依赖了其他bean属性,在初始化bean之前会先初始化这个bean所依赖的bean属性。

    8、创建bean

    Spring容器根据不同scope创建bean实例。

  • 相关阅读:
    python txt文件数据转excel
    数字的可视化:python画图之散点图sactter函数详解
    Python使用matplotlib模块绘制多条折线图、散点图
    python 读取文件时报错UnicodeDecodeError: 'gbk' codec can't decode byte 0x80 in position 205: illegal multibyte sequence
    Python Requests post并将得到结果转换为json
    Python按行读取文件、写文件
    重装系统后,指纹识别无法使用
    MySQL的简单使用和JDBC示例
    resin后台输出中文乱码的解决办法!
    MySQL时间增加、字符串拼接
  • 原文地址:https://www.cnblogs.com/grj001/p/12223594.html
Copyright © 2011-2022 走看看