zoukankan      html  css  js  c++  java
  • spring-boot源码分析之BeanFactory

    前言

    今天原本是打算分析beanFactory的,但由于昨天我们有一部分内容还没有分享完,所以今天就先开个倒车,把做昨天的内容先将清楚,所以今天的内容主要就是对昨天分享内容的的补充。

    当然,昨天我们分享的内容beanDefinitionNames也算是BeanFactory的核心属性,所以也不能说完全没有关系:

    而且从源码中我们可以看出来,beanDefinitionNamesbeanDefinitionMap这些属性的初始化大小,这也算是在学习beanFactory的相关知识吧。

    BeanFactory

    beanDefinitionNames内容补充

    正式开始之前,我们先把昨天遗留的问题解决了。昨天,我们分享了一张beanDefinitionNames初始化的时序图,但是由于有一些内容没有梳理清楚,所以这里先做个补充。

    调用过程各方法作用

    SpringApplication这里就不做过多说明了,我们在前面最开始的时候就已经分析过这个类的run方法,当时也已经介绍过这个类的这些方法,他们的主要作用就是为了初始化容器,在SpringApplication的最后一个refresh方法中,最后会调用AbstractApplicationContext自身的refresh方法,这里的AbstractApplicationContextApplicationContext的抽象实现,它实现了ConfigurableApplicationContext接口(ConfigurableApplicationContext继承了ApplicationContext),我们的AnnotationConfigReactiveWebServerApplicationContext(默认容器)就是继承自它,不过并不是直接继承,它的父类继承了AbstractApplicationContext,关于容器这块的继承关系,我们改天抽个时间,专门分析下。

    大部分继承了AbstractApplicationContext的容器都没有重写refresh方法,就算重写了这个方法,其内部也是调用了父类的refresh方法:

    我们看下refresh的实现源码:

    	public void refresh() throws BeansException, IllegalStateException {
    		synchronized (this.startupShutdownMonitor) {
    			// Prepare this context for refreshing.
    			prepareRefresh();
    
    			// Tell the subclass to refresh the internal bean factory.
    			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    			// Prepare the bean factory for use in this context.
    			prepareBeanFactory(beanFactory);
    
    			try {
    				// Allows post-processing of the bean factory in context subclasses.
    				postProcessBeanFactory(beanFactory);
    
    				// Invoke factory processors registered as beans in the context.
    				invokeBeanFactoryPostProcessors(beanFactory);
    
    				// Register bean processors that intercept bean creation.
    				registerBeanPostProcessors(beanFactory);
    
    				// Initialize message source for this context.
    				initMessageSource();
    
    				// Initialize event multicaster for this context.
    				initApplicationEventMulticaster();
    
    				// Initialize other special beans in specific context subclasses.
    				onRefresh();
    
    				// Check for listener beans and register them.
    				registerListeners();
    
    				// Instantiate all remaining (non-lazy-init) singletons.
    				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.
    				destroyBeans();
    
    				// Reset 'active' flag.
    				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();
    			}
    		}
    	}
    

    refresh方法内部,调用了很多其他方法,其中prepareRefresh的作用是为我们下面的刷新操作做准备,其内部主要是对配置的一些初始化操作:

    obtainFreshBeanFactory方法的作用是刷新beanFactory,主要是对beanFactory进行一些初始化操作,如果beanFactory已经存在,会将已有的beanFactory销毁,然后重新创建,最后将beanFactory返回:

    prepareBeanFactory方法的作用是对BeanFactory进行一些赋值和设置,为容器初始化操作做准备:

    postProcessBeanFactory方法就是我们昨天提到的会进行包扫描的那个方法,但由于basePackagesannotatedClasses都是空,所以其中的scan方法并不会被执行。这个方法实际的作用是,后置处理BeanFactory

    invokeBeanFactoryPostProcessors方法的作用是,实例化并调用所有注册的BeanFactory的后置处理器。我们昨天说的beanDefinitionNamesbeanDefinitionMap就是通过这个方法最终完成初始化的:

    registerBeanPostProcessors方法和它名字一样,它的作用就是注册bean的后置处理器:

    initMessageSource方法是进行消息源初始化的,主要是对web应用消息国际化提供支持的:

    initApplicationEventMulticaster,这个方法是初始化spring boot应用时间广播的,如果不指定的话,默认情况下为我们指定的是SimpleApplicationEventMulticaster

    onRefresh,这个方法是提供给子类初始化其他特殊bean对象的,默认实现为空,子类可根据需要重写:

    registerListeners方法是用来注册事件监听器的:

    finishBeanFactoryInitialization,完成beanFactory初始化,同时在方法内部会实例化剩余的单例类(不包括懒加载部分):

    finishRefresh,完成刷新,主要进行一些清理、刷新、事件推送等操作:

    总结

    经过今天的补充之后,我相信各位小伙伴一定也对spring boot的启动和初始化过程有了更深刻的认识,因为我就是这样的感受。相比于昨天分享完内容的感受,今天我感觉整体来说要更好。一方面感觉spring boot启动和初始化的流程更清晰了,而且由于最近这几天一直在看spring boot的源码,看的多了感觉就没有那么难了,毕竟书读百遍其意自现,代码也是大同小异;另一方面在梳理分析的过程中,让我也能够清晰地看到下一步要分享的内容,明确后面地前进方向,这也算是意外的收获吧。

  • 相关阅读:
    vue开发chrome扩展,数据通过storage对象获取
    Vue手动集成less预编译器
    Google Translate寻找之旅
    Javascript Range对象的学习
    Javascript Promises学习
    SublimeText 建立构建Node js系统
    We're sorry but demo3 doesn't work properly without JavaScript enabled. Please enable it to continue.
    npm安装包出现UNMET DEPENDENCY报错
    (转载)命令行说明中格式 尖括号 中括号的含义
    Linux重启网卡服务Failed to start LSB: Bring up/down networking.
  • 原文地址:https://www.cnblogs.com/caoleiCoding/p/15232227.html
Copyright © 2011-2022 走看看