SpringFramework 的基本知识
SpringFramework 概述
SpringFramework 是一个开源的、松耦合的、分层的、可配置的一站式企业级 Java 开发框架,它的核心是 IOC 和 AOP,使用它可以更容易的构建出企业级 Java 应用,并且它可以根据应用开发的组件需求,整合对于的技术。
为什么使用 SpringFramework
SpringFramework 支持 IOC、AOP、容器与事件、web、事务控制、测试、快捷的与其他技术整合
IOC:组件之间解耦(有强依赖降为若依赖)
AOP:切面编程可以将应用业务做统一或特定的功能增强,能够实现应用业务与增强逻辑的解耦
容器与事件:管理应用中使用的组件 Bean、托管 bean 的生命周期、事件与监听器的驱动机制
SpringFramework 的模块划分
- beans、core、context、expression【核心包、容器】
- aop【切面编程】
- jdbc【整合jdbc】
- orm【整合 ORM 框架】
- tx【事务控制】
- web【web层技术】
- test{单元测试}
IOC 相关
如何理解 IOC
IOC 控制反转是一种思想,它的核心是将控制权交出去,交由IOC管理的思想,可以实现组件之间的解耦。IOC 的实现方式通常有依赖注入和依赖查找
为什么使用 IOC
- 解耦
- 解决对象间的依赖关系
- 托管对象的大部分生命周期过程,应用程序只需要关心使用过程、
IOC 的实现方式及对比
IOC 仅仅是一种思想,依赖查找DL和依赖注入DI才是 IOC 的落地实现。DL和DI的对比如下
- 作用目标不同:
- 依赖注入的作用目标通常是类成员(当然也可以是方法参数)
- 依赖查找的作用目可以是方法体内,也可以是方法体外
- 实现方式不同
- 依赖注入通常借助一个上下文 被动 的接收(标注 @Autowired 注解/
<property>
标签配置) - 依赖查找通常 主动 使用上下文搜索(拿到 BeanFactory / ApplicationContext 之后主动调用 getBean 方法)
- 依赖注入通常借助一个上下文 被动 的接收(标注 @Autowired 注解/
IOC 在SpringFramework中的实现方式
依赖查找
- getBean:根据 bean name 获取 / 根据 Class 获取指定的 bean
- ofType:根据 Class 获取容器中所有指定类型的 bean
- withAnnotation:获取标注了指定容器注解的 bean
- getBeanDefinitionNames:获取容器中所有的 bean 的 name
- getBeanProvider:延迟操作,先获取 ObjectProvider 后获取时机对象,如果不存在可以使缺省值代替
依赖注入
- xml 配置文件驱动方式
- 借助
<property>
标签给带有 setter 方法的属性赋值 / 注入依赖对象 - 借助
<constructor-arg>
标签使用 bean 的构造器注入依赖对象 / 属性赋值
- 借助
- 注解驱动方式
- 使用 @Value 给普通属性赋值
- 使用 @Autowired / @Resource / @Inject 注解给组件依赖注入
- 借助 ObjectProvider 可以实现组件的延迟注入
- 借助 Aware 系列接口实现回调注入
使用依赖注入的优点
-
依赖注入作为 IOC 的实现方式之一,目的就是 解耦,我们不再需要去直接的 new 那些依赖对象(直接依赖会导致对象的创建机制、初始化过程难以统一控制);而且如果组件存在多级依赖。依赖注入可以简化这些依赖关系,开发者只需要定义好谁依赖谁即可。
-
依赖注入还有另外一个特定就是依赖对象的 可配置:通过 xml 或注解声明,可以指定和调整组件注入的对象,借助 Java 的多态特性,可以不需要大批量的修改就可以完成依赖注入对象的替换(面向接口编程与依赖注入配合几乎完美)。
-
依赖注入可以不需要依赖框架的API(仅仅依赖 JSR 规范也可以实现依赖注入),而依赖查找必须要拿到框架容器的 API,这一点也能看出依赖注入的一个优点:与框架 API 低耦合
依赖注入的方式对比
注入方式 | 被注入的成员是否可以变 | 是否依赖IOC框架的API | 使用场景 |
---|---|---|---|
构造器注入 | 不可变 | 否(xml。编程式注入不依赖) | 不可变的固定场景 |
参数注入 | 不可变 | 否(高版本中注解配置类中的 @Bean 方法参数注入可不标注注解) | 注解配置类中的 @Bean 方法注册 bean |
属性注入 | 不可变 | 是(只能通过标注注解来侵入式注入) | 通常用于不可变的固定注入 |
setter注入 | 可变 | 否(xml、编程时注入不依赖) | 可选属性的注入 |
自动注入注解的对比
注解 | 注入方式 | 支持 @Primary | 来源 | Bean 不存在时的处理 |
---|---|---|---|---|
@Autowired | 根据类型注入 | 支持 | SpringFramework的原生注解 | 可指定 required=fasle 来避免依赖不存在时抛出异常 |
@Resource | 根据名称注入 | 支持 | JSP 250规范 | 容器中不存在指定 Bean 时会抛出异常 |
@Inject | 根据类型注入 | 支持 | JSR 330规范(需要导入jar包) | 容器中不存在指定 Bean 时会抛出异常 |
@Qualifer:如果被标注的成员 / 方法在根据类型注入时发现多个类型相同的 bean 时,则会根据该注解声明的 bean name 来寻找对应的 bean
@Primary:如果有多个相同类型的 bean 同时注册到 IOC 容器中,使用“根据类型注入”的注解时会直接注入 @Primary 标注的 bean
使用 setter 注入还是构造器注入
-
SpringFramework 4.0.2 及以前推荐使用 setter 注入,理由是:一个 Bean 有多个依赖时,构造器的参数列表会很长 ;而且如果 Bean 中依赖的属性不都是必须的话,注入会变得更麻烦;
-
4.0.3 开始以后官方推荐构造器注入,理由是:构造器注入的依赖是不可变的、完全初始化好的,并且可以保证不为null;
-
当然官方文档也说了,如果 真的出现了构造器参数列表过长的情况,可能是这个 Bean 承担的职责太多,应该考虑组件的责任拆解
SpringFramework 中的自动注入模式
- byType:根据类型注入
- byName:根据名称注入
- byConstructor:根据构造器注入
- autodetect:通过类的内省机制决定使用哪种方式注入
- 顺序:byConstructor -> byType
- no:不自动注入(默认)
IOC 容器相关
BeanFactory 和 ApplicationContext 的区别
BeanFactory 是实现 IOC 的顶层接口,它提供了一个抽象的配置和对象管理机制,ApplicationContext 是 BeanFactory 的子接口,它简化了和 AOP 的整合、消息机制、事件机制,以及对 Web 环境的扩展(WebApplicationContext 等)。ApplicationContext 是基于 BeanFactory 的扩展而不是继承 !
- AOP 支持(AnnotationAwareAspectJAutoProxyCreator 作用于 bean 的初始化之后)
- 配置元信息(BeanDefinition、Environment、注解等)
- 资源管理(Resource抽象)
- 事件驱动机制(ApplicationEvent、ApplicationListener)
- 消息与国际化(LocaleResolver)
- Environment 抽象
feature | BeanFactory | ApplicationContext |
---|---|---|
Bean Instantion/wiring —— Bean 的实例化和属性注入 | Yes | Yes |
Integrated lifecycle management —— 生命周期管理 | No | Yes |
Automatic BeanPostProcess registration —— Bean 后置处理器的支持 | No | Yes |
Automatic BeanFactoryPostProcessor registration —— BeanFactory 的后置处理器支持 | No | Yes |
Convenient MessageSource access(for internalization)—— 消息转换服务(国际化) | No | Yes |
Built-in ApplicationEvent publication mechanism —— 时间发布机制(事件驱动) | No | Yes |
除此之外,可以适当的引用官方文档的内容(可参照第 6 章 2.1 节)加以阐述,增加论述的可靠性。
ApplicationContext 的类型
从支持的配置源的角度来看,ApplicationContext
分为两种:基于 xml 配置文件的 ApplicationContext,和基于注解驱动配置类的 ApplicationContext。其中基于 xml 配置文件的 ApplicationContext 又有 ClassPathXMLApplicationContext
和 FileSystemXMLApplicationContext
两种,它们的区别是在加载 xml 配置文件的基础路径不同;基于注解的 ApplicationContext 只有 AnnotationConfigApplicationContext
,它可以基于配置类驱动,也可以基于包扫描路径驱动
可以参照第 15 章 ApplicationContext 全解析的内容辅以理解。
BeanFactory 和 FactoryBean 区别
BeanFactory:是 SpringFramework 中实现 IOC 的最底层容器;从类的继承结构上看,它是最顶级的接口,也是最顶层的容器实现;从类的组合结构上看,它是最深层次的容器,ApplicationContext 在最底层组合了 BeanFactory
FactoryBean:创建对象的工厂 Bean ,可以使用它来直接创建一些初始化流程比较复杂的对象。
BeanFactory 的设计
从接口设计角度来看:BeanFactory 是 IOC 的基础实现,最基础的 BeanFactory 只具备 依赖查找 的能力,它的直接子接口分别增加了 BeanFactory 的 层次性、可列举性、可配置 的特性
从实现的设计交底:BeanFactory 的实现类中,大多采用 父类控制流程 + 子类实现细节 的方式完成底层的功能逻辑,在父类中使用大量模板方法来控制整体的逻辑流程,由子类实现这些模板方法,完成功能的真正实现。
BeanFactory 本身具有以下一些特性:
- 基础的容器(DL、DI)
- 定义了作用域的概念(scope)
- 集成环境配置(Environment)
- 支持多种类型的配置源(Resource、PropertySource)
- 层次性的设计(Hierarchical)
- 完整的生命周期控制(createBean 定义在 BeanFactory 中,而不是 ApplicationContext 中)
在理解 BeanFactory 的时候,一定要从多方位的角度出发理解,结合第 14 章的内容理清 BeanFactory 中实现的功能、特性,以及在应用中发挥的作用。
ApplicationContext 的设计
从接口设计角度:ApplicationContext
继承了 BeanFactory
接口,它具备 BeanFactory
本身的特性;除此之外,ApplicationContext
还继承了多个接口,扩展了资源加载解析、消息国际化、事件发布等特性
从实现设计角度:ApplicationContext
分为 xml
配置文件和注解驱动两种不同的驱动实现,它们的实现方法与 BeanFactory 相似,也是采用 父类控制流程 + 子类实现细节 的方式设计。
扩展特性:
- 用于访问应用程序组件的 Bean 工厂方法,继承自 ListableBeanFactory
- 以通用方法加载文件资源的能力,它继承自 ResourceLoader
- 能够将事件发布给注册的监听器,它继承自 ApplicationEventPublisher
- 解析消息的能力,支持国际化,它继承自 MessageSource
- 从父上下文继承,在子容器中的定义将始终优先。(ApplicationContext 也具有层次性)
在理解 ApplicationContext 的时候不要一味地想着 ApplicationContext 是 BeanFactory 的子类扩展,它与 BeanFactory 的关系是组合关系,包括继承了其他接口后底层也都是组合这些接口对应功能的核心API。
Environment 的设计
Environmen
t 是 SpringFramework 3.1 引入的抽象的概念,它包含了 profiles
和 properties
的信息,可以实现统一的配置存储和注入、配置属性的解析等。其中 profiles 实现了一种基于模式的环境配置,properties 则应用于外部化配置
如何理解 BeanDefinitionRegistry
BeanDefinitionRegistry
是维护 BeanDefinition
的注册中心,它内部存放了 IOC 容器总 bean 的定义信息,同时 BeanDefinitionRegistry
也是支撑其它组件和动态注册 Bean 的重要组件。在 SpringFramework 中,BeanDefinitionRegistry
的实现的 DefaultListableBeanFactory
。
BeanDefinitionRegistry 针对的目标是 BeanDefinition 而不是 bean 对象
对比 BeanFactory 与 BeanDefinitionRegistry
BeanFactory:SpringFramework 中实现 IOC 的最底层容器,内部存放了应用中注册的 Bean 实例
BeanDefinitionRegistry:BeanDefinition 的注册表,它维护的对象是 BeanDefinition 而不是 bean 实例
BeanFactoryPostProcessor
BeanFactoryPostProcessor 的设计
BeanFactoryPostProcessor 是容器的扩展点,它用于 IOC 容器生命周期中,所有 BeanDefinition 都注册到 BeanFactory 后回调触发,用于访问 / 修改已经存在的 BeanDefinition。与 BeanPostProcess 相同,它们都是容器隔离的,不同容器中的 BeanFactoryPostProcessor 不会相互起作用
后置处理器对比
BeanPostProcessor | BeanFactoryPostProcessor | BeanDefinitionRegistryPostProcessor | |
---|---|---|---|
处理目标 | bean | BeanDefinition | BeanDefinition、.class 文件等 |
执行时机 | bean 的初始化阶段前后(已经创建出 bean 对象) | BeanDefinition 解析完毕,注册进 BeanDefinition 之后(此时Bean 还未实例) | 配置文件、配置类已经解析完毕并注册进BeanFactory。但还没有被 BeanFactoryPostProcessor 处理 |
可操作空间 | 给 bean 的属性赋值、创建代理对象等 | 给BeanDefinition中增删属性、移除 BeanDefinition 等 | 向 BeanFactory 中注册新的 BeanDefinition |
Bean相关
Bean 的类型有哪些
SpringFramework 中的 bean 只有两种类型:普通 bean 和工厂 baen(FactoryBean 创建的对象)
普通 bean:就是最最普通的 bean 对象,SpringFramework 中绝大部分创建的 bean 都是普通 bean
工厂 bean:由 FactoryBean 创建的 bean 就是 工厂 bean,工厂 bean 不会在实际的业务逻辑中起作用,而是由创建的对象来起作用。FactoryBean 本身只是一个接口,它只是创建真正 bean 对象的工厂。
Bean 的作用域有哪些
在SpringFramework 5.x 版本中内置了 6 中作用域
作用域类型 | 概述 |
---|---|
Singleton | 一个 IOC 容器中只有一个相同类型的 bean(默认) |
prototype | 每次获取创建一个新的 |
request | 一次请求创建一个新的(仅web环境可用) |
session | 一个会话创建一个新的 |
application | 一个web应用创建一个 |
websocket | 一个websocket会话创建一个 |
Bean 的实例化方式
SpringFramework 中实例化 bean 的方式,分为 4 种普通方式 + 1 种特殊方式
- 直接通过
<bean>
/ @Bean /@Component 的方式注册 Bean 后实例化 - 借助 FactoryBean 实例化 bean
- 使用静态工厂方法(factory-method)实例化 bean
- 使用实例工厂方法(factory-bean + factory-method)实例化 bean
- 借助 InstantiationAwareBeanPostProcessor 实例化 bean(该方法比较特殊,实际上就是拦截原有 bean 的创建流程而是)
Bean 初始化 / 销毁的三种生命周期控制方法对比
init-method & destroy-method | @PostConstruct & @PreDestroy | InitlizingBean & DisposableBean | |
---|---|---|---|
执行顺序 | 最后 | 最先 | 中间 |
组件耦合 | 无侵入(自在<bean> 和 @Bean 中使用) |
与 JSR 规范耦合 | 与 SpringFramework 耦合 |
容器支持 | xml、注解原生支持 | 注解原生支持,xml 需要开启注解驱动 | xml、注解原生支持 |
单实例 Bean | ✔ | ✔ | ✔ |
原型 Bean | 只支持 init-method | ✔ | ✔ |
如何理解 BeanDefinition
BeanDefinition
描述了 SpringFramework 中 Bean
的元信息,它包含 Bean
的类信息、属性、行为、依赖关系、配置信息等。BeanDefinition
具有层次性,并且可以在 IOC 容器初始化阶段被 BeanDefinitionRegistryPostProcessor
构造和注册,被 BeanFactoryPostProcessor
拦截修改等。
设计 BeanDefinition 的意义
SpringFramework 面对一个应用程序,它需要对其中的 Bean
进行定义抽取,只有抽取成可以统一类型 / 格式的模型,才能在后续的 Bean
对象管理时,进行统一管理,或者对特定的 Bean
进行特殊化的处理。而这一切的一切最终落地到统一类型上,就是 BeanDefinition
这个抽象化的模型。先有定义,后有实例,这样更容易实现全流程的控制和扩展的切入
BeanPostProcess
BeanPostProcess 的设计
BeanPostProcess
是一个容器的扩展点,它针对的是 Bean
对象,可以在 Bean
的生命周期过程中,初始化阶段前后添加自定义的处理逻辑,并且不同的 IOC 容器的 BeanPostProcess
不会互相干预。
BeanPostProcess 的扩展
在 SpringFramework 内部,BeanPostProcess 的扩展有三种:
- InstantiationAwareBeanPostProcessor:作用于 Bean 对象的实例化前后,以及属性赋值阶段
- MergedBeanDefinitionPostProcessor:作用于 BeanDefinition 的合并阶段,借助它可以完成层级 Bean 的定义信息汇总
- 如 AutowiredAnnotationBeanPostProcessor 会收集 Bean 所设计类及 bean 所属类的父类中自动注入信息
- DestructionAwareBeanPostProcessor:作用于 Bean 对象的销毁动作之前
单实例 Bean 的线程安全问题
SpringFramework 中的 Bean 默认单实例的,是线程不安全的,如果 Bean 存在多种状态,则需要考虑换位 prototype(原型)作用域类型的 Bean
通常情况下,Singleton 用于无状态 Bean,Prototype 用于有状态的 Bean
Bean 的生命周期
Bean
的生命周期分为 BeanDefinition
阶段和 Bean
实例阶段
-
BeanDefinition:该阶段分为加载 xml 配置文件、解析注解配置类、编程式构造
BeanDefinition
、BeanDefinition
的后置处理,一共四个部分 -
Bean 实例化阶段,该阶段的生命周期包含四大步:
- bean 的实例化
- 属性注入 + 依赖注入
- bean 的初始化生命周期回调
- bean 实例的销毁
BeanDefinition 阶段生命周期
-
加载 xml 配置文件:发生在基于 xml 配置文件的
ApplicationContext
中refresh()
方法的BeanFactory
初始化阶段,此时 BeanFactory 刚刚构建完成,它会借助XmlBeanDefinitionReader
来加载 xml 配置文件,并使用DefaultBeanDefinitionDocumentReader
解析 xml 配置文件,封装声明的<bean>
标签内容并转换为BeanDefinition
。 -
解析注解配置类:发生在
ApplicationContext
中refresh()
方法的BeanDefinitionRegistryPostProcessor
阶段,该阶段首先会执行ConfigurationClassPostProcessor
的postProcessorBeanDefinitionRegistry
方法。ConfigurationClassPostprocessor
中会找出所有的配置类,排序后依次解析,并借助ClassPathBeanDefinitionScanner
实现包扫描的BeanDefinition
封装,借助ConfigurationClassBeanDefinitionReader
实现@Bean
注解方法的BeanDefinition
解析和封装。 -
编程式构造:
BeanDefinition
也是发生在ApplicationContext
的refresh()
方法的BeanDefinitionRegistryPostProcessor
执行阶段,由于BeanDefinitionRegistryPostProcessor
中包含ConfigurationClassPostProcessor
,而ConfigurationClassPostProcessor
会执行ImportBeanDefinitionRegistry
的逻辑,从而达到编程式构造BeanDefinition
并注入到BeanDefinitionRegistry
的目的;另外,实现了BeanDefinitionRegistryPostProcessor
的类也可以编程式构造BeanDefinition
注入到BeanDefinitionRegistry
。
bean 实例化阶段的生命周期
在所有非延迟加载的单实例 bean 初始化之前,会先初始化所有的 BeanPostProcessor
。
在 ApplicationContext
的 refresh()
方法中,finishBeanFactoryInitialization
步骤会初始化所有的非延迟加载的单实例 bean。实例化 bean 的入口是 getBean()
-> doGetBean()
,该阶段会合并 BeanDefinition
,并根据 bean
的 scope
选择实例化 bean
的策略。
创建 bean 的逻辑会走 createBean()
方法,该方法中会先执行所有 InstantiationAwareBeanPostProcessor
的 postProcessorBeforeInstantiation()
方法尝试创建 bean 实例,如果成功创建,则会直接调用 PostProcessorAfterInstantiation()
方法初始化 bean 后返回,如果 InstantiationAwareBeanPostProcessor
没有创建 bean 实例,则会调用 doCreateBean()
方法创建 bean 实例。在 doCreateBean()
方法中,会先根据 bean 的 Class 中的构造器定义,决定如何实例化 bean,如果没有定义构造器,则会使用无参构造器,反射创建 bean 对象。
Bean 初始化阶段的生命周期
bean 对象创建完成后,会进行属性赋值、依赖注入,以及初始化阶段的方法回调。在 populateBean
属性赋值阶段,会事先收集好 bean 中标注了依赖注入的注解(@Autowired
、@Value
、@Resource
、@Inject
),之后会借助后置处理器,回调 PostProcessorProperties
方法实现依赖注入。
属性赋值和依赖注入之后,会调用执行 bean 的初始化方法,以及后置处理器的逻辑:首先会执行 Aware 相关的回调注入,之后执行后置处理器的前置回调,在后置处理器的前置方法中,会回调 bean 中标注了 @PostConstruct 注解的方法,所有的后置处理器前置回调后,会执行 InitializingBean 的 afterPropertiesSet 方法,随后是 init-method 指定的方法,等这些 bean 的初始化方法都回调完毕后,最后执行后置处理器的后置回调
全部的 bean 初始化结束后,ApplicationContext 的 start 方法触发时,会触发实现了 Lifecycle 接口的 bean 的 start 方法
Bean 销毁阶段的生命周期
bean 对象在销毁时,由 ApplicationContext 发起关闭动作。销毁 bean 的阶段,由 BeanFactory 取出所有单实例 bean ,并逐个销毁
销毁动作会将当前 bean 依赖的所有 bean 都销毁,随后回调那些自定义的 bean 的销毁方法,之后如果 bean 中有定义内部 bean 则会一并销毁,最后销毁那些依赖了当前 bean 的 bean 也一起销毁
Bean 装配相关
模块装配与条件装配
-
模块装配:指用最少的代码,把一个模块需要的核心功能组件都装配好(通常使用自定义 @EnableXxxx 注解 + @Import 注解完成)。
- @Import 支持装配的组件:普通类、注解配置类、ImportSelector、ImportBeanDefinitionRegistry
-
条件装配:可以设定装配 bean 或配置类在特定条件下才生效,分为 profile 和 conditional 两种实现方式。
- profile 基于 Environment 层,一般用于多环境配置
- conditional 基于 bean 层,且 conditional 的判断方式更加灵活
组件扫描
利用组件扫描,可以扫描指定路径下的所有标注了模式注解的类,并封装生成 bean 对象。可以通过声明 @ComponentScan 注解中的 includeFilters 和 excludeFilters 属性来指定扫描的匹配规则。
SPI
SPI 是通过一种“服务寻找”的机制,动态的加载接口 / 抽象类对应的具体实现类,它把接口具体实现类的定义和声明权交给了外部化的配置文件中。
jdk 的 SPI 是需要遵循规范的:所有定义的 SPI 文件都必须放在工程的 META-INF/services 目录下,且文件名必须命名为接口 / 抽象类的全限定名,文件内容为接口 / 抽象类的具体实现类的全限定名,如果出现多个具体实现类,则每行声明一个类的全限定名,没有分隔符。
SpringFramework 中的 SPI 在要求上比较宽松,它不止可以基于接口 / 抽象类,还可以是任何一个类、接口、注解,并且这种机制被大量用于 SpringBoot 的自动装配中。
功能特性相关
事件与监听器
如何理解观察者模式
观察者模式,也被称为发布订阅模式、监听器模式,它是 GoF23 设计模式中行为型模式的其中之一。观察者模式关注的点是某一个对象被修改 / 做出某些反应 / 发布一个信息等,会自动通知依赖它的对象(订阅者)。观察者模式的三大核心是:观察者、被观察主题、订阅者。观察者( Observer )需要绑定要通知的订阅者( Subscriber ),并且要观察指定的主题( Subject )。
Spring中的观察者模式是如何体现的
SpringFramework 中,体现观察者模式的特性就是事件驱动和监听器。监听器充当订阅者,监听特定的事件;事件源充当被观察的主题,用来发布事件;IOC 容器本身也是事件广播器,可以理解成观察者。
SpringFramework 的事件驱动核心概念可以划分为 4 个:事件源、事件、广播器、监听器。
- 事件源:发布事件的对象
- 事件:事件源发布的信息 / 作出的动作
- 广播器:事件真正广播给监听器的对象【即 ApplicationContext 】
- ApplicationContext 接口有实现 ApplicationEventPublisher 接口,具备事件广播器的发布事件的能力
- ApplicationEventMulticaster 组合了所有的监听器,具备事件广播器的广播事件的能力
- 监听器:监听事件的对象
监听器的实现方式
- 实现 ApplicationListener ,并指定要监听的事件类型
- 普通 bean 的方法上标注 @EventListener 注解,同样可以生成一个监听器
Spring中内置的事件
- ContextRefreshedEvent :IOC 容器刷新完毕但尚未启动,广播该事件
- ContextClosedEvent :IOC 容器已经关闭但尚未销毁所有 Bean ,广播该事件
- ContextStartedEvent :ApplicationContext 的 start 方法被触发,广播该事件
- ContextStoppedEvent :ApplicationContext 的 stop 方法被触发,广播该事件
资源管理
SpringFramework 中的资源管理是内部封装的,它的核心资源模型接口 Resource 可以支持 ResourceLoader 从类路径等位置加载。根据资源的加载来源不同,Spring 划分了几种 Resource 的不同实现,并由 DefaultResourceLoader 委托 ProtocolResolver 来负责加载这些资源。
SpringFramework 可以支持 properties 、xml(yml)等类型的资源文件,这些资源会通过 PropertySourceFactory 加载进 Environment 中,成为应用内变量的一部分。
配置元信息
理解配置源
配置源,就是配置的来源。对于 IOC 容器而言,xml 配置文件或者注解配置类可以称之为配置源;对于 Environment 来讲,properties 资源文件也可以看作是配置源。SpringFramework 拿到配置源后会先加载,再解析,最后注册那些定义好的 bean 到 IOC 容器。
理解元信息
简单的理解,元信息,就是信息的信息,定义的定义。举个例子,Class 这个类里面就包含一个类的所有定义(属性、方法、继承实现、注解等),所以我们可以说:Class 中包含类的元信息。
Spring中的元信息
Spring 中的元信息可以简单的分为 Bean 的元信息、IOC 容器的元信息:
- Bean 的元信息
- 全限定名 className
-作用域 scope
-是否延迟加载 lazy
-工厂 Bean 名称 factoryBean
-构造方法参数列表 constructorArgumentValues
-属性值 propertyValues
- 全限定名 className
- IOC 容器的元信息
-beans ,包含 profile 、default-autowire 等配置
-context ,包含 component-scan 、property-placeholder 、annotation-config 等配置