ApplicationContext 和 BeanFacotry 两者都是用于加载 Bean 的,但是相比之下, ApplicationContext 提供了更多的扩展功能,简单一点说 ApplicationContext 包含 BeanFactory 的所有功能 通常建议比 BeanFactory 优先 ,除非在一些限制的场合,比如字节长度对内存有很大的影响时 (Applet) 使用 BeanFactory 方式加载 XML 使用 ApplicationContext 方式加载 XML
ClassPathXmlApplicationContext 中可以将配置文件路径以数 组的方式传人, ClassPathXmlApplicationContext 可以对数组进行解析并进行加载 而对于解析及功能实现都在 refresh()中实现
设置配置路径 此函数主要用于解析给定的路径数组,当然, 如果数组中包含特殊符号,如${var},那么 在resolvePath中会搜寻匹配的系统变量并替换
扩展功能 设置了路径之后,便可以根据路径做配置文件的解析以及各种功能的实现了 ClassPathXm!ApplicationContext 初始化的步骤 初始化前的准备工作,例如对系统属性或者环境变量进行准备及验证 初始化 BeanFactory 并进行 XML 文件读取 对BeanFactory 进行各种功能填充 子类覆盖方法做额外的处理 激活各种 BeanFactory 处理器 注册拦截 bean 创建的 bean 处理器,这里只是注册, 真正的调用是在 getBean 时候 为上下文初始化 Message 源,即对不同语言的消息体进行国际化处理 初始化应用消息广播器,并放入“applicationEventMulticaster” bean中 留给子类来初始化其他的 bean 在所有注册的 bean 中查找 listenerbean 注册到消息广播器中 初始化剩下的单实例(非惰性的) 完成刷新过程,通知生命周期处理器 lifecycleProcessor 刷新过程,同时发出 ContextRefreshEvent 通知别人
环境准备 prepareRefresh 函数主要是做些准备工作,例如对系统属性及环境变量的初始化及验证 initPropertySources 正符合 Spring 的开放式结构设计,给用户最大扩展 Spring 的能力 用户可以根据自身的需要重写 initPropertySources 方法,并在方法中进行个性化的属性处理及 设置 validateRequiredProperties 则是对属性进行验证 假如现在有这样一个需求,工程在运行过程中用到的某个设置(例如 VAR )是从系统环境 变量中取得的,而如果用户没有在系统环境变量中配置这个参数,那么工程可能不会工作 这 一要求可能会有各种各样的解决办法 当然,在Spring中可以这样做,可以直接修改 Spring 的源码,例如修改 ClassPathXmlApplicationContext 当然,最好的办法还是对源码进行扩展 可以自定义类: 还需要在使用的时候替换掉原有的ClassPathXmlApplicationContext
加载 BeanFactory obtainFreshBeanFactory 正是实现 BeanFactory 的地方 方法中将核心实现委托给了refreshBeanFactory: 创建DefaultListableBeanFactory 指定序列化 ID 定制BeanFactory 加载BeanDefinition 使用全局变量记录 BeanFactory 类实例
定制 BeanFactory 这里已经开始了对 BeanFactory 的扩展,在基本容器的基础上,增加了是否允许覆盖是否 允许扩展的设置并提供了注解@Qualifier 和@Autowired 的支持 对于允许覆盖和允许依赖的设置这里只是判断了是否为空,如果不为空要进行设置 解析 autowire 类型时首先会调用方法 在 QualifierAnnotationAutowireCandidateResolver 中一定会提供了解析 Qualifier 与 Autowire 注解的方法
加载 BeanDefinition 在实现配置文件的加载功能中除了我们在第一步中已经初始化的 DefaultListableBeanFactory 外, 还需要 XmlBeanDefinitionReader 来读取 XML 在初始化了 DefaultListableBeanFactory 和 XmlBeanDefinitionReader 后就可以进行配置文件 的读取了
功能扩展 上面函数中主要进行了几个方面的扩展 增加对 SpEL 语言的支持 增加对属性编辑器的支持 增加对一些内直类,比如 EnvironmentAware MessageSourceAware 的信息注入 设直了依赖功能可忽略的接口 注册一些固定依赖的属性 增加 Aspect 的支持 将相关环境变量及属性注册以单例模式注册
增加 SpEL 语言的支持 Spring 表达式语言全称为 Spring Expression Language ,缩写为 SpEL ,类似于 Struts 2x 中使 用的 OGNL 表达式语言 ,能在运行时构建复杂表达式、存取对象图属性、对象方法调用等,并 且能与 Spring 功能完美整合 ,比如能用来配置 bean 定义 SpEL 是单独模块,只依赖于 core 模块 不依赖于其他模块,可以单独使用 SpEL 使用#{ ...}作为定界符,所有在大框号中的字符都将被认为是 SpEL ,使用格式如下: 一般通过 AbstractBeanFactory 中的 evaluateBeanDefinitionString 方法去完成 SpEL 的解析
增加属性注册编辑器 在Spring DI 注入的时候可以把普通属性注入进来,但是像 Date 类型就无法被识别 上面代码中 需要对日期型属性进行注入: 如果直接这样使用,程序则会报异常, 类型转换不成功
Spring 针对此问题提供了两种解决办法 使用自定义属性编辑器 使用自定义属性编辑器,通过继承 PropertyEditorSupport ,重写 setAsText 方法,
注册 Spring 自带的属性编辑器 CustomDateEditaor
ResourceEditorRegistrar 的内部实现
ResourceEditorRegistrar 的 registerCustomEditors 方法的调用层次结构
AbstractBeanFactory 中的 registerCustomEditors 方法的调用层次结构 在 bean的初始化后会调用 ResourceEditorRegistrar 的 registerCustomEditors 方法进行批量的通用属性编 辑器注册 注册后,在属性填充的环节便可以直接让 Spring 使用这些编辑器进行属性的解析了
BeanWrapperlmpl 除了实现 BeanWrapper 接口外 还继承了 PropertyEditorRegistrySupport
添加 ApplicationContextAwareProcessor处理器 对于 postProcessAfterlnitialization 方法,在 ApplicationContextAwareProcessor 中并没有做过 多逻辑处理
设置忽略依赖
注册依赖
Beanfactory 的后处理
激活注册的 BeanFactoryPostProcessor
BeanFactoryPostProcessor 的典型应用: PropertyPlaceholderConfigurer 变量引用: ${ bean.message } 这就是 Spring 的分散配置 ,可以在另外的配 置文件中为 bean.message 指定值 如在 bean.property 配置如下定义 当访问名为 message 的 bean 时, mes 属性就会被置为字符串 “ Hi,can you find me?”
使用自定义 BeanFactoryPostProcessor 通过 ObscenityRemovingBeanFactoryPostProcessor Spring 很好地实现了屏蔽掉 obscenties定 义的不应该展示的属性
激活 BeanFactoryPostProcessor
对于 BeanDefinitionRegistry 类型的处理类的处理主要包括以下内容 对于硬编码注册的后处理器的处理 ,主要是通过 AbstractApplicationContext 中的添加处 理器方法 addBeanFactoryPostProcessor 进行添加 记录后处理器主要使用了3个List完成 registryPostProcessors 记录通过硬编码方式注册的 BeanDefinitionRegistryPostProcessor 类型的处理器 regularPostProcessors :记录通过硬编码方式注册的 BeanFactoryPostProcessor 类型的处 理器 registryPostProcessorBeans 记录通过配置方式注册的BeanDefinitionRegistryPostProcessor 类型的处理器 对以上所记录的 List 中的后处理器进行统一调用 BeanFactoryPostProcessor的 postProcessBeanFactory 方法 对beanFactoryPostProcessors 中非 BeanDefinitionRegis PostProcessor 型的 理器进行 BeanFactoryPostProcessor 的 postProcessBeanFactory 方法调用 普通beanFactory处理
注册BeanPostProcessor Spring 中大部分功能都是通过后处理器的方式进行扩展的 这是 Spring 框架的一个特性 但是在 BeanFactory 中其实并没有 实现后处理器的自动注册 所以在调用的时候如果没有进行手动注册其实是不能使用的 但是 在ApplicationContext 中却添加了自动注册功能 那么使用 BeanFactory 方式进行 Spring 的 bean 的加载时是不会有任何改变的,但是使用 ApplicationContext 方式获取 bean 的时候会在获取每个 bean 时打印出 “===”,而这个特性就 是在 registerBeanPostProcessors 方法中完成的
对于 internalPostProcessors 中存储的后处理器也就是 MergedBeanDefinitionPostProcessor 类型的处理器,在代码中似乎是被重复调用了 其实不是
初始化消息资源 java.util.Locale 是表示语言和国家/地区信息的本地化类 ,它是创建国际化应用的基础 JDK 的 java.util 包中 提供了几个支持本地化的格式化操作工具类 NumberFormat DateFormat MessageFormat
HierarchicalMessageSource 接口的几个实现类,
ResourceBundleMessageSource 的实现方式
在initMessageSource 中获取自定义资源文件的方式为 beanFactory.getBean(MESSAGE_ SOURCE BEAN NAME, MessageSource.class),在这里 Spring 使用了硬编码的方式硬性规定了 子定义资源文件必须为 message ,否则便会获取不到自定义资源配置,这也是为什么之前提到 Bean 的 id 如果部位 message 会抛出异常
在 AbstractApplicationContext 中的获取资源文件属性的方法 其中的 getMessageSource() 方法正是获取了之前定义的自定义资源配置
初始化 ApplicationEventMulticaster
ApplicationEventMulticaster 是如何被初始化的 initApplicationEve ntMulticaster 的方式比较简单 ,无非考虑两种情况 如果用户自定义了事件广播器 ,那么使用用户自定义的事件广播器 如果用户没有自定义事件广播器,那么使用默认的 ApplicationEventMulticaster
默认的广播器实现 SimpleApplicationEventMulticaster
注册监听器
初始化非延迟加载单例
ConversionService 的设置
冻结配置 冻结所有的 bean 定义,说明注册的 bean 定义将不被修改或进行任何进一步的处理
初始化非延迟加载 ApplicationContext 实现的默认行为就是在启动时将所有单例 bean 提前进行实例化 提 前实例化意味着作为初始化过程的一部分 ApplicationContext 实例会创建并配置所有的单例 bean 而这个实例化的过程就是在 finishBeanFactorylnitialization 中完成的
finishRefresh 在 Spring 中还提供了 Lifecycle 接口, Lifecycle 中包含 start/stop 方法,实现此接口后 Spring 会 保证在启动的时候调用其 start 方法开始生命周期,并在 Spring 关闭的时候调用 stop 方法来结束生 命周期,通常用来配置后台程序,在启动后一直运行(如对 MQ 进行轮询等)而 ApplicationContext 的初始化最后正是保证了这一功能的实现
initlifecycleProcessor 当ApplicationContext 启动或停止时,它会通过 LiifecycleProcessor 来与所有声明的 bean 的 周期做状态更新,而在 LifecycleProcessor 的使用前首先需要初始化
onRefresh 启动所有实现了 Lifecycle 接口的 bean publishEvent 当完成 ApplicationContext 初始化的时候,要通过 Spring 中的事件发布机制来发出 ContextRefreshedEvent 事件,以保证对应的监听器可以做进一步的逻辑处理
|