spring源码:Spring IoC 容器初始化过程

自我感觉spring在面试当中很常见,仔细整理了一下:

1 BeanDefinition的Resource定位 
2 BeanDefinition的载入 
3 向IoC容器注册BeanDefinition

Spring IoC 容器初始化的关键环节就在 AbstractApplicationContext的refresh() ⽅法中

1.主流程

@Override

public void refresh() throws BeansException, IllegalStateException {

    synchronized (this.startupShutdownMonitor) {

        // 第⼀步:刷新前的预处理

        prepareRefresh();

       /*

        第⼆步:

        获取BeanFactory;默认实现是DefaultListableBeanFactory

        加载BeanDefinition 并注册到 BeanDefitionRegistry

        */ ConfigurableListableBeanFactory beanFactory =

        obtainFreshBeanFactory();

        // 第三步:BeanFactory的预准备⼯作(BeanFactory进⾏⼀些设置,⽐如context的类加载器等)
        prepareBeanFactory(beanFactory);
        try {
            // 第四步:BeanFactory准备⼯作完成后进⾏的后置处理⼯作
            postProcessBeanFactory(beanFactory);
            // 第五步:实例化并调⽤实现了BeanFactoryPostProcessor接⼝的Bean
            invokeBeanFactoryPostProcessors(beanFactory);
            // 第六步:注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执⾏
            registerBeanPostProcessors(beanFactory);
            // 第七步:初始化MessageSource组件(做国际化功能;消息绑定,消息解析);
            initMessageSource();

            // 第⼋步:初始化事件派发器
            initApplicationEventMulticaster();

            // 第九步:⼦类重写这个⽅法,在容器刷新的时候可以⾃定义逻辑
            onRefresh();

            // 第⼗步:注册应⽤的监听器。就是注册实现了ApplicationListener接⼝的监听器bean
            registerListeners();

        /*

        第⼗⼀步:
        初始化所有剩下的⾮懒加载的单例bean
        初始化创建⾮懒加载⽅式的单例Bean实例(未设置属性)
                填充属性
                初始化⽅法调⽤(⽐如调⽤afterPropertiesSet⽅法、init-method⽅法)
                调⽤BeanPostProcessor(后置处理器)对实例bean进⾏后置处
        */
            finishBeanFactoryInitialization(beanFactory);
        /*
        第⼗⼆步:
        完成context的刷新。主要是调⽤LifecycleProcessor的onRefresh()⽅法,并且发布事件(ContextRefreshedEvent)
        */
            finishRefresh();
      }
.......
   }
}

2.BeanFactory创建流程

2.1获取BeanFactory子流程

QQ截图20200706120004.png

上面流程中的第二步的方法: obtainFreshBeanFactory()

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    return getBeanFactory();
}

refreshBeanFactory()在AbstractRefreshableApplicationContext类中

protected final void refreshBeanFactory() throws BeansException {
    // 判断是否已有bean factory
    if (hasBeanFactory()) {
        // 销毁beans
        destroyBeans();
        // 关闭bean factory
        closeBeanFactory();
    }
    try {
    // 实例化DefaultListableBeanFactory  划重点:创建了beanFacory:DefaultListableBeanFactory 
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        // 设置序列化id
        beanFactory.setSerializationId(getId());
        // 自定义bean工厂的一些属性(如多个xml中的bean的id相同时是否覆盖,是否允许循环依赖)
        customizeBeanFactory(beanFactory);
        // 加载应用中的BeanDefinitions   划重点:加载所有bean的BeanDefinitions
        loadBeanDefinitions(beanFactory);
        synchronized (this.beanFactoryMonitor) {
            // 赋值当前beanFactory
            this.beanFactory = beanFactory;
        }
    }
    ....
}

QQ截图20200710190950.png

2.2加载解析BeanDefinition以及其注册

上面代码中AbstractRefreshableApplicationContext中的loadBeanDefinitions()方法加载

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
     //给指定的beanFactory创建一个XmlBeanDefinitionReader读取器对象,用于读取解析xml对象
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    
    //给XmlBeanDefinitionReader对象设置一些context上下文中的环境属性
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

     //提供给子类实现,提供一些自定义的初始化策略
    initBeanDefinitionReader(beanDefinitionReader);
    // 真正的去加载BeanDefinition
    loadBeanDefinitions(beanDefinitionReader);
}

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    // 从Resource资源对象加载BeanDefinitions
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
        reader.loadBeanDefinitions(configResources);
    }
    // 从xml配置文件加载BeanDefinition对象
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
              //跳转至XmlBeanDefinitionReader中去加载
        reader.loadBeanDefinitions(configLocations);
    }
}

