0.What’s this?
这是一篇关于《Spring源码深度解析》的笔记
第六章 容器的功能扩展
除了XmlBeanFactory,Spring中还提供了另一个接口ApplicationContext,用于扩展BeanFactory的现有功能。
// 使用BeanFactory
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("xxx.xml"));
// 使用ApplicationContext
ApplicationContext context = new ClassPathXmlApplicationContext("xxx.xml");
6.1 设置配置路径
ClassPathXmlApplicationContext提供了一个方法setConfigLocations,支持将配置文件以数组的形式同时传入,解析给定的全部路径,如果数组中包含系统变量,会在内部调用resolvePath搜寻匹配的系统变量并进行替换。
6.2 扩展功能
通过refresh方法对配置文件做解析,并完成各种扩展功能的实现:
- prepareRefreh: 对系统属性或环境变量进行准备及验证,完成初始化前的准备工作
- obtainFreshBeanFactory: 初始化beanFactory,对XML文件进行读取
- prepareBeanFacory: 对BeanFactory进行各种功能填充,支持@Qualifier于@Autowired注解
- postProcessBeanFactory: 对子类覆盖的方法做额外处理
- invokeBeanFactoryPostProcessors: 激活各种BeanFactory的处理器
- registerBeanPostProcessors:注册拦截bean创建的bean处理器
- initMessageSource: 为上下文初始化Message源,对普通语言的消息体提供支持
- initApplicationEventMulticaseter: 初始化应用消息广播器,并放入applicationEventMulticaster中
- onRefresh: 留给子类来初始化其他bean
- registerListeners: 在所有注册的bean中查找listener bean,注册到消息广播器中
- finishBeanFacotryInitialization: 初始化剩下的非惰性单实例
- finishRefresh: 完成刷新,通知生命周期管理器刷新过程,并发出ContentRefreshEvent通知其他组件
- destoryBeans & cancelRefresh: 在以上步骤发生异常的情况下,删除创建的bean,并做取消刷新的后处理
6.3 环境准备
prepareRefresh方法对系统属性或环境变量进行准备及验证,完成初始化前的准备工作
- initPropertySources方法交给开发者根据需要进行重写(Spring 开放式架构涉设计)
- validateRequiredProperties方法对属性进行验证
6.4 加载BeanFactory
该方法的核心实现委托在refreshBeanFactory的实现中:
- 创建DefaultListableBeanFactory
- 指定序列化id
- 定制BeanFactory,提供对注解@Qualifier和@Autowired的支持
- 加载BeanDefinition
- 使用全局变量记录BeanFactory的实例
6.5 功能拓展
进入函数prepareBeanFactory之前,Spring已经完成了对配置的解析,ApplicationContext对功能的扩展在这里完成:
- 设置BeanFactory的classLoader为当前context的classLoader
- 设置BeanFactory的表达式语言处理器,以支持SpEL
- 为BeanFactory添加一个默认的propertyEdit,作为bean的属性等的设置管理工具
- 添加beanPostProcessor
- 设置忽略自动装配的接口
- 设置自动装配的特殊规则
- 增加对AspectJ的支持
- 添加默认的系统环境bean
6.5.1 SpEL语言的支持
SpEL(Spring Expression Language) 用于在运行时构建复杂表达式、存取对象图属性、对象方法调用。只依赖于core模块,可以单独使用。
SpEl的解析是在AbstractAutowireCapableBeanFactory.applyPropertyValues方法中,通过AbstractBeanFactory(基类)的evaluateBeanDefinitionString方法进行解析的。
6.5.2 增加属性注册编辑器
Spring 进行依赖注入时,能够把普通的属性注入进来,但是有些类型无法被识别,如Date类,在进行mapper转换时,它被认为是Date类,但在Xml配置文档中,它会被视为String类,从而抛出异常。此时有两种方式解决这个问题
1. 使用自定义属性编辑器
首先,通过继承PropertyEditorSupport类,实现一个属性编辑器,为一个Spring类型的值指定特殊的解析方法,将字符串解析为实际Bean所期望的类型,再通过setValue方法注入依赖。
然后再配置文件中,在bean标签内,通过class属性指定该Bean所使用的属性编辑器,将两者绑定。
2. 使用自带的属性编辑器
对于某些类,Spring提供了自带的属性编辑器,如Date类,可以使用Spring的CustomDateEditor类,绑定方式同上。具体处理过程略。
6.5.3 添加ApplicationContextAwareProcessor处理器
核心方法是invokeAwareInterfaces,实现了这些Aware接口的bean再被初始化后可以获得一些对应的资源。
6.5.4 设置忽略依赖
调用beanFactory.ignoreDependencyInterface(xxxx.class)设置Spring注入依赖时忽略这些类。
6.5.5 注册依赖
调用beanFactory.registerResolvableDependency(xxxx.class, this/beanFactory)设置Spring在注入依赖时添加这些类。
6.6 BeanFactory的后处理
6.6.1 激活注册的BeanFactoryPostProcessor
BeanFactoryPostProcessor接口于BeanPostProcessor相似,可以对bean的定义继续宁处理。IoC容器允许BeanFactoryPostProcessor在容器实际实例化任何其他bean之前读取配置元数据,并有可能修改。BeanFactoryPostProcessor可以配置多个,并且当BeanFactoryPostProcessor实现了Ordered接口时,可以通过order属性来指定执行次序。
1.PropertyPlaceholderConfigurer
用于处理在bean配置文件中出现的变量引用。该类是一个bean,有一个名为locations的列表属性,其中每一项的值是一个配置文件的位置,PropertyPlaceholderConfigurer将会扫描这些配置文件,从中查找符合条件的值来替换bean配置文件中的变量引用。
2.使用自定义BeanFactoryPostProcessor
自定义的BeanFactoryPostProcessor可以屏蔽一些不期望出现在bean中的属性值。定义一个bean,包含名为obscenties的属性,属性内为一个set标签包含一系列value子标签,value的内容即为需要屏蔽的内容。在postProcessorBeanFactory的实现中,可以通过重写StringValueResolver的resolverStringValue方法,将屏蔽词替换为其他字符串。最后将StringValueResolver设置到BeanDefinitionVisitor中即可。
3.激活BeanFactoryPostProcessor
- 对硬编码注册的后处理器进行处理,主要是通过AbstractApplicationContext中添加处理器方法addBeanFactoryPostProcessor进行添加。添加后的后处理器会存放在beanFactoryPostProcessor中,而在处理BeanFactoryPostProcessor是会先检测beanFactoryPostProcessor中是否有数据。
- 使用三个List记录后处理器:registryPostProcessors记录通过硬编码方式注册的BeanDefinitionRegistryPostProcessor类型的处理器、regularPostProcessor记录通过硬编码方式注册的BeanFactoryPostProcessor类型的处理器、registryPostProcessorBeans记录通过配置方式注册的BeanDefinitionRegistryPostProcessor类型的处理器。
- 对所有List中记录的后处理器统一调用postProcessBeanFactory方法
- 对beanFactoryPostProcessor中非BeanDefinitionRegistryPostProcessor类型的后处理器继续宁统一的postProcessorBeanFactory方法调用
- 处理普通beanFactory。
6.6.2 注册BeanPostProcessor
Spring中大部分功能都是通过后处理器进行扩展的,但是BeanFactory中其实并没有实现后处理器的自动注册,所以在调用的时候需要进行手动注册,而ApplicationContext中为其提供了自动注册功能,因此使用ApplicationContext方式获取bean时可以执行后处理器方法。
对于beanFactory中后处理器的注册,Spring支持对于BeanPostProcessor的排序,比如根据PriorityOrdered进行排序,根据Orderd进行排序或无序,而Spring在BeanPostProcessor的激活顺序上也会考虑进行排序。
6.6.3 初始化消息资源
Spring定义了访问国际化信息的MessageSource接口,并提供了几个易用的实现类。
消息资源的设置过程:
- 定义资源文件,如messages.properties设置英文或messages_zh_CN设置中文等。
- 定义配置文件,定义一个id为messageSource的bean,然后通过property内的list标签下的value子标签来定义消息。
- 使用ApplicationContext的getMessage方法获取消息。
6.6.4 初始化ApplicationEventMulticaster
Spring监听器的简单用法:
- 定义监听事件
- 定义监听器
- 添加配置文件
- 测试:发送事件,检查监听器的响应
当产生Spring时间的时候,会默认使用SimpleApplicationEventMulticaster的multicasterEvent来广播时间,遍历所有监听器,并使用监听器中的onApplicationevetn方法来进行监听器的处理。而对于每个监听器来说,其实都可以获取到产生的事件,但是是否进行处理则由事件监听器决定。
6.6.5 注册监听器
Spring注册监听器的时候所做的逻辑操作:
- 硬编码方式注册的监听器处理:直接将listener类加入监听器容器中
- 配置文件注册的监听器处理:将listener类的名字传递给addApplicationListenerBean方法,再由该方法获得bean并加入监听器容器中
6.7 初始化非延迟加载单例
完成BeanFactory的初始化工作,其中包括ConversionService的设置、配置冻结以及非延迟加载的bean的初始化工作。
6.7.1 ConversionService设置
类似于String转Date的方式,ConversionService提供了使用Converter来完成这一项工作:
- 定义转换器,即String如何变为Date类
- 注册转换器,在配置文件中定义id为conversonService的bean,通过name为converters的property下list标签内的bean子标签来指定converter类
- 测试,直接调用conversionService的convert方法。传入String和输出类的class对象,检验结果
6.7.2 冻结配置
冻结所有的bean定义,说明注册的bean定义将不被修改或进行任何进一步的处理。核心逻辑在freezeConfiguration方法内完成。
6.7.3 初始化非延迟bean的加载
ApplicationContext实现的默认行为就是在启动时将所有单例bean提前进行实例化,提前实例化意味着作为初始化过程的一部分,ApplicationContext实例会创建并配置所有的单例bean。该过程在finishBeanFactoryInitialization中完成。
6.8 finishRefresh
在Spring中还提供了LifeCycle接口,Lifecycle中包含start/stop方法。实现此接口后Spring会保证在启动的时候调用其start方法开始生命周期,并在关闭时调用stop方法结束生命周期,通常用来配置后台程序,在启动后一直运行。
- initLifecycleProcessor: 初始化LifecycleProcessor
- onRefresh:启动所有实现了Lifecycle接口的bean
- publishEvent:通过Spring中的事件发布机制来发出ContextRefreshedEvent事件,通知对应监听器做进一步处理