资讯专栏INFORMATION COLUMN

Spring专题之Bean初始化源码分析(1)

harryhappy / 1494人阅读

摘要:初始化我们知道容器初始化后会对容器中非懒加载的,单例的以及非抽象的定义进行的初始化操作,所以我们分析源码的入口也就是在容器初始化的入口,分析容器初始化后在什么地方开始第一次的初始化。

前言

Spring IOC容器在初始化之后会对容器中非懒加载的,单例的以及非抽象的bean定义进行bean的初始化操作,同时会也涉及到Bean的后置处理器以及DI(依赖注入)等行为。对于Bean的初始化,Spring是通过第一次调用getBean方法向容器获取bean实例时进行的。下面的源码分析也是基于getBean()作为入口一步步去了解Spring是如何初始化单例Bean的。

Bean初始化

我们知道Spring IOC容器初始化后会对容器中非懒加载的,单例的以及非抽象的bean定义进行bean的初始化操作,所以我们分析源码的入口也就是在容器初始化的入口,分析容器初始化后Spring在什么地方开始第一次的Bean初始化。

在之前的一篇博文Spring专题之IOC源码分析中有分析到Spring IOC容器初始化的过程,过程源码如下:

    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            //调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            //告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从
            //子类的refreshBeanFactory()方法启动
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            //为BeanFactory配置容器特性,例如类加载器、事件处理器等
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                //为容器的某些子类指定特殊的BeanPost事件处理器
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                //调用所有注册的BeanFactoryPostProcessor的Bean
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                //为BeanFactory注册BeanPost事件处理器.
                //BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                //初始化信息源,和国际化相关.
                initMessageSource();

                // Initialize event multicaster for this context.
                //初始化容器事件传播器.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                //调用子类的某些特殊Bean初始化方法
                onRefresh();

                // Check for listener beans and register them.
                //为事件传播器注册事件监听器.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                //初始化所有剩余的单例Bean
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                //初始化容器的生命周期事件处理器,并发布容器的生命周期事件
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                //销毁已创建的Bean
                destroyBeans();

                // Reset "active" flag.
                //取消refresh操作,重置容器的同步标识.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring"s core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

上述源码可以观察看在IOC容器被初始化后进行了很多其他的操作,但这些现在我们暂时不关心,我们需要关注的只有finishBeanFactoryInitialization这个方法,这个方法的作用就是初始化所有剩余的单例Bean,所以这也是我们以下分析源码的入口。

finishBeanFactoryInitialization方法源码如下:

    //对配置了lazy-init属性的Bean进行预实例化处init属性的Bean进行预实例化处理理
    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        ....

        // Instantiate all remaining (non-lazy-init) singletons.
        //对配置了lazy-init属性的单态模式Bean进行预实例化处理
        beanFactory.preInstantiateSingletons();
    }

这个方法前面一些处理暂时不看,可以知道最后调用了ConfigurableListableBeanFactory的preInstantiateSingletons方法,也就是对配置了lazy-init属性的单态模式Bean进行预实例化处理。
下面进入preInstantiateSingletons方法分析,源码如下:

    //对配置lazy-init属性单态Bean的预实例化
    public void preInstantiateSingletons() throws BeansException {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Pre-instantiating singletons in " + this);
        }

        List beanNames = new ArrayList<>(this.beanDefinitionNames);

        for (String beanName : beanNames) {
            //获取指定名称的Bean定义
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            //Bean不是抽象的,是单态模式的,且lazy-init属性配置为false
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                //如果指定名称的bean是创建容器的Bean
                if (isFactoryBean(beanName)) {
                    //FACTORY_BEAN_PREFIX=”&”,当Bean名称前面加”&”符号
                    //时,获取的是产生容器对象本身,而不是容器产生的Bean.
                    //调用getBean方法,触发容器对Bean实例化和依赖注入过程
                    final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
                    //标识是否需要预实例化
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        //一个匿名内部类
                        isEagerInit = AccessController.doPrivileged((PrivilegedAction) () ->
                                ((SmartFactoryBean) factory).isEagerInit(),
                                getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                ((SmartFactoryBean) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        //调用getBean方法,触发容器对Bean实例化和依赖注入过程
                        getBean(beanName);
                    }
                }
                else {
                    //调用getBean方法,触发容器对Bean实例化和依赖注入过程
                    getBean(beanName);
                }
            }
        }

        //触发bean初始化后的回调
        ...
    }