XmlBeanDefinitionReader类中加载代码

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    ......
    try {
        InputStream inputStream = encodedResource.getResource().getInputStream();
        try {
            // 把xml文件流封装为InputSource对象
            InputSource inputSource = new InputSource(inputStream);
            if (encodedResource.getEncoding() != null) {
                inputSource.setEncoding(encodedResource.getEncoding());
            }
            // do!执行加载逻辑
            return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
        }
    ......

doLoadBeanDefinitions:真正加载的方法:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
        throws BeanDefinitionStoreException {
    try {
        // 读取xml信息,将xml中信息保存到Document对象中
        Document doc = doLoadDocument(inputSource, resource);
        // 解析Document对象,封装成BeanDefinition对象并进行注册
        int count = registerBeanDefinitions(doc, resource);
        if (logger.isDebugEnabled()) {
            logger.debug("Loaded " + count + " bean definitions from " + resource);
        }
        return count;
    }
    ......
}

我们重点观察XmlBeanDefinitionReader类的registerBeanDefinitions方法,期间产生了多次重载调用,我们定位到最后一个

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    // 获取已有BeanDefinition的数量
    int countBefore = getRegistry().getBeanDefinitionCount();
    // 注册BeanDefinition(createReaderContex()首先完成了NamespaceHandlerResolver的初始化。)
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    // 返回新注册的BeanDefinition数量
    return getRegistry().getBeanDefinitionCount() - countBefore;
}

进入registerBeanDefinitions,再进入DefaultBeanDefinitionDocumentReader类中的doRegisterBeanDefinitions()方法

protected void doRegisterBeanDefinitions(Element root) {
    ......
    preProcessXml(root);
    // 解析BeanDefinition
    parseBeanDefinitions(root, this.delegate);
    postProcessXml(root);
    this.delegate = parent;
}

查看parseBeanDefinitions()方法,解析xml中的<bean>等标签

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                if (delegate.isDefaultNamespace(ele)) {
                    // 解析默认标签元素
                    parseDefaultElement(ele, delegate);
                }
                else {
                    // 解析自定义标签元素
                    delegate.parseCustomElement(ele);
        ......
}

查看分类处理方法parseDefaultElement(ele, delegate);

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    // import元素处理
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
        importBeanDefinitionResource(ele);
    }
    // alias元素处理
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
        processAliasRegistration(ele);
    }
    // bean元素处理
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        processBeanDefinition(ele, delegate);
    }
    // 嵌套beans处理
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        // recurse
        doRegisterBeanDefinitions(ele);
    }
}

具体解析注册bean的方法:processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 解析bean元素为BeanDefinition,但是此时使用BeanDefinitionHoler 又包装成了BeanDefinitionHoler对象
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        // 如果有自定义标签,则处理自定义标签
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // Register the final decorated instance.
            // 完成BeanDefinition的注册
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        .....
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

查看BeanDefinitionReaderUtils的registerBeanDefinition()方法,然后一直跟踪registerBeanDefinition方法直到下面这个方法中看到this.beanDefinitionMap.put(beanName, beanDefinition);将他放入beanDefinitionMap(是一个 ConcurrentHashMap),完成注册。

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
        throws BeanDefinitionStoreException {

    ......
    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {
        ......
        // 划重点:将beanDefinition存入map集合
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    ...
}

至此,注册流程结束,我们发现,所谓的注册就是把封装的XML中定义的Bean信息封装为BeanDefinition对象之后放入-个Map中, BeanFactory 是以Map的结构存放这些BeanDefinition的。
BeanDefinition和BeanDefinitionHolder的结构


QQ截图20200710190905.png

QQ截图20200710190950.png

3.Bean创建流程

⼦流程⼊⼝在AbstractApplicationContext#refresh()⽅finishBeanFactoryInitialization(beanFactory) 处
进入方法,还在当前类中:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        beanFactory.setTempClassLoader(null);

        // Allow for caching all bean definition metadata, not expecting further changes.
        beanFactory.freezeConfiguration();

        // 实例化所有立即加载的单例bean
        beanFactory.preInstantiateSingletons();
    }

继续进⼊DefaultListableBeanFactory类的preInstantiateSingletons⽅法

public void preInstantiateSingletons() throws BeansException {
    ......
        synchronized (this.beanDefinitionMap) {
            for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) {
                String beanName = (String) it.next();
                RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
                if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                                      //判断是否是工厂bean
                    if (isFactoryBean(beanName)) {
                        FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
                        if (factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit()) {
                                                //通过getbean获取实例
                            getBean(beanName);
                        }
                    }
                    else {
                                              //通过getbean获取实例
                        getBean(beanName);
                    }
                }
            }
        }
    }

可以看出不管是工厂bean还是普通bean都是通过getBean获取实例
进入getBean(),只是转发调用,最终进入AbstractBeanFactory类的doGetBean

protected Object doGetBean(
            final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
  ......
  String[] dependsOn = mbd.getDependsOn();
    if (dependsOn != null) {
        for (int i = 0; i < dependsOn.length; i++) {
            String dependsOnBean = dependsOn[i];
            getBean(dependsOnBean);
            registerDependentBean(dependsOnBean, beanName);
        }
    }

    //划重点 Create bean instance.创建单例bean
    if (mbd.isSingleton()) {
        sharedInstance = getSingleton(beanName, new ObjectFactory() {
            public Object getObject() throws BeansException {
                try {
                                        //划重点 创建bean
                    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);
    }

}

进⼊到AbstractAutowireCapableBeanFactory类的⽅法,找到以下代码部分


QQ截图20200713115103.png

进⼊doCreateBean⽅法

              if (instanceWrapper == null) {
                        //创建bean实例,但是尚未设置属性
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
        Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

        // Allow post-processors to modify the merged bean definition.
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                mbd.postProcessed = true;
            }
        }
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
                //判断二级缓存
        if (earlySingletonExposure) {
            if (logger.isDebugEnabled()) {
                logger.debug("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, new ObjectFactory() {
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }

        // 重点:给Bean填充属性,调⽤初始化⽅法,应⽤BeanPostProcessor后置处理器
        Object exposedObject = bean;
        try {
                        //bean属性填充
            populateBean(beanName, mbd, instanceWrapper);
                        //掉用初始化方法,应用BeanPostprocessor后置处理器
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
                }
    ......

bean实例化的时候如果存在bean之间互相依赖,使用三级缓存解决非构造单例bean循环依赖问题,具体请看下一篇文章

4. lazy-init 延迟加载机制原理

普通 Bean 的初始化是在容器启动初始化阶段执⾏的,⽽被lazy-init=true修饰的 bean 则是在从容器⾥
第⼀次进⾏context.getBean() 时进⾏触发。Spring 启动的时候会把所有bean信息(包括XML和注解)解
析转化成Spring能够识别的BeanDefinition并存到Hashmap⾥供下⾯的初始化时⽤,然后对每个
BeanDefinition 进⾏处理,如果是懒加载的则在容器初始化阶段不处理,其他的则在容器初始化阶段进
⾏初始化并依赖注⼊

public void preInstantiateSingletons() throws BeansException {
        // 所有beanDefinition集合
        List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
        // 触发所有⾮懒加载单例bean的初始化
        for (String beanName : beanNames) {
            // 获取bean 定义
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            // 判断是否是懒加载单例bean,如果是单例的并且不是懒加载的则在容器创建时初始化
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                // 判断是否是 FactoryBean
                if (isFactoryBean(beanName)) {
                    final FactoryBean<?> factory = (FactoryBean<?>)
                            getBean(FACTORY_BEAN_PREFIX + beanName);
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof
                            SmartFactoryBean) {
                        isEagerInit = AccessController.doPrivileged(new
                       PrivilegedAction<Boolean>() {
                       @Override
                           public Boolean run() {
                                 return ((SmartFactoryBean<?>) factory).isEagerInit();
                             }
                          }, getAccessControlContext());
                   }                                                 
                } else {
                 /*
                  划重点
                 如果是普通bean则进⾏初始化并依赖注⼊,此 getBean(beanName)接下来触发的逻辑
                和懒加载时 context.getBean("beanName") 所触发的逻辑是⼀样的
                 */
                    getBean(beanName);
                }
            }
        }
    }

总结

对于被修饰为lazy-init的bean Spring 容器初始化阶段不会进⾏ init 并且依赖注⼊,当第⼀次
进⾏getBean时候才进⾏初始化并依赖注⼊
对于⾮懒加载的bean,getBean的时候会从缓存⾥头获取,因为容器初始化阶段 Bean 已经
初始化完成并缓存了起来

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351