深入理解Spring框架-启动Bean加载过程

  1. spring web应用启动过程核心流程:

(1)web 容器启动时,首先加载web.xml 文件,并逐一解析web.xml文件内容配置,优先解析到内容上线文加载监听器配置:org.springframework.web.context.ContextLoaderListener, 该配置主要工作是:基于contextClass以及servlet的上下文参数context-param指定的spring配置文件创建一个web 应用上下文—初始化root application context 以及通过指定应用上下文的配置文件进行初始化加载。(1)web 容器启动时,首先加载web.xml 文件,并逐一解析web.xml文件内容配置,优先解析到内容上线文加载监听器配置:org.springframework.web.context.ContextLoaderListener, 该配置主要工作是:基于contextClass以及servlet的上下文参数context-param指定的spring配置文件创建一个web 应用上下文—初始化root application context 以及通过指定应用上下文的配置文件进行初始化加载。

(2)调用ContextLoaderListener:: contextInitialized 方法对根应用上下文进行初始化. contextInitialized 方法中调用了一个ContextLoaderListener父类ContextLoader上下文加载器方法
initWebApplicationContext(ServletContext);

(3) ContextLoader::initWebApplicationContext(ServletContext) 的职责工作:创建一个可配置的web应用上下文(将上下文存储在本地实例变量中,以确保它在servletcontext关闭时可用),并设置器父上下文,然后调用ContextLoader::configureAndRefreshWebApplicationContext;

(4) ContextLoader::configureAndRefreshWebApplicationContext() 主要工作:首先获取到spring上下文配置文件路径-configLocationParam=classpath:spring/spring-config.xml(在web.xml > listener >context-param 指定),设置自定义的上下文初始化器(ApplicationContextInitializer),并进行初始化;然后调用ConfigurableWebApplicationContext的核心方法:refresh();

深入理解Spring框架-启动Bean加载过程_第1张图片

  1. 上下文刷新refresh工作流程如下

     	代码流程:{
     		prepareRefresh();
     		
     		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
     		
     		prepareBeanFactory(beanFactory);
     		
     		postProcessBeanFactory(beanFactory);
    
     		invokeBeanFactoryPostProcessors(beanFactory);
     		
     		registerBeanPostProcessors(beanFactory);
    
     		initMessageSource();
    
     		initApplicationEventMulticaster();
     		
     		onRefresh();
    
     		registerListeners();
    
     		finishBeanFactoryInitialization(beanFactory);
     		
     		finishRefresh();
     	}
    

    step1:prepareRefresh 上下文刷新前准备工作:设置ConfigurableWebApplicationContext上下文实例对象wac的启动日期和活动标志、加载属性源配置以及判断必填项是否都完整。

    step2: obtainFreshBeanFactory 通知子类刷新内部bean工厂工作:创建BeanFactory,如果已有就销毁,没有就创建;核心工作就是解析XML 以及扫描注解 将扫描到的Bean配置属性封装到BeanDefinition 对象中,并对它beanName(key) , BeanDefinition(v) 保存到一个Map 中。

    step3:prepareBeanFactory 对bean factory进行一些上下文标准化配置:设置factory的类加载器、bean 表达式解释器、资源编辑注册器、应用上下文自动注入后处理器、配置在自动装配(通过beans标签default-autowire属性来依赖注入)的时候的需要忽略的类(如ApplicationContextAwareProcessor、EnvironmentAware、ResourceLoaderAware、 EmbeddedValueResolverAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware)、注册可以自动装配的 Bean(如BeanFactory)以及注册默认系统变量配置等。

     [自动装配与@Autowired 的区别:自动装配指通过beans标签default-autowire属性来依赖注入的方式,
     而不是指使用@Autowired注解进行的依赖注入。区别在于,使用default-autowire会自动给所有的类
     都会从容器中查找匹配的依赖并注入,而使用@Autowired注解只会给这些注解的对象从容器查找依赖并注入]
    

    step4: postProcessBeanFactory 修改BeanFactory的后处理器配置:在标准初始化之后修改应用程序上下文的内部bean工厂初始化配置,允许注册特殊BeanPostProcessors->即ServletContextAwareProcessor 后处理器以及设置自动装配忽略接口类(ServletContextAware、ServletConfigAware)以及注册应用上下文的request/session 范围。 这一阶段所有bean定义都已加载,但没有bean将被实例化

    step5:invokeBeanFactoryPostProcessors 工作:通过显示顺序方式调用手动注册的BeanFactory后处理器,先实例化spring框架涉及到的后处理器,在调用。

    (1)先执行 BeanDefinitionRegistryPostProcessor 的方法
    (2)对配置/组件类中声明的嵌套@component类或configuration类者进行自动注册成bean定义,并对这些候选bean定义按照优先级进行排序。
    (3)执行beanFactoryPostProcessors,对配置文件bean进行扫描实例化:如propertyConfigurer。

    step6:registerBeanPostProcessors 注册拦截bean创建的bean处理器-实例化:
    (1):通过beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);方法获取beanFactory里继承了BeanPostProcessor接口的name的集合;
    (2):把后置器beans分为PriorityOrdered、Ordered、nonOrdered三大类,前两类是增加了排序条件的后置器;
    (3):前两类后置器执行sortPostProcessors和registerBeanPostProcessors方法,也就是先执行排序方法,后执行注册方法。
    (4):最后一步用到了上面提到的BeanPostProcessor和BeanFactoryPostProcessor的入参不同的AbstractApplicationContext,在addBeanPostProcessor方法里把BeanPostProcessor注册进了AbstractBeanFactory,这也就是为什么BeanFactoryPostProcessor执行了后置接口实现类,而BeanPostProcessor仅仅执行了注册和实例化,而没有执行的原因。

    step7:initMessageSource 初始化消息源:MessageSource接口类用于支持信息的国际化和包含参数的信息的替换。
    ApplicationContext接口继承了MessageSource接口,应用可通过ApplicationContext来调用MessageSource接口方法以实现信息的国际化和替换信息中包含的参数。所有对MessageSource接口的实现都是在AbstractApplicationContext中实现

    step8: initApplicationEventMulticaster 初始化事件广播器:如果上下文中没有定义则使用默认广播器:SimpleApplicationEventMulticaster。

    step9: onRefresh 初始化其他特定的bean,由具体子类实现。

    step10:registerListeners 注册监听事件:在容器中将所有项目里面的ApplicationListener注册进来,大体过程如下:获取所有的事件,并添加到事件派发器中 -> 监听事件进行派发广播。

     for (String listenerBeanName : listenerBeanNames) {
     		getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
     	}
     	...
     getApplicationEventMulticaster().multicastEvent(earlyEvent)
    

    step11: finishBeanFactoryInitialization 初始化所有剩下的单实例 Bean(没有配置赖加载的 lazy!=true)。大体过程如下:

     -> 获取bean的定义信息
     -> 判断bean 是否是抽象的、是单例的、非懒加载的
     -> 是否为 FactoryBean ,是则调用 FactoryBean 的创建方法,否则执行 getBean() 方法
     -> 调用 getBean() 方法 
     -> getBean方法内部再调用 doGetBean() 方法
    

    step12:finishRefresh 完成BeanFactory的初始化创建工作:

     	// 初始化生命周期处理器组件
     	initLifecycleProcessor();
    
     	// 首先将刷新状态传播到生命周期组件中.
     	getLifecycleProcessor().onRefresh();
    
     	// 发布上下文已刷新完毕的事件.
     	publishEvent(new ContextRefreshedEvent(this));
    
     	// Participate in LiveBeansView MBean, if active:
     	LiveBeansView活动beans的查看适配器,构建当前bean的快照 和来自本地{@code ApplicationContext}的依赖关系(带有本地{@code LiveBeansView} bean定义)或所有已注册的ApplicationContexts由{@value #MBEAN_DOMAIN_PROPERTY_NAME}环境属性驱动)
     	LiveBeansView.registerApplicationContext(this);
    
  2. obtainFreshBeanFactory 工作流程
    主要工作解析web项目配置(在web.xml > listener >context-param 指定)的应用application.xml文件的import、bean、resource、profile…等配置项的进行逐一解析。核心工作就是解析XML 或扫描注解,将其属性封装到BeanDefinition 对象中,并对它beanName(key) 、BeanDefinition(v) 保存到一个Map 中,为后面spring加载依赖注入提供了对应的元数据(bean 定义)。

    在obtainFreshBeanFactory方法内部调用了refreshBeanFactory方法,此方法是执行应用上下文的基础bean工厂的实际刷新,首先,若存在一个bean工厂,进行关闭,其次创建一个新bean工厂。

    3.1 refreshBeanFactory 工作流程如下:

    createBeanFactory()
    ->customizeBeanFactory() : 设置BeanFactory定制化信息:允许bean定义重载(allowBeanDefinitionOverriding)、允许循环引用(allowCircularReferences)

    ->loadBeanDefinitions(beanFactory) : 默认执行XmlWebApplicationContext的bean配置加载

    -> loadBeanDefinitions(XmlBeanDefinitionReader render): 遍历所有配置文件

    -> reader.loadBeanDefinitions(“classpath:spring/spring-config.xml”)

    1.getResourceLoader() :获取资源加载器
    2. List< Resource> resources = resourceLoader.getResources(location):通过资源加载器加载资源-支持正则匹配查找资源

    ->loadBeanDefinitions(Resource resource): 遍历所有资源resource

    ->loadBeanDefinitions(EncodedResource resource): Resource 转换成EncodedResource

    -> encodedResource.getResource().getInputStream() :读取文件流

    -> doLoadBeanDefinitions(inputSource)
    -> Document doc = loadDocument(inputSource) :根据xml schema解析成xml文档对象
    -> registerBeanDefinitions(doc)
    -> doRegisterBeanDefinitions(Element root): 核心逻辑 解析xml文档并注册bean定义

3.2 doRegisterBeanDefinitions方法处理过程

    (1) preProcessXml(root);  // xml解析前处理方法:空处理,spring 框架提供子类扩展点
	(2) parseBeanDefinitions(root, this.delegate); // 主要解析步骤,遍历解析root节点子节点
	(3) postProcessXml(root) ;// xml解析后处理方法:空处理,spring 框架提供子类扩展点

parseBeanDefinitions 解析项分为两大类:一是spring默认配置项:import、alias、bean、beans 配置项,二是定制化的配置项:如component-scan、annotation-config、property-placeholder、mbean-export等。

 (1). 解析< bean id="" classs="" />将element属性赋值到对应的AbstractBeanDefinition 定义的对象中
 (2). 将AbstractBeanDefinition继续赋值给一个BeanDefinitionHolder(包含aliases、beanName、
 	  beanDefinition)获取BeanDefinitionHolder对象的beanName和beanDefinition 将其注册到
 	  BeanDefinitionRegistry 对象中(以beanName为key和beanDefinition为值value 保存到Map 中。)
 (2). 遇到import配置项,依照上述步骤进行解析

4. doGetBean方法实例化过程
深入理解Spring框架-启动Bean加载过程_第2张图片
4.1 doGetBean方法处理过程

(1)获取bean所对应clazz的构造函数
(2)构造函数先执行静态字段的初始化,然后按照属性字段声明顺序执行初始化
(3)调用各个MergedBeanDefinitionPostProcessor后处理器的postProcessMergedBeanDefinition
    进行信息合并处理。
(4)在容器中为bean 添加一个单指定的单例工厂
(5)调用各个InstantiationAwareBeanPostProcessor后处理器的postProcessAfterInstantiation
(6)调用autowireByName方法处理通过autowire设置为byName的属性字段: xml 中bean的autowire指定
(7)调用autowireByType方法处理通过autowire设置为byType的属性字段 :xml 中bean的autowire指定
(8)若有实例化感知后处理器InstantiationAwareBeanPostProcessor,则调用postProcessPropertyValues
		进行处理:更新beanFactory的设置
(9)若有bean属性值依赖检查,则进行检查:依赖性检查属性可以是协作对象bean,简单类型或全部
(10)调用applyPropertyValues方法对MutablePropertyValues可变属性-复杂对象进行设值,涉及到属性值
	依赖注入,主要是xml中的bean配置, 例如PropertyPlaceholderConfigurer::propertyConfigurer配置,
	 
   		 
    	
     
     
     
    		
   			
      		  
            	classpath*:production.properties
       	     
    	   
    
	在这一阶段会解析property配置文件。
(11)调用bean初始化之前的后处理器的postProcessBeforeInitialization方法对初始化(@postContruct、@preDestroy标注方法)方法进行处理调用
(12)调用初始化方法afterPropertiesSet():bean是实现了InitializingBean
(13)调用bean初始化之后的后处理器,一般是没有操作,直接返回。

由上面bean实例化过程可以看出:

   Constructor > @PostConstruct > InitializingBean > init-method
   
 (1)如果bean有依赖bean, 则先对依赖bean进行实例化
 (2)初始化方法(如果实现了InitializingBean接口类)在bean属性字段依赖注入完成后执行
 (3)autowireByName 先于autowireByType执行
 (4)若bean存在初始化字段如field=new xxx() 时,调用bean构造方法后进行初始化赋值,
     然后对注解的属性进行依赖注入和注解的方法的执行

以上就是整个spring 的启动Bean加载过程,以上如有误,请指正!

你可能感兴趣的:(深入理解Spring框架-启动Bean加载过程)