通过源码解析,我们可以看到这里对于不是抽象的,是单态模式的,且lazy-init属性配置为false的Bean定义进行初始化,而初始化过程正是调用了getBean方法。下面我们进入getBean方法观察Spring对bean的初始化过程。getBean方法及相关调用源码如下:

    //获取IOC容器中指定名称的Bean
    public Object getBean(String name) throws BeansException {
        //doGetBean才是真正向IoC容器获取被管理Bean的过程
        return doGetBean(name, null, null, false);
    }
    //真正实现向IOC容器获取Bean的功能,也是触发依赖注入功能的地方
    protected  T doGetBean(final String name, @Nullable final Class requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        //根据指定的名称获取被管理Bean的名称,剥离指定名称中对容器的相关依赖,如果指定的是别名,将别名转换为规范的Bean名称
        final String beanName = transformedBeanName(name);
        Object bean;

        //先从缓存中取是否已经有被创建过的单态类型的Bean,对于单例模式的Bean整个IOC容器中只创建一次,不需要重复创建
        Object sharedInstance = getSingleton(beanName);
        //IOC容器创建单例模式Bean实例对象
        if (sharedInstance != null && args == null) {
            if (logger.isDebugEnabled()) {
                //如果指定名称的Bean在容器中已有单例模式的Bean被创建
                //直接返回已经创建的Bean
                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的实例对象,主要是完成FactoryBean的相关处理。注意:BeanFactory是管理容器中Bean的工厂,而FactoryBean是创建创建对象的工厂Bean,两者之间有区别
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
            //缓存没有正在创建的单例模式Bean,缓存中已经有已经创建的原型模式Bean,但是由于循环引用的问题导致实例化对象失败
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            //对IOC容器中是否存在指定名称的BeanDefinition进行检查,首先检查是否能在当前的BeanFactory中获取的所需要的Bean,如果不能则委托当前容器的父级容器去查找,如果还是找不到则沿着容器的继承体系向父级容器查找
            BeanFactory parentBeanFactory = getParentBeanFactory();
            //当前容器的父级容器存在,且当前容器中不存在指定名称的Bean
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                //解析指定Bean名称的原始名称
                String nameToLookup = originalBeanName(name);
                if (parentBeanFactory instanceof AbstractBeanFactory) {
                    return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                            nameToLookup, requiredType, args, typeCheckOnly);
                }
                else if (args != null) {
                    //委派父级容器根据指定名称和显式的参数查找
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else {
                    //委派父级容器根据指定名称和类型查找
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }

            //创建的Bean是否需要进行类型验证,一般不需要
            if (!typeCheckOnly) {
                //向容器标记指定的Bean已经被创建
                markBeanAsCreated(beanName);
            }

            try {
                //根据指定Bean名称获取其父级的Bean定义
                //主要解决Bean继承时子类合并父类公共属性问题
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);
                //获取当前Bean所有依赖Bean的名称
                String[] dependsOn = mbd.getDependsOn();
                //如果当前Bean有依赖Bean
                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 + """);
                        }
                        //递归调用getBean方法,获取当前Bean的依赖Bean
                        registerDependentBean(dep, beanName);
                        //把被依赖Bean注册给当前依赖的Bean
                        getBean(dep);
                    }
                }
                //创建单例模式Bean的实例对象
                if (mbd.isSingleton()) {
                    //这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            //创建一个指定Bean实例对象,如果有父级继承,则合并子类和父类的定义
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            //显式地从容器单例模式Bean缓存中清除实例对象
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    //获取给定Bean的实例对象
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }

                //IOC容器创建原型模式Bean实例对象
                else if (mbd.isPrototype()) {
                    //原型模式(Prototype)是每次都会创建一个新的对象
                    Object prototypeInstance = null;
                    try {
                        //回调beforePrototypeCreation方法,默认的功能是注册当前创建的原型对象
                        beforePrototypeCreation(beanName);
                        //创建指定Bean对象实例
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        //回调afterPrototypeCreation方法,默认的功能告诉IOC容器指定Bean的原型对象不再创建
                        afterPrototypeCreation(beanName);
                    }
                    //获取给定Bean的实例对象
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }

                //要创建的Bean既不是单例模式,也不是原型模式,则根据Bean定义资源中配置的生命周期范围,选择实例化Bean的合适方法,这种在Web应用程序中,比较常用,如:request、session、application等生命周期
                else {
                    String scopeName = mbd.getScope();
                    final Scope scope = this.scopes.get(scopeName);
                    //Bean定义资源中没有配置生命周期范围,则Bean定义不合法
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope name "" + scopeName + """);
                    }
                    try {
                        //这里又使用了一个匿名内部类,获取一个指定生命周期范围的实例
                        Object scopedInstance = scope.get(beanName, () -> {
                            beforePrototypeCreation(beanName);
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            finally {
                                afterPrototypeCreation(beanName);
                            }
                        });
                        //获取给定Bean的实例对象
                        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    }
                    catch (IllegalStateException ex) {
                        ...
                    }
                }
            }
            catch (BeansException ex) {
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }

        //对创建的Bean实例对象进行类型检查
        if (requiredType != null && !requiredType.isInstance(bean)) {
            try {
                T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
                if (convertedBean == null) {
                    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                }
                return convertedBean;
            }
            catch (TypeMismatchException ex) {
                ...
            }
        }
        return (T) bean;
    }

这里通过上述源码的分析,总结以下Spring初始化bean的过程,首先Spring会去缓存中搜索是否已存在bean实例,如果存在则直接取出返回,不存在就判断是否存在父容器,存在则调用父容器的getBean方法进行初始化,否则通过判断bean定义是否是单例bean,是否是原型bena进行相关的初始化操作,可以知道最后都是调用了createBean方法去创建bean的。

至此,通过上述的源码分析,我们对Spring在IOC初始化后对bean的初始化过程有了大致的了解,下篇博客会继续这篇通过源码分析Spring初始化的具体过程。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/77002.html

相关文章

  • Spring专题Bean始化源码分析(2)

    摘要:前言这篇是专题初始化的第二篇,主要对初始化具体过程的源码分析。上篇博客专题之初始化源码分析中我们对如何开始初始化以及初始化的总体过程有了大致的了解,接下来就继续上篇博客的结尾处开始来分析初始化的具体过程。 前言 这篇是Spring专题Bean初始化的第二篇,主要对bean初始化具体过程的源码分析。上篇博客Spring专题之Bean初始化源码分析(1)中我们对Spring如何开始初始化b...

    Pikachu 评论0 收藏0
  • Spring专题IOC源码分析

    摘要:前言以下源码基于版本解析。实现源码分析对于的实现,总结来说就是定位加载和注册。定位就是需要定位配置文件的位置,加载就是将配置文件加载进内存注册就是通过解析配置文件注册。下面我们从其中的一种使用的方式一步一步的分析的实现源码。 前言 以下源码基于Spring 5.0.2版本解析。 什么是IOC容器? 容器,顾名思义可以用来容纳一切事物。我们平常所说的Spring IOC容器就是一个可以容...

    不知名网友 评论0 收藏0
  • Spring注解专题系类(二)

    摘要:的在单例被破坏时由进行方法调用。定义并实现这两个接口容器创建完成注解是的缩写,意思是规范提案。在创建完成并且属性赋值完成来执行初始化方法在容器销毁之前回调通知支持自动装配,类似。 Spring注解应用篇--IOC容器Bean生命周期 这是Spring注解专题系类文章,本系类文章适合Spring入门者或者原理入门者,小编会在本系类文章下进行企业级应用实战讲解以及spring源码跟进。本文...

    Alex 评论0 收藏0
  • 慕课网_《Spring入门篇》学习总结

    摘要:入门篇学习总结时间年月日星期三说明本文部分内容均来自慕课网。主要的功能是日志记录,性能统计,安全控制,事务处理,异常处理等等。 《Spring入门篇》学习总结 时间:2017年1月18日星期三说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学示例源码:https://github.com/zccodere/s...个人学习源码:https://git...

    Ververica 评论0 收藏0

发表评论

0条评论

harryhappy

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<