Spring Bean 的创建是典型的工厂模式,在顶层的结构设计主要围绕着 BeanFactory 和 xxxRegistry 进行:
- BeanFactory: 工厂模式定义了 IOC 容器的基本功能
- BeanRegistry: 提供手动注册 BeanDefinition到容器中的方法
BeanFactory
BeanFactory作为最顶层的一个接口类,它定义了IOC容器的基本功能
1 | public interface BeanFactory { |
BeanFactory 有三个子类:ListableBeanFactory
、HierarchicalBeanFactory
和AutowireCapableBeanFactory
。
- **
ListableBeanFactory
**:该接口定义了访问容器中 Bean 基本信息的若干方法,如查看 Bean 的个数、获取某一类型 Bean 的配置名、查看容器中是否包括某一 Bean 等方法; - **
HierarchicalBeanFactory
**:父子级联 IoC 容器的接口,子容器可以通过接口方法访问父容器; 通过 HierarchicalBeanFactory 接口, Spring 的 IoC 容器可以建立父子层级关联的容器体系,子容器可以访问父容器中的 Bean,但父容器不能访问子容器的 Bean。Spring 使用父子容器实现了很多功能,比如在 Spring MVC 中,展现层 Bean 位于一个子容器中,而业务层和持久层的 Bean 位于父容器中。这样,展现层 Bean 就可以引用业务层和持久层的 Bean,而业务层和持久层的 Bean 则看不到展现层的 Bean。 - **
ConfigurableBeanFactory
**:是一个重要的接口,增强了 IoC 容器的可定制性,它定义了设置类装载器、属性编辑器、容器初始化后置处理器等方法; ConfigurableListableBeanFactory
: ListableBeanFactory 和 ConfigurableBeanFactory 的融合;- **
AutowireCapableBeanFactory
**:定义了将容器中的 Bean 按某种规则(如按名字匹配、按类型匹配等)进行自动装配的方法
BeanRegistry
BeanDefinitionRegistry 接口提供了向容器手工注册 BeanDefinition 对象的方法
BeanDefinition
Bean 对象存在依赖嵌套等关系,所以设计者设计了 BeanDefinition,它用来对 Bean 对象及关系定义;我们在理解时只需要抓住如下三个要点:
BeanDefinition
定义了各种 Bean 对象及其相互的关系BeanDefinitionReader
这是 BeanDefinition 的解析器BeanDefinitionHolder
这是 BeanDefination 的包装类,用来存储 BeanDefinition,name 以及 aliases 等。
ApplicationContext
ApplicationContext是IoC容器的接口,除了继承了BeanFactory的能力,还拓展了配置资源的加载、应用事件、国际化等功能
- ApplicationEventPublisher:让容器拥有发布应用上下文事件的功能,包括容器启动事件、关闭事件等。
- MessageSource:为应用提供 i18n 国际化消息访问的功能;
- ResourcePatternResolver :资源模式解析接口,可以通过带前缀的 Ant 风格的资源文件路径装载 Spring 的配置文件。
- LifeCycle:提供了
start()
和stop()
两个方法,主要用于控制异步处理过程。在具体使用时,该接口同时被 ApplicationContext 实现及具体 Bean 实现, ApplicationContext 会将 start/stop 的信息传递给容器中所有实现了该接口的 Bean,以达到管理和控制 JMX、任务调度等目的。
ApplicationContext体系
为什么设计这么多ApplicationContext?
第一,从类结构设计上看, 围绕着是否需要 Refresh 容器衍生出两个抽象类:
GenericApplicationContext
: 是初始化的时候就创建容器,往后的每次 refresh 都不会更改AbstractRefreshableApplicationContext
:AbstractRefreshableApplicationContext
及子类的每次 refresh 都是先清除已有 (如果不存在就创建) 的容器,然后再重新创建,因此无法做到像GenericApplicationContext
混合搭配从不同源头获取 bean 的定义信息第二, 从加载的源来看(比如 xml,groovy,annotation 等), 衍生出众多类型的 ApplicationContext, 典型比如:
FileSystemXmlApplicationContext
: 从文件系统下的一个或多个 xml 配置文件中加载上下文定义,也就是说系统盘符中加载 xml 配置文件。ClassPathXmlApplicationContext
: 从类路径下的一个或多个 xml 配置文件中加载上下文定义,适用于 xml 配置的方式。AnnotationConfigApplicationContext
: 从一个或多个基于 java 的配置类中加载上下文定义,适用于 java 注解的方式。ConfigurableApplicationContext
: 扩展于 ApplicationContext,它新增加了两个主要的方法:refresh()
和close()
,让 ApplicationContext 具有启动、刷新和关闭应用上下文的能力。在应用上下文关闭的情况下调用refresh()
即可启动应用上下文,在已经启动的状态下,调用refresh()
则清除缓存并重新装载配置信息,而调用close()
则可关闭应用上下文。第三, 更进一步理解:
***设计者在设计时
AnnotationConfigApplicationContext
为什么是继承GenericApplicationContext
***? 因为基于注解的配置,是不太会被运行时修改的,这意味着不需要进行动态 Bean 配置和刷新容器,所以只需要GenericApplicationContext
。而基于 XML 这种配置文件,这种文件是容易修改的,需要动态性刷新 Bean 的支持,所以 XML 相关的配置必然继承
AbstractRefreshableApplicationContext
; 且存在多种 xml 的加载方式(位置不同的设计),所以必然会设计出AbstractXmlApplicationContext
, 其中包含对 XML 配置解析成 BeanDefination 的过程。那么细心的你从上图可以***发现
AnnotationWebConfigApplicationContext
却是继承了AbstractRefreshableApplicationContext
而不是GenericApplicationContext
***? 因为用户可以通过 ApplicationContextInitializer 来设置 contextInitializerClasses(context-param / init-param), 在这种情况下用户倾向于刷新 Bean 的,所以设计者选择让AnnotationWebConfigApplicationContext
继承了AbstractRefreshableApplicationContext
。
这一段解释封神,我直接复制粘贴😆
参考: