Spring的Ioc容器的实例化过程详解

   依然还是针对Spring面试题的内容,这次我想记录下Spring容器是如何进行bean的加载以及整个容器初始化的过程理解,都是个人看书后的理解,如有不正确的地方,欢迎指正!

   spring 的Ioc容器在通常意义上理解可以分为两类:BeanFactory 和 ApplicationContext;BeanFactory是Spring容器最初级的单位,而ApplicationContext是实现BeanFactory接口的一个针对web开发而产生的一个拥有更多spring定制功能的容器,如国际化、AOP;对于spring容器在开发中所起的作用就是将ConfigurationMetaData(配置信息,就是我们常用的Xml配置)中所有的信息包装成一个轻量化容器的过程;而这个过程我们可以简单划分为两部:1、容器的启动;2、Bean对象的实例化;

    1、容器的启动包含:将所有xml配置中的<bean>标签元素当然也包含其他标签如<import>通过BeanDefinition类(叫做bean定义信息对象)进行封装,生成对应的BeanDefinition实例对象,然后调用BeanDefinitionRegistry的register方法将BeanDefinition加入registry容器中;

     2、容器中bean的实例化:当所有beanDefinition对象都已经准备好之后,spring框架会在容器初始化时就调用getBean——》doGetBean——》createBean——》doCreateBean这个流程将所有的bean对象进行初始化过程,所有的bean对象最后存储的容器是DefaultListableBeanFactory;

概念:beanFactoryPostprocessor(容器启动阶段):BeanDefinition对象的后置处理器,在beanDefinition初始化之前,我们可以通过实现这个接口来修改对应的beanDefinition,也就是修改bean的初始定义信息;而且spring框架也为我们提供了一些beanFactoryPostprocessor的实现类,如PropertyPlaceholderConfigurer(属性占位符):在xml配置文件中我们可以把对数据库连接的动态配置抽离到properties文件中,方便后期对数据库的管理:${}美元符号这个属性占位符就可以动态加载propertis文件中有关数据库地址、用户、密码;

beanPostProcessor(bean的实例化阶段):bean对象的后置处理,在bean真正初始化之前,我们可以通过实现这个接口对bean的有关属性,或者方法进行修改,在spring中有AOP就是通过beanPostProcessor在bean创建之后创建bean的代理对象;

 对于spring容器启动到bean初始化整个过程,spring都统一将这个过程放到了AbstractApplicationContext.refresh()这个方法中,读懂这个方法的核心步骤,也就理解了spring容器是如何启动并加载bean对象的;源码如下

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            /**
             * 做容器刷新前的准备工作
             * 1、设置容器的启动时间
             * 2、设置活跃状态为true
             * 3、设置关闭状态为false
             * 4、获取Environment对象,并加载当前系统的属性值到Environment对象中
             * 5、准备监听器和事件的集合对象,默认为空的集合
             */

            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            // 创建容器对象:DefaultListableBeanFactory
            // 加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinition
            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.
                // 子类覆盖方法做额外的处理,此处我们自己一般不做任何扩展工作,但是可以查看web中的代码,是有具体实现的
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                // 调用各种beanFactorypostProcessor进行beanDefinition的增强处理
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                // 注册beanPostprocessor,这里只是注册功能,真正调用的是getBean方法(核心四步:getBean——>doGetBean——>createBean——>doCreateBean)
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                // 为上下文初始化message源,即不同语言的消息体,国际化处理,在springmvc的时候通过国际化的代码重点讲
                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.
                // 在所有注册的bean中查找listener bean,注册到消息广播器中
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                // 初始化剩下的单实例(非懒加载的)
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                // 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
                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资源占用,在异常处理中,销毁已经在前面过程中生成的单件bean
                destroyBeans();

                // Reset 'active' flag.
                // 重置active标志
                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();
            }
        }
    }

 

 以上有关spring容器的内容参考了《Spring揭秘》——作者:王福强 ;有兴趣的同学可以把那本书作为spring框架理解的核心书籍,个人所知道的spring核心功能本书都有提及;是加强个人基础功的好书

 
posted @ 2021-11-27 18:51  mudy  阅读(392)  评论(0)    收藏  举报