Spring4.x 笔记(6):Ioc 容器高级-内部工作机制

容器启动

Spring 的容器初始化,如new ClassPathXmlApplicationContext("spring-context.xml"),内部调用 AbstractApplicationContext 的 refresh() 方法。该方法定义了 Spring 容器在加载配置文件后的各项处理过程,即Spring 容器启动是所执行的各项操作

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
		throws BeansException {
    // 父容器
	super(parent);
	// 设置配置文件
	setConfigLocations(configLocations);
	if (refresh) {
	    // 初始化容器
		refresh();
	}
}

refresh() 方法概述

public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// Prepare this context for refreshing.
		prepareRefresh();

        // 初始化 BeanFactory
		// 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);
            
            // 注册Bean 后置处理器
			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);
            
            // 初始化消息源(I18n国际化)
			// Initialize message source for this context.
			initMessageSource();
            
            // 初始化应用上下文事件广播器
			// Initialize event multicaster for this context.
			initApplicationEventMulticaster();
            
            // 初始化其他特殊的 bean ,由子类实现
			// Initialize other special beans in specific context subclasses.
			onRefresh();
            
            // 注册事件监听器
			// Check for listener beans and register them.
			registerListeners();

            // 初始化所有单实例的Bean,使用懒加载模式的 Bean 除外
			// 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();
		}
	}
}

步骤分析

  1. 初始化 BeanFactory。

Spring 将配置文件的信息装入 Bean定义注册表(BeanDefinitionRegistry)中,此时 Bean 还未初始化。根据配置文件,实例化 BeanFactory,在 obtainFreshBeanFactory() 方法中 ,首先调用refreshBeanFactory 方法刷新 BeanFactory,然后调用 getBeanFactory 方法获取 BeanFactory,这两个方法都是由具体的子类实现的。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
	refreshBeanFactory();
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	if (logger.isDebugEnabled()) {
		logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
	}
	return beanFactory;
}
  1. 调用工厂后置处理器。

根据反射机制从 BeanDefinitionRegistry 中找出所有实现了 BeanFactoryPostProcessor 接口的 Bean,并调用其postProcessBeanFactory 方法

  1. 注册Bean 后置处理器

根据反射机制从 BeanDefinitionRegistry 中找出所有实现了 BeanFactoryPostProcessor 接口的 Bean,并将他们注册到容器 Bean 后置处理器的注册表中

  1. 初始化消息源(I18n国际化):初始化容器的国际化消息资源
  2. 初始化应用上下文事件广播器
  3. 初始化其他特殊的 bean 。由子类实现,如AbstractRefreshableWebApplicationContext 重写该方法初始化ThemeSource
  4. 注册事件监听器
  5. 初始化所有单实例的Bean,放入容器的缓存池中。使用懒加载模式的 Bean 除外。
  6. 完成刷新并发布容器刷新事件

Bean 装配流程

流程图

image

  1. ResourceLoader 加载配置文件信息,并使用 Resource 表示这个配置文件资源

  2. BeanDefinitionReader 读取 Resource 所指向的配置文件资源,解析配置文件。配置文件中每一个 解析成一个 BeanDefinition 对象,并保存在 BeanDefinitionRegistry 中

  3. 容器扫描 BeanDefinitionRegistry 中的 BeanDefinition ,使用个反射机制自动识别出 Bean 的工厂后置处理器(实现 BeanFactoryPostProcessor 接口),然后调用这个后置处理器的postProcessBeanFactory() 方法,对 BeanDefinitionRegistry 中的 BeanDefinition 进行加工处理。

  • 对使用占位符的 元素标签进行解析,得到最终的配置值
  • 对 BeanDefinitionRegistry 中的 BeanDefinition 进行扫描,通过反射扎到属性编辑器 Bean (实现了 java.beans.PropertyEditor 接口),并将其注册到容器的编辑器注册表中(PropertyEditorRegistry)
  1. Spring 容器从 BeanDefinitionRegistry 中取出加工后的 BeanDefinition,并调用 InstantiationStrategy 进行 Bean 的实例化工作

  2. 在实例化 Bean 时,Spring 容器使用 BeanWrapper 对 Bean 进行封装。BeanWrapper 提供了很多反射操作Bean的方法,将结合Bean 的 BeanDefinition 和容器中的属性编辑器,完成对 Bean 的属性注入

  3. 利用容器中的Bean 的后置处理器(实现 BeanPostProcessor 接口)对已经完成属性设置工作的 Bean 进行后续加工,完成 Bean 的装配工作

BeanDefinition:Bean 在容器中的内部表示

  1. 简单类图

image

  1. BeanDefinition 是 Bean 在容器中的内部表示。RootBeanDefinition 是最常用的实现类。如果有父子,父为 RootBeanDefinition,子为 ChildBeanDefinition;如果没有父的直接使用 RootBeanDefinition 表示

  2. Spring 容器将配置文件中的 配置信息转换为容器中的内部的 BeanDefinition 对象,并将这些 BeanDefinition 注册到 BeanDefinitionRegistry 中,后续的操作直接从 BeanDefinitionRegistry 中获取配置信息。

  3. 创建最终 BeanDefinition 主要是两个步骤:

  • 利用 BeanDefinitionReader 读取配置信息的 Resource,xml 解析成 BeanDefinition 对象。这个时候是个半成品,因为还有占位符存在
  • 利用 BeanFactoryPostProcessor 后置工厂处理器对半成品的 BeanDefinition 利用加工,生成成品的的 BeanDefinition

InstantiationStrategy:Bean 实例化策略

  1. 简单类图

image

  1. org.springframework.beans.factory.support.InstantiationStrategy 负责根据 BeanDefinition 对象创建一个 Bean 实例。相当于 new 的功能,不会参与 Bean 的属性设置工作

  2. SimpleInstantiationStrategy 是最常用的实例化策略,该策略利用 Bean 实现类的默认构造函数、带参构造函数、工厂方法创建 Bean 的示例

  3. CglibSubclassingInstantiationStrategy 扩展了 SimpleInstantiationStrategy,为需要进行方法注入的 Bean 提供支持。利用 CGLib 类库为 Bean 动态生成子类,在子类方法注入逻辑,然后使用这个动态生成的子类创建 Bean 的示例

BeanWrapper:Bean 属性编辑器填充

  1. 简单类图

image

  1. org.springframework.beans.BeanWrapper 是Spring 中的重要组件类。相当于一个代理器,Spring 委托 BeanWrapper 完成 Bean 属性的填充工作。在Bean 实例化被 InstantiationStrategy 创建出来后,容器将 Bean 实例通过 BeanWrapper 的包装起来。

  2. BeanWrapper 继承了 PropertyAccessor、PropertyEditorRegistry 接口。PropertyAccessor定义了各种访问Bean 属性的方法(getPropertyValue()),PropertyEditorRegistry 是属性编辑器的注册表。所以 BeanWrapper 的实现类 BeanWrapperImpl 具有3重身份:

  • Bean 包裹器
  • 属性访问器
  • 属性编辑器注册表
  1. BeanWrapperImpl 实例内部封装了两类组件,被封装的待处理的Bean,一套用于设置属性的属性编辑器

参考

  1. 源码地址

Fork me on Gitee

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值