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实例。

  • 相关阅读:
    Nodejs下载和第一个Nodejs示例
    永久关闭Win10工具栏的TaskbarSearch控件
    对称加密,非对称加密,散列算法,签名算法
    【转】TTL和RS232之间的详细对比
    zlg核心板linux系统中查看系统内存等使用信息
    Power BI后台自动刷新数据报错 The operation was throttled by Power BI Premium because there were too many datasets being processed concurrently.
    剪切板和上传文件内容获取
    CSS, LESS, SCSS, SASS总结
    文字程序
    electron 打包“ERR_ELECTRON_BUILDER_CANNOT_EXECUTE”
  • 原文地址:https://www.cnblogs.com/grj001/p/12223594.html
Copyright © 2011-2022 走看看