thinking-in-spirng
第一章:Spring Framework 总览(Overview)
Spring Framework 版本 | Java 标准版 | Java 企业版 |
---|---|---|
1.x | 1.3+ | J2EE 1.3 + |
2.x | 1.4.2+ | J2EE 1.3 + |
3.x | 5+ | J2EE 1.4 和 Java EE 5 |
4.x | 6+ | Java EE 6 和 7 |
5.x | 8+ | Java EE 7 |
Spring 编程模型:
面向对象编程
契约接口:Aware、BeanPostProcessor …
设计模式:观察者模式、组合模式、模板模式 …
对象继承:Abstract* 类
面向切面编程
- 动态代理:JdkDynamicAopProxy
- 字节码提升:ASM、CGLib、AspectJ…
面向元编程
- 注解:模式注解(@Component、@Service、@Respository …)
- 配置:Environment 抽象、PropertySources、BeanDefinition …
- 泛型:GenericTypeResolver、ResolvableType …
函数驱动
- 函数接口:ApplicationEventPublisher
- Reactive:Spring WebFlux
模块驱动
- Maven Artifacts
OSGI Bundles- Java 9 Automatic Modules
- Spring @Enable*
第二章:重新认识 IoC
2.1 IoC 容器的职责:
- 通用职责
- 依赖处理
- 依赖查找
- 依赖注入
- 生命周期管理
- 容器
- 托管的资源(Java Beans 或其他资源)
- 配置
- 容器
- 外部化配置
- 托管的资源(Java Beans 或其他资源)
- 依赖处理
2.2 Spring 作为 IoC 容器的优势:
- 典型的 IoC 管理,依赖查找和依赖注入
- AOP 抽象
- 事务抽象
- 事件机制
- SPI 扩展
- 强大的第三方整合
- 易测试性
- 更好的面向对象
第三章:Spring IoC 容器概述
3.1 Spring IoC 依赖查找:
BeanFactory beanFactory = new ClassPathXmlApplicationContext("...")
- 根据 Bean 名称查找
- 实时查找
(User) beanFactory.getBean("user")
- 延迟查找
org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean
- 实时查找
- 根据 Bean 类型查找
- 单个 Bean 对象
beanFactory.getBean(User.class);
- 集合 Bean 对象
- 单个 Bean 对象
- 根据 Bean 名称 + 类型查找
beanFactory.getBean("user", User.class);
- 根据 Java 注解查找
- 单个 Bean 对象
- 集合 Bean 对象
3.2 Spring IoC 依赖注入:
- 根据 Bean 名称注入
- 根据 Bean 类型注入
- 单个 Bean 对象
- 集合 Bean 对象
- 注入容器內建 Bean 对象
- 注入非 Bean 对象
- 注入类型
- 实时注入
- 延迟注入
延迟查找和延迟注入,使用到接口 org.springframework.beans.factory.ObjectProvider
和 org.springframework.beans.factory.ObjectFactory
,ObjectProvider
继承 ObjectFactory
BeanFactory
和 ApplicationContext
谁才是 Spring IoC 容器?
BeanFactory
是 Spring 底层 IoC 容器ApplicationContext
是具备应用特性的BeanFactory
超集BeanFactory
是基本的 IoC 容器,ApplicationContext
实现BeanFactory
接口,并在内部使用ConfigurableListableBeanFactory
实现接口方法。
3.3 ApplicationContext 除了 IoC 容器角色,还有提供:
- 面向切面(AOP)
- 配置元信息(Configuration Metadata)
- 资源管理(Resources)
- 事件(Events)
- 国际化(i18n)
- 注解(Annotations)
- Environment 抽象(Environment Abstraction)
第四章:Spring Bean 基础
什么是 BeanDefinition
?
org.springframework.beans.factory.config.BeanDefinition
BeanDefinition
是 Spring Framework 中定义 Bean 的配置元信息接口,包含:- Bean 的类名
- Bean 行为配置元素,如作用域、自动绑定的模式,生命周期回调等
- 其他 Bean 引用,又可称作合作者(collaborators)或者依赖(dependencies)
- 配置设置,比如 Bean 属性(Properties)
- BeanDefinition 构建
- 通过
BeanDefinitionBuilder
- 通过
AbstractBeanDefinition
以及派生类
- 通过
Bean 名称生成器:org.springframework.beans.factory.support.BeanNameGenerator
注册 Spring Bean:
- BeanDefinition 注册
- XML 配置元信息
<bean ... />
- Java 注解配置元信息
@Bean
@Component
@Import
- Java API 配置元信息
- 命名方式:
BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)
- 非命名方式:
BeanDefinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition,Be
anDefinitionRegistry)
- 配置类方式:
AnnotatedBeanDefinitionReader#register(Class...)
- 命名方式:
- XML 配置元信息
- 外部单例对象注册
- Java API 配置元信息
SingletonBeanRegistry#registerSingleton
- Java API 配置元信息
Bean 实例化(Instantiation)
- 常规方式
- 通过构造器(配置元信息:XML、Java 注解和 Java API )
- 通过静态工厂方法(配置元信息:XML 和 Java API )
- 通过 Bean 工厂方法(配置元信息:XML 和 Java API )
- 通过
FactoryBean
(配置元信息:XML、Java 注解和 Java API )
- 特殊方式
- 通过
ServiceLoaderFactoryBean
(配置元信息:XML、Java 注解和 Java API ) - 通过
AutowireCapableBeanFactory#createBean(java.lang.Class, int, boolean)
- 通过
BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)
- 通过
Bean 初始化(Initialization),同时存在时,顺序从上到下:
@PostConstruct
标注方法- 实现
InitializingBean
接口的afterPropertiesSet()
方法 - 自定义初始化方法(
BeanDefinition
)- XML 配置:
<bean init-method=”init” ... />
- Java 注解:
@Bean(initMethod=”init”)
- Java API:
AbstractBeanDefinition#setInitMethodName(String)
- XML 配置:
Bean 延迟初始化(Lazy Initialization)
- XML 配置:
<bean lazy-init=”true” ... />
- Java 注解:
@Lazy(true)
Bean 销毁(Destroy),同时存在时,顺序从上到下:
@PreDestroy
标注方法- 实现
DisposableBean
接口的destroy()
方法 - 自定义销毁方法
- XML 配置:
<bean destroy=”destroy” ... />
- Java 注解:
@Bean(destroy=”destroy”)
- Java API:
AbstractBeanDefinition#setDestroyMethodName(String)
- XML 配置:
第五章:Spring IoC 依赖查找
单一类型依赖查找接口 - BeanFactory
- 根据 Bean 名称查找
getBean(String)
- Spring 2.5 覆盖默认参数:
getBean(String,Object...)
- 根据 Bean 类型查找
- Bean 实时查找
- Spring 3.0 :
getBean(Class)
- Spring 4.1 覆盖默认参数:
getBean(Class,Object...)
- Spring 3.0 :
- Spring 5.1 Bean 延迟查找
getBeanProvider(Class)
getBeanProvider(ResolvableType)
- Bean 实时查找
- 根据 Bean 名称 + 类型查找:
getBean(String,Class)
集合类型依赖查找接口 - ListableBeanFactory
- 根据 Bean 类型查找
- 获取同类型 Bean 名称列表
getBeanNamesForType(Class)
- Spring 4.2
getBeanNamesForType(ResolvableType)
- 获取同类型 Bean 实例列表
getBeansOfType(Class)
以及重载方法
- 获取同类型 Bean 名称列表
- 通过注解类型查找
- Spring 3.0 获取标注类型 Bean 名称列表
getBeanNamesForAnnotation(Class<? extends Annotation>)
- Spring 3.0 获取标注类型 Bean 实例列表
getBeansWithAnnotation(Class<? extends Annotation>)
- Spring 3.0 获取指定名称 + 标注类型 Bean 实例
findAnnotationOnBean(String,Class<? extends Annotation>)
- Spring 3.0 获取标注类型 Bean 名称列表
层次性依赖查找接口 - HierarchicalBeanFactory
- 双亲 BeanFactory:
getParentBeanFactory()
- 层次性查找
- 根据 Bean 名称查找
- 基于
containsLocalBean
方法实现
- 基于
- 根据 Bean 类型查找实例列表
- 单一类型:
BeanFactoryUtils#beanOfType
- 集合类型:
BeanFactoryUtils#beansOfTypeIncludingAncestors
- 单一类型:
- 根据 Java 注解查找名称列表
BeanFactoryUtils#beanNamesForTypeIncludingAncestors
- 根据 Bean 名称查找
Bean 延迟依赖查找接口
org.springframework.beans.factory.ObjectFactory
org.springframework.beans.factory.ObjectProvider
- Spring 5 对 Java 8 特性扩展
- 函数式接口
getIfAvailable(Supplier)
ifAvailable(Consumer)
- Stream 扩展 -
stream()
- 函数式接口
- Spring 5 对 Java 8 特性扩展
依赖查找安全性对比:
依赖查找类型 | 代表实现 | 是否安全 |
---|---|---|
单一类型查找 | BeanFactory#getBean | 否 |
ObjectFactory#getObject | 否 | |
ObjectProvider#getIfAvailable | 是 | |
集合类型查找 | ListableBeanFactory#getBeansOfType | 是 |
ObjectProvider#stream | 是 |
注意:层次性依赖查找的安全性取决于其扩展的单一或集合类型的 BeanFactory 接口
AbstractApplicationContext 内建可查找的依赖
Bean 名称 | Bean 实例 | 使用场景 |
---|---|---|
environment | Environment 对象 | 外部化配置以及 Profiles |
systemProperties | java.util.Properties 对象 | Java 系统属性 |
systemEnvironment | java.util.Map 对象 | 操作系统环境变量 |
messageSource | MessageSource 对象 | 国际化文案 |
lifecycleProcessor | LifecycleProcessor 对象 | Lifecycle Bean 处理器 |
applicationEventMulticaster | ApplicationEventMulticaster 对 象 | Spring 事件广播器 |
注解驱动 Spring 应用上下文内建可查找的依赖
Bean 名称 | Bean 实例 | 使用场景 |
---|---|---|
org.springframework.context.annotation.internalConfigurationAnnotationProcessor | ConfigurationClassPostProcesso | 处理 Spring 配置类 |
org.springframework.context.annotation.internalAutowiredAnnotationProcessor | AutowiredAnnotationBeanPostProcessor 对象 | 处理 @Autowired 以及 @Value 注解 |
org.springframework.context.annotation.internalCommonAnnotationProcessor | CommonAnnotationBeanPostProcessor 对象 | (条件激活)处理 JSR-250 注解,如 @PostConstruct 等 |
org.springframework.context.event.internalEventListenerProcessor | EventListenerMethodProcessor 对象 | 处理标注 @EventListener 的 Spring 事件监听方法 |
org.springframework.context.event.internalEventListenerFactory | DefaultEventListenerFactory 对象 | @EventListener 事件监听方法适配为 ApplicationListener |
org.springframework.context.annotation.internalPersistenceAnnotationProcessor | PersistenceAnnotationBeanPostProcessor 对象 | (条件激活)处理 JPA 注解场景 |
依赖查找中的经典异常,BeansException
子类型
异常类型 | 触发条件(举例) | 场景举例 |
---|---|---|
NoSuchBeanDefinitionException | 当查找 Bean 不存在于 IoC 容器时 BeanFactory#getBean | ObjectFactory#getObject |
NoUniqueBeanDefinitionException | 类型依赖查找时,IoC 容器存在多个 Bean 实例 | BeanFactory#getBean(Class) |
BeanInstantiationException | 当 Bean 所对应的类型非具体类时 | BeanFactory#getBean |
BeanCreationException | 当 Bean 初始化过程中 | Bean 初始化方法执行异常时 |
BeanDefinitionStoreException | 当 BeanDefinition 配置元信息非法时 | XML 配置资源无法打开时 |
BeanFactory.getBean
方法的执行是线程安全的,超过过程中会增加互斥锁
第六章:Spring IoC 依赖注入(Dependency Injection)
依赖注入的模式和类型
- 手动模式 - 配置或者编程的方式,提前安排注入规则
- XML 资源配置元信息
- Java 注解配置元信息
- API 配置元信息
- 自动模式 - 实现方提供依赖自动关联的方式,按照內建的注入规则
- Autowiring(自动绑定)
依赖注入类型
依赖注入类型 | 配置元数据举例 |
---|---|
Setter 方法 | <proeprty /> |
构造器 | <constructor-arg /> |
字段 | @Autowired User user; |
方法 | @Autowired public void user(User user) { ... } |
接口回调 | class MyBean implements BeanFactoryAware { ... } |
自动绑定(Autowiring)模式,Autowiring modes
参考枚举:org.springframework.beans.factory.annotation.Autowire
模式 | 说明 |
---|---|
no | 默认值,未激活 Autowiring,需要手动指定依赖注入对象。 |
byName | 根据被注入属性的名称作为 Bean 名称进行依赖查找,并将对象设置到该属性。 |
byType | 根据被注入属性的类型作为依赖类型进行查找,并将对象设置到该属性。 |
constructor | 特殊 byType 类型,用于构造器参数。 |
Java 注解配置元信息
@Autowired
@Resource
@Inject
可选,需要环境中存在 JSR-330 依赖
1
2
3
4
5<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>@Bean
Aware 系列接口回调
內建接口 | 说明 |
---|---|
BeanFactoryAware | 获取 IoC 容器 - BeanFactory |
ApplicationContextAware | 获取 Spring 应用上下文 - ApplicationContext 对象 |
EnvironmentAware | 获取 Environment 对象 |
ResourceLoaderAware | 获取资源加载器 对象 - ResourceLoader |
BeanClassLoaderAware | 获取加载当前 Bean Class 的 ClassLoader |
BeanNameAware | 获取当前 Bean 的名称 |
MessageSourceAware | 获取 MessageSource 对象,用于 Spring 国际化 |
ApplicationEventPublisherAware | 获取 ApplicationEventPublishAware 对象,用于 Spring 事件 |
EmbeddedValueResolverAware | 获取 StringValueResolver 对象,用于占位符处理 |
依赖注入类型选择
- 低依赖:构造器注入
- 多依赖:Setter 方法注入
- 便利性:字段注入
- 声明类:方法注入
各种类型注入:
基础类型
- 原生类型(Primitive):boolean、byte、char、short、int、float、long、double
- 标量类型(Scalar):Number、Character、Boolean、Enum、Locale、Charset、Currency、Properties、UUID
- 常规类型(General):Object、String、TimeZone、Calendar、Optional 等
- Spring 类型:Resource、InputSource、Formatter 等
集合类型
- 数组类型(Array):原生类型、标量类型、常规类型、Spring 类型
- 集合类型(Collection)
- Collection:List、Set(SortedSet、NavigableSet、EnumSet)
- Map:Properties
限定注入
- 使用注解 @Qualifier 限定
- 通过 Bean 名称限定
- 通过分组限定
- 基于注解 @Qualifier 扩展限定
- 自定义注解,如 Spring Cloud @LoadBalanced
- 使用注解 @Qualifier 限定
延迟依赖注入
使用 API ObjectFactory 延迟注入
- 单一类型
- 集合类型
使用 API ObjectProvider 延迟注入(推荐)
- 单一类型
- 集合类型
依赖处理过程
- 入口 -
DefaultListableBeanFactory#resolveDependency
- 依赖描述符 - DependencyDescriptor
- 自定绑定候选对象处理器 - AutowireCandidateResolver
@Autowired、@Inject 注入,参考 AutowiredAnnotationBeanPostProcessor
Java 通用注解注入原理:
CommonAnnotationBeanPostProcessor
- 注入注解
- javax.xml.ws.WebServiceRef
- javax.ejb.EJB
- javax.annotation.Resource
- 生命周期注解
- javax.annotation.PostConstruct
- javax.annotation.PreDestroy
自定义依赖注入注解
基于
AutowiredAnnotationBeanPostProcessor
实现自定义实现
- 生命周期处理
- InstantiationAwareBeanPostProcessor
- MergedBeanDefinitionPostProcessor
- 元数据
- InjectedElement
- InjectionMetadata
- 生命周期处理
org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
@Autowired
@Value
@Inject
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
@PostConstruct
@PreDestroy
初始化 Bean 时,AutowiredAnnotationBeanPostProcessor
先解析 Bean 中的依赖(@Autowire
,@Value
),然后 CommonAnnotationBeanPostProcessor
调用初始化方法 @@PostConstruct
将 @Bean
方法设置为 static
,可以让 Bean 提前初始化。
依赖查找:
ApplicationContext#getBean
依赖处理过程:
org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency
第七章:Spring IoC 依赖来源(Dependency Sources)
Spring IoC 依赖来源
来源 | 配置元数据 | 注册 API | Spring Bean 对象 | 生命周期管理 | 配置元信息 | 使用场景 |
---|---|---|---|---|---|---|
Spring BeanDefinition | <bean> @Bean public User user(){...} BeanDefinitionBuilder | BeanDefinitionRegistry#registerBeanDefinition | 是 | 是 | 有 | 依赖查找、依赖注入 |
单例对象 | API 实现 | SingletonBeanRegistry#registerSingleton | 是 | 否 | 无 | 依赖查找、依赖注入 |
非 Spring 容器管理对象 | Resolvable Dependency | ConfigurableListableBeanFactory#registerResolvableDependency | 否 | 否 | 无 | 依赖注入 |
外部化配置 | @Value | Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor); | 否 | 否 | 无 | 依赖注入 |
依赖注入比依赖查找多一个来源,Resolvable Dependency。也就是说,可以通过注入的方式获取这类对象,但不能通过 BeanFactory#getBean
方法从容器中获取。
Spring 內建 BeanDefintion
在使用 AnnotationConfigApplicationContext
或者在 XML 配置中配置了注解驱动 <context:annotation-config/>
,或组件扫描 <context:component-scan base-package="org.acme" />
,会触发org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors
注入一些 Spring 内建的 Bean:
org.springframework.context.annotation.ConfigurationClassPostProcessor
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor
需要环境中有 JPA 依赖
org.springframework.context.event.EventListenerMethodProcessor
org.springframework.context.event.DefaultEventListenerFactory
Spring 內建单例对象
Spring 启动时,refresh()
方法会调用 org.springframework.context.support.AbstractApplicationContext#prepareBeanFactory
,会注入一些单例对象,名称为:
environment
systemProperties
systemEnvironment
单例对象由 org.springframework.beans.factory.config.SingletonBeanRegistry
注册,org.springframework.beans.factory.support.AbstractBeanFactory
实现了这个接口,从容器中获取 Bean 的方法 org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
中,会先从单例对象中查找,如果查找到,直接返回;查找不到,则从 Spring BeanDefinition 中获取,并执行生命周期函数
Resolvable Dependency / 非 Spring 容器管理对象 / 可解析依赖
org.springframework.context.support.AbstractApplicationContext#prepareBeanFactory
1 |
|
后三个实际上都是同一个 ApplicationContext
order 值越大,优先级越小
第八章:Spring Bean 作用域
作用域 | 说明 |
---|---|
singleton | 默认 Spring Bean 作用域,一个 BeanFactory 有且仅有一个实例 |
prototype | 原型作用域,每次依赖查找和依赖注入生成新 Bean 对象 |
request | 将 Spring Bean 存储在 ServletRequest 上下文中 |
session | 将 Spring Bean 存储在 HttpSession 中 |
application | 将 Spring Bean 存储在 ServletContext 中 |
注意事项:
- Spring 容器没有办法管理 prototype Bean 的完整生命周期,也没有办法记录示例的存
在。销毁回调方法将不会执行,可以利用 BeanPostProcessor 进行清扫工作。 - 无论是 Singleton 还是 Prototype Bean 均会执行初始化方法回调,不过仅 Singleton Bean 会执行销毁方法回调
@Scope
注解定义原型 Bean :
1 |
|
“request” Bean 作用域
- XML -
<bean class= "..." scope = "request" />
- Java 注解 -
@RequestScope
或@Scope(WebApplicationContext.SCOPE_REQUEST)
每次使用的 CGLIB 代理对象是同一个,但是被代理的对象每次都会重新生成。
使用 IDEA 进行远程调试:
- 在 Edit Configurations 中新增一个 Remote ,使用命令启动 jar 时,在启动命令中增加 Remote 里的内容,启动 jar 以及 Remote,打断点进行调试。
实现 API
@RequestScope
RequestScope
“session” Bean 作用域
配置
- XML -
<bean class= "..." scope = "session" />
- Java 注解 -
@RequestScope
或@Scope(WebApplicationContext.SCOPE_REQUEST)
实现 API
@SessionScope
SessionScope
“application” Bean 作用域
配置
- XML -
<bean class= "..." scope = "application" />
- Java 注解 -
@ApplicationScope
或@Scope(WebApplicationContext.SCOPE_APPLICATION)
实现 API
@ApplicationScope
ServletContextScope
实现方式与 request 和 session 不同,这里直接将 Bean 放入 ServletContext
中
自定义 Bean 作用域
实现 Scope
org.springframework.beans.factory.config.Scope
注册 Scope
API
org.springframework.beans.factory.config.ConfigurableBeanFactory#registerScope
配置
1
2
3
4
5
6
7
8<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property >
<map>
<entry key="...">
</entry>
</map>
</property>
</bean>
第九章:Spring Bean 生命周期(Bean Lifecycle)
Spring Bean 元信息配置阶段
BeanDefinition 配置
- 面向资源
- XML 配置
- Properties 资源配置
- 面向注解
- 面向 API
Spring Bean 元信息解析阶段
BeanDefinition 解析
- 面向资源 BeanDefinition 解析 -
BeanDefinitionReader
- XML 解析器 -
XmlBeanDefinitionReader
- Properties 解析器 -
PropertiesBeanDefinitionReader
- XML 解析器 -
- 面向注解 BeanDefinition 解析 -
AnnotatedBeanDefinitionReader
Spring Bean 注册阶段
BeanDefinition 注册接口
BeanDefinitionRegistry
Spring BeanDefinition 合并阶段
BeanDefinition 合并
父子 BeanDefinition 合并
- 当前 BeanFactory 查找
- 层次性 BeanFactory 查找
1 |
|
XmlBeanDefinitionReader#loadBeanDefinitions
加载 XML 文件时,赋值 DefaultListableBeanFactory#beanDefinitionMap
,这个 Map 中的 BeanDefinition
还没有合并,也就是说 superUser 的属性值还没有从 user 中继承过来。
AbstractBeanFactory#getBean
获取 bean 时,执行 AbstractBeanFactory#getMergedBeanDefinition
,对 superUser 进行合并,放入 AbstractBeanFactory#mergedBeanDefinitions
中。
Spring Bean Class 加载阶段
- ClassLoader 类加载
- Java Security 安全控制
- ConfigurableBeanFactory 临时 ClassLoader
AbstractBeanDefinition#beanClass
被定义为 Object ,有两种形式,一种是 全类名 的 String,另一种是 Class 对象
Java Security 安全控制 相关
1 |
|
临时 ClassLoader 与 load-time weaving 技术有关,用于进行类型检查时(即尚未创建实际实例)
Spring Bean 实例化阶段
传统实例化方式
- 实例化策略 - InstantiationStrategy
构造器依赖注入
实例化阶段,如果使用构造器注入,将解析构造器注入的依赖
AbstractAutowireCapableBeanFactory#createBeanInstance
Spring Bean 实例化前阶段
- 非主流生命周期 - Bean 实例化前阶段
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
返回非 null 时,阻止 bean 的默认实例化过程及以下生命周期
唯一可以进一步生命周期处理的是 BeanPostProcessor#postProcessAfterInitialization
Spring Bean 实例化后阶段
- Bean 属性赋值(Populate)判断
InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
在给 bean 实例做属性赋值的方法 AbstractAutowireCapableBeanFactory#populateBean
的最开始调用,如果返回 false ,阻止 bean 的属性赋值及以下生命周期
Spring Bean 属性赋值前阶段
Bean 属性值元信息
- PropertyValues
Bean 属性赋值前回调
Spring 1.2 - 5.0:
InstantiationAwareBeanPostProcessor#postProcessPropertyValues
此方法已过期,使用
postProcessProperties
替代,为了兼容,只有在postProcessProperties
返回 null 时(默认实现),才会调用此方法Spring 5.1:
InstantiationAwareBeanPostProcessor#postProcessProperties
在工厂将给定属性值应用于给定 bean 之前,对它们进行处理。
在依赖注入( byName
或 byType
)之后,在将配置的属性赋值给 bean 实例 AbstractAutowireCapableBeanFactory#applyPropertyValues
之前执行此阶段方法
Spring Bean 初始化阶段
AbstractAutowireCapableBeanFactory#initializeBean
Spring Bean Aware 接口回调阶段
Spring Aware 接口,执行顺序从上到下
BeanNameAware
BeanClassLoaderAware
BeanFactoryAware
依赖于 ApplicationContext
:
EnvironmentAware
EmbeddedValueResolverAware
ResourceLoaderAware
ApplicationEventPublisherAware
MessageSourceAware
ApplicationContextAware
在初始化 Bean 实例 AbstractAutowireCapableBeanFactory#initializeBean
的最开始执行此阶段,前三个接口直接调用,而依赖于 ApplicationContext 的几个 Aware 接口,在 ApplicationContext 的生命周期中,会在 beanFactory 中加入 ApplicationContextAwareProcessor
,在其 postProcessBeforeInitialization
方法中执行调用
ApplicationContextAwareProcessor
是包权限的
Spring Bean 初始化前阶段
已完成
Bean 实例化
Bean 属性赋值
Bean Aware 接口回调
方法回调
BeanPostProcessor#postProcessBeforeInitialization
Spring Bean 初始化阶段
Bean 初始化(Initialization)
@PostConstruct
标注方法- 实现
InitializingBean
接口的afterPropertiesSet()
方法 - 自定义初始化方法
对 @PostConstruct
的处理需要依赖于注解驱动,CommonAnnotationBeanPostProcessor#postProcessBeforeInitialization
Spring Bean 初始化后阶段
方法回调
BeanPostProcessor#postProcessAfterInitialization
Spring Bean 初始化完成阶段
方法回调
- Spring 4.1 +:
SmartInitializingSingleton#afterSingletonsInstantiated
SmartInitializingSingleton
通常在 Spring ApplicationContext 场景使用
使用 BeanFactory
时,需要显式的调用此方法;在 ApplicationContext
启动时,调用了此方法 AbstractApplicationContext#finishBeanFactoryInitialization
,这个方法做了两件事情:
- 将已注册的
BeanDefinition
初始化成 Spring Bean - 调用所有
SmartInitializingSingleton#afterSingletonsInstantiated
Spring Bean 销毁前阶段
- 方法回调
DestructionAwareBeanPostProcessor#postProcessBeforeDestruction
执行 ConfigurableBeanFactory#destroyBean
时,触发 Bean 前销毁阶段
对 @PreDestroy
的处理需要依赖于注解驱动,CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction
Spring Bean 销毁阶段
Bean 销毁(Destroy)
@PreDestroy
标注方法- 实现
DisposableBean
接口的destroy()
方法 - 自定义销毁方法
对 @PreDestroy
的处理需要依赖于注解驱动,CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction
CommonAnnotationBeanPostProcessor
是 DestructionAwareBeanPostProcessor
的实现类之一
如果其他 DestructionAwareBeanPostProcessor
排序在 CommonAnnotationBeanPostProcessor
后,会先执行 @PreDestroy
标注方法,后执行其他 DestructionAwareBeanPostProcessor
销毁前阶段方法
Spring Bean 垃圾收集
Bean 垃圾回收(GC)
- 关闭 Spring 容器(应用上下文)
- 执行 GC
- Spring Bean 覆盖的
finalize()
方法被回调
面试题
BeanPostProcessor 的使用场景有哪些?
答:BeanPostProcessor
提供 Spring Bean 初始化前和初始化后的生命周期回调,分别对应 postProcessBeforeInitialization
以及 postProcessAfterInitialization
方法,允许对关心的 Bean 进行扩展,甚至是替换。
加分项:其中,ApplicationContext
相关的 Aware
回调也是基于 BeanPostProcessor
实现,即 ApplicationContextAwareProcessor
。
BeanFactoryPostProcessor 与 BeanPostProcessor 的区别
答:BeanFactoryPostProcessor
是 Spring BeanFactory
(实际为 ConfigurableListableBeanFactory
) 的后置处理器,用于扩展 BeanFactory
,或通过 BeanFactory
进行依赖查找和依赖注入。
加分项:BeanFactoryPostProcessor
必须有 Spring ApplicationContext
执行,BeanFactory
无法与其直接交互。而 BeanPostProcessor
则直接与 BeanFactory
关联,属于 N 对 1 的关系。
BeanFactory 是怎样处理 Bean 生命周期?
BeanFactory
的默认实现为 DefaultListableBeanFactory
,其中 Bean 生命周期与方法映射如下:
- BeanDefinition 注册阶段 -
registerBeanDefinition
- BeanDefinition 合并阶段 -
getMergedBeanDefinition
- Bean 实例化前阶段 -
resolveBeforeInstantiation
- Bean 实例化阶段 -
createBeanInstance
- Bean 实例化后阶段 -
populateBean
- Bean 属性赋值前阶段 -
populateBean
- Bean 属性赋值阶段 -
populateBean
- Bean Aware 接口回调阶段 -
initializeBean
- Bean 初始化前阶段 -
initializeBean
- Bean 初始化阶段 -
initializeBean
- Bean 初始化后阶段 -
initializeBean
- Bean 初始化完成阶段 -
preInstantiateSingletons
- Bean 销毁前阶段 -
destroyBean
- Bean 销毁阶段 -
destroyBean
第十章:Spring 配置元信息(Configuration Metadata)
Spring 配置元信息
- Spring Bean 配置元信息 -
BeanDefinition
- Spring Bean 属性元信息 -
PropertyValues
- Spring 容器配置元信息
- Spring 外部化配置元信息 -
PropertySource
- Spring Profile 元信息 -
@Profile
Spring Bean 配置元信息
Bean 配置元信息 - BeanDefinition
GenericBeanDefinition
:通用型BeanDefinition
RootBeanDefinition
:无 Parent 的BeanDefinition
或者合并后BeanDefinition
AnnotatedBeanDefinition
:注解标注的BeanDefinition
Spring Bean 属性元信息
- Bean 属性元信息 -
PropertyValues
- 可修改实现 -
MutablePropertyValues
- 元素成员 -
PropertyValue
- 可修改实现 -
- Bean 属性上下文存储 -
AttributeAccessor
- Bean 元信息元素 -
BeanMetadataElement
AttributeAccessorSupport#attributes
是附加属性(不影响 Bean populate、initialize)
BeanMetadataAttributeAccessor#source
存储当前 BeanDefinition 来自于何方(辅助作用)
Spring 容器配置元信息
Spring XML 配置元信息 - beans 元素相关
beans 元素属性 | 默认值 | 使用场景 |
---|---|---|
profile | null(留空) | Spring Profiles 配置值 |
default-lazy-init | default | 当 outter beans “default-lazy-init” 属性存在时,继承该值,否则为 “false” |
default-merge | default | 当 outter beans “default-merge” 属性存在时,继承该值,否则为 “false” |
default-autowire | default | 当 outter beans “default-autowire” 属性存在时,继承该值,否则为 “no” |
default-autowire-candidates | null(留空) | 默认 Spring Beans 名称 pattern |
default-init-method | null(留空) | 默认 Spring Beans 自定义初始化方法 |
default-destroy-method | null(留空) | 默认 Spring Beans 自定义销毁方法 |
Spring XML 配置元信息 - 应用上下文相关
XML 元素 | 使用场景 |
---|---|
<context:annotation-config /> | 激活 Spring 注解驱动 |
<context:component-scan /> | Spring @Component 以及自定义注解扫描 |
<context:load-time-weaver /> | 激活 Spring LoadTimeWeaver |
<context:mbean-export /> | 暴露 Spring Beans 作为 JMX Beans |
<context:mbean-server /> | 将当前平台作为 MBeanServer |
<context:property-placeholder /> | 加载外部化配置资源作为 Spring 属性配置 |
<context:property-override /> | 利用外部化配置资源覆盖 Spring 属性值 |
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate
populateDefaults
基于 XML 资源装载 Spring Bean 配置元信息
XML 元素 | 使用场景 |
---|---|
<beans:beans /> | 单 XML 资源下的多个 Spring Beans 配置 |
<beans:bean /> | 单个 Spring Bean 定义(BeanDefinition)配置 |
<beans:alias /> | 为 Spring Bean 定义(BeanDefinition)映射别名 |
<beans:import /> | 加载外部 Spring XML 配置资源 |
底层实现 - XmlBeanDefinitionReader
加载 BeanDefinition 入口方法 loadBeanDefinitions
使用 DOM 来解析 XML 文件,实现为 BeanDefinitionDocumentReader
解析方法:XmlBeanDefinitionReader#parseBeanDefinitions
- 判断 beans 标签的 profile 属性,如果不在激活状态,直接返回,不再向下解析
- 如果是 beans 标签下的特殊元素,进行特殊处理,方法为
DefaultBeanDefinitionDocumentReader#parseDefaultElement
- beans
- bean
- alias
- import
- 否则,
BeanDefinitionParserDelegate#parseCustomElement
基于 Properties 资源装载 Spring Bean 配置元信息
Properties 属性名 | 使用场景 |
---|---|
(class) | Bean 类全称限定名 |
(abstract) | 是否为抽象的 BeanDefinition |
(parent) | 指定 parent BeanDefinition 名称 |
(lazy-init) | 是否为延迟初始化 |
(ref) | 引用其他 Bean 的名称 |
(scope) | 设置 Bean 的 scope 属性 |
${n} | n 表示第 n+1 个构造器参数 |
底层实现 - PropertiesBeanDefinitionReader
如果出现重复的 Bean 定义,后者不会被注册进 BeanFactory
中
基于 Java 注解装载 Spring Bean 配置元信息
Spring 模式注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@Repository | 数据仓储模式注解 | 2.0 |
@Component | 通用组件模式注解 | 2.5 |
@Service | 服务模式注解 | 2.5 |
@Controller | Web 控制器模式注解 | 2.5 |
@Configuration | 配置类模式注解 | 3.0 |
org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#registerDefaultFilters
将 @Component
及其派生注解加入筛选
Spring Bean 定义注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@Bean | 替换 XML 元素 <bean> | 3.0 |
@DependsOn | 替代 XML 属性 <bean depends-on="..."/> | 3.0 |
@Lazy | 替代 XML 属性 <bean lazy-init="true|falses" /> | 3.0 |
@Primary | 替换 XML 元素 <bean primary="true|false" /> | 3.0 |
@Role | 替换 XML 元素 <bean role="..." /> | 3.1 |
@Lookup | 替代 XML 属性 <bean lookup-method="..."> | 4.1 |
Spring Bean 依赖注入注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@Autowired | Bean 依赖注入,支持多种依赖查找方式 | 2.5 |
@Qualifier | 细粒度的 @Autowired 依赖查找 | 2.5 |
AutowiredAnnotationBeanPostProcessor
与 @Autowired
相关
Java 注解 | 场景说明 | 起始版本 |
---|---|---|
@Resource | 类似于 @Autowired | 2.5 |
@Inject | 类似于 @Autowired | 2.5 |
CommonAnnotationBeanPostProcessor
与 @Resource
相关
AutowiredAnnotationBeanPostProcessor
与 @Inject
相关
Spring Bean 条件装配注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@Profile | 配置化条件装配 | 3.1 |
@Conditional | 编程条件装配 | 4.0 |
@Profile
基于 @Conditional
实现
@Conditional
相关 API,ConditionEvaluator
,用于判断 Bean 是否满足条件,满足则注册
Spring Bean 生命周期回调注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@PostConstruct | 替换 XML 元素 <bean init-method="..." /> 或 InitializingBean | 2.5 |
@PreDestroy | 替换 XML 元素 <bean destroy-method="..." /> 或 DisposableBean | 2.5 |
CommonAnnotationBeanPostProcessor
Spring Bean 配置元信息底层实现
Spring BeanDefinition 解析与注册
实现场景 | 实现类 | 起始版本 |
---|---|---|
XML 资源 | XmlBeanDefinitionReader | 1.0 |
Properties 资源 | PropertiesBeanDefinitionReader | 1.0 |
Java 注解 | AnnotatedBeanDefinitionReader | 3.0 |
XmlBeanDefinitionReader
和PropertiesBeanDefinitionReader
都继承自AbstractBeanDefinitionReader
,实现了BeanDefinitionReader
接口,与资源(Resource)相关联AnnotatedBeanDefinitionReader
是独立的类,与Resource
无关Spring XML 资源 BeanDefinition 解析与注册
- 核心 API -
XmlBeanDefinitionReader
- 资源 - Resource
- 底层 -
BeanDefinitionDocumentReader
- XML 解析 - Java DOM Level 3 API
- BeanDefinition 解析 -
BeanDefinitionParserDelegate
- BeanDefinition 注册 -
BeanDefinitionRegistry
- 核心 API -
Spring Properties 资源 BeanDefinition 解析与注册
- 核心 API -
PropertiesBeanDefinitionReader
- 资源
- 字节流 -
Resource
- 字符流 -
EncodedResouce
- 字节流 -
- 底层
- 存储 -
java.util.Properties
- BeanDefinition 解析 - API 内部实现
- BeanDefinition 注册 -
BeanDefinitionRegistry
- 存储 -
- 资源
- 核心 API -
Spring Java 注册 BeanDefinition 解析与注册
- 核心 API -
AnnotatedBeanDefinitionReader
- 资源
- 类对象 -
java.lang.Class
- 类对象 -
- 底层
- 条件评估 -
ConditionEvaluator
- Bean 范围解析 -
ScopeMetadataResolver
- BeanDefinition 解析 - 内部 API 实现
- BeanDefinition 处理 -
AnnotationConfigUtils.processCommonDefinitionAnnotations
- BeanDefinition 注册 -
BeanDefinitionRegistry
- 条件评估 -
- 资源
- 核心 API -
Properties
资源加载默认编码是 ISO-8859-1
AnnotatedBeanDefinitionReader
使用 ConditionEvaluator
判断 Bean 的元信息,如果其中存在 @Conditional
条件,判断此条件通过才会将 Bean 加入容器
基于 XML 资源装载 Spring IoC 容器配置元信息
Spring IoC 容器相关 XML 配置
命名空间 | 所属模块 | Schema 资源 URL |
---|---|---|
beans | spring-beans | https://www.springframework.org/schema/beans/spring-beans.xsd |
context | spring-context | https://www.springframework.org/schema/context/spring-context.xsd |
aop | spring-aop | https://www.springframework.org/schema/aop/spring-aop.xsd |
tx | spring-tx | https://www.springframework.org/schema/tx/spring-tx.xsd |
util | spring-beans | https://www.springframework.org/schema/util/spring-util.xsd |
tool | spring-beans | https://www.springframework.org/schema/tool/spring-tool.xsd |
基于 Java 注解装载 Spring IoC 容器配置元信息
Spring IoC 容器装配注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@ImportResource | 替换 XML 元素 <import> | 3.0 |
@Import | 导入 Configuration Class | 3.0 |
@ComponentScan | 扫描指定 package 下标注 Spring 模式注解的类 | 3.1 |
Spring IoC 配属属性注
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@PropertySource | 配置属性抽象 PropertySource 注解 | 3.1 |
@PropertySources | @PropertySource 集合注解 | 4.0 |
基于 Extensible XML authoring 扩展 Spring XML 元素
Spring XML 扩展
- 编写 XML Schema 文件:定义 XML 结构
- users.xsd
- 自定义
NamespaceHandler
实现:命名空间绑定- spring.handlers
org.geekbang.thinking.in.spring.configuration.metadata.UsersNamespaceHandler
- 自定义
BeanDefinitionParser
实现:XML 元素与BeanDefinition
解析org.geekbang.thinking.in.spring.configuration.metadata.UserBeanDefinitionParser
- 注册 XML 扩展:命名空间与 XML Schema 映射
- spring.schemas
- users-context.xml
触发时机:BeanDefinitionParserDelegate#parseCustomElement
- 获取 namespace
- 通过 namespace 解析
NamespaceHandler
- 构造
ParserContext
- 解析元素,获取
BeanDefinintion
基于 Properties 资源装载外部化配置
- 注解驱动
@org.springframework.context.annotation.PropertySource
@org.springframework.context.annotation.PropertySources
- API 编程
org.springframework.core.env.PropertySource
org.springframework.core.env.PropertySources
基于 YAML 资源装载外部化配置
API 编程
org.springframework.beans.factory.config.YamlProcessor
org.springframework.beans.factory.config.YamlMapFactoryBean
org.springframework.beans.factory.config.YamlPropertiesFactoryBean
Requires SnakeYAML 1.18 or higher, as of Spring Framework 5.0.6
通过 PropertySourceFactory 接口,引入 PropertySource
org.springframework.core.io.support.PropertySourceFactory
1 |
|
面试题
Spring 內建 XML Schema 常见有哪些?
命名空间 | 所属模块 | Schema 资源 URL |
---|---|---|
beans | spring-beans | https://www.springframework.org/schema/beans/spring-beans.xsd |
context | spring-context | https://www.springframework.org/schema/context/spring-context.xsd |
aop | spring-aop | https://www.springframework.org/schema/aop/spring-aop.xsd |
tx | spring-tx | https://www.springframework.org/schema/tx/spring-tx.xsd |
util | spring-beans | https://www.springframework.org/schema/util/spring-util.xsd |
tool | spring-beans | https://www.springframework.org/schema/tool/spring-tool.xsd |
Spring 配置元信息具体有哪些?
- Bean 配置元信息:通过媒介(如 XML、Proeprties 等),解析 BeanDefinition
- IoC 容器配置元信息:通过媒介(如 XML、Proeprties 等),控制 IoC 容器行为,比如注解驱动、AOP 等
- 外部化配置:通过资源抽象(如 Proeprties、YAML 等),控制 PropertySource
- Spring Profile:通过外部化配置,提供条件分支流程
Extensible XML authoring 的缺点?
- 高复杂度:开发人员需要熟悉 XML Schema,spring.handlers,spring.schemas 以及 Spring API 。
- 嵌套元素支持较弱:通常需要使用方法递归或者其嵌套解析的方式处理嵌套(子)元素。
- XML 处理性能较差:Spring XML 基于 DOM Level 3 API 实现,该 API 便于理解,然而性能较差。
- XML 框架移植性差:很难适配高性能和便利性的 XML 框架,如 JAXB。
第十一章:Spring 资源管理
引入动机
为什么 Spring 不使用 Java 标准资源管理,而选择重新发明轮子?
- Java 标准资源管理强大,然而扩展复杂,资源存储方式并不统一
- Spring 要自立门户(重要的话,要讲三遍)
- Spring “抄”、“超” 和 “潮”
Java 标准资源管理
Java 标准资源定位
职责 | 说明 |
---|---|
面向资源 | 文件系统、artifact(jar、war、ear 文件)以及远程资源(HTTP、FTP 等) |
API 整合 | java.lang.ClassLoader#getResource、java.io.File 或 java.net.URL |
资源定位 | java.net.URL 或 java.net.URI |
面向流式存储 | java.net.URLConnection |
协议扩展 | java.net.URLStreamHandler 或 java.net.URLStreamHandlerFactory |
Java URL 协议扩展
- 基于
java.net.URLStreamHandlerFactory
- 基于
java.net.URLStreamHandler
基于 java.net.URLStreamHandler 扩展协议
JDK 1.8 內建协议实现
协议 | 实现类 |
---|---|
file | sun.net.www.protocol.file.Handler |
ftp | sun.net.www.protocol.ftp.Handler |
http | sun.net.www.protocol.http.Handler |
https | sun.net.www.protocol.https.Handler |
jar | sun.net.www.protocol.jar.Handler |
mailto | sun.net.www.protocol.mailto.Handler |
netdoc | sun.net.www.protocol.netdoc.Handler |
实现类名必须为 Handler
实现类命名规则 | 说明 |
---|---|
默认 | sun.net.www.protocol.${protocol}.Handler |
自定义 | 通过 Java Properties java.protocol.handler.pkgs 指定实现类包名,实现类名必须为 Handler 。如果存在多包名指定,通过分隔符 | |
Spring 资源接口
类型 | 接口 |
---|---|
输入流 | org.springframework.core.io.InputStreamSource |
只读资源 | org.springframework.core.io.Resource |
可写资源 | org.springframework.core.io.WritableResource |
编码资源 | org.springframework.core.io.support.EncodedResource |
上下文资源 | org.springframework.core.io.ContextResource |
Spring 内建 Resource 实现
资源来源 | 资源协议 | 实现类 |
---|---|---|
Bean 定义 | 无 | org.springframework.beans.factory.support.BeanDefinitionResource |
数组 | 无 | org.springframework.core.io.ByteArrayResource |
类路径 | classpath:/ | org.springframework.core.io.ClassPathResource |
文件系统 | file:/ | org.springframework.core.io.FileSystemResource |
URL | URL 支持的协议 | org.springframework.core.io.UrlResource |
ServletContext | 无 | org.springframework.web.context.support.ServletContextResource |
Spring Resource 接口扩展
- 可写资源接口
org.springframework.core.io.WritableResource
org.springframework.core.io.FileSystemResource
org.springframework.core.io.FileUrlResource
(@since 5.0.2)org.springframework.core.io.PathResource
(@since 4.0 & @Deprecated)
- 编码资源接口
org.springframework.core.io.support.EncodedResource
Spring 资源加载器
Resource 加载器
org.springframework.core.io.ResourceLoader
org.springframework.core.io.DefaultResourceLoader
org.springframework.core.io.FileSystemResourceLoader
org.springframework.core.io.ClassRelativeResourceLoader
org.springframework.context.support.AbstractApplicationContext
Spring 通配路径资源加载器
- 通配路径 ResourceLoader
org.springframework.core.io.support.ResourcePatternResolver
org.springframework.core.io.support.PathMatchingResourcePatternResolver
- 路径匹配器
org.springframework.util.PathMatcher
- Ant 模式匹配实现 -
org.springframework.util.AntPathMatcher
- Ant 模式匹配实现 -
Spring 通配路径资源扩展
- 实现
org.springframework.util.PathMatcher
- 重置 PathMatcher
PathMatchingResourcePatternResolver#setPathMatcher
依赖注入 Spring Resource
基于 @Value
实现
1 |
|
依赖注入 ResourceLoader
- 方法一:实现
ResourceLoaderAware
回调 - 方法二:
@Autowired
注入ResourceLoader
- 方法三:注入
ApplicationContext
作为ResourceLoader
ApplicationContext
接口继承 ResourcePatternResolver
继承 ResourceLoader
ResourceLoaderAware
回调在 实例初始化(@PostConstruct
等)之前
面试题
Spring 配置资源中有哪些常见类型?
- XML 资源
- Properties 资源
- YAML 资源
请例举不同类型 Spring 配置资源?
- XML 资源
- 普通 Bean Definition XML 配置资源 -
*.xml
- Spring Schema 资源 -
*.xsd
- 普通 Bean Definition XML 配置资源 -
- Properties 资源
- 普通 Properties 格式资源 -
*.properties
- Spring Handler 实现类映射文件 -
META-INF/spring.handlers
- Spring Schema 资源映射文件 -
META-INF/spring.schemas
- 普通 Properties 格式资源 -
- YAML 资源
- 普通 YAML 配置资源 -
*.yaml
或*.yml
- 普通 YAML 配置资源 -
Java 标准资源管理扩展的步骤?
- 简易实现
- 实现
URLStreamHandler
并放置在sun.net.www.protocol.${protocol}.Handler
包下
- 实现
- 自定义实现
- 实现
URLStreamHandler
- 添加
-Djava.protocol.handler.pkgs
启动参数,指向URLStreamHandler
实现类的包下
- 实现
- 高级实现
- 实现
URLStreamHandlerFactory
并传递到 URL 之中
- 实现
简易实现实例
扩展 x 协议,新建类
sun.net.www.protocol.x.Handler
,类名格式必须符合规范1
2
3
4
5
6public class Handler extends URLStreamHandler {
@Override
protected URLConnection openConnection(URL u) throws IOException {
return new XURLConnection(u);
}
}新建类
XURLConnection
,实现java.net.URLConnection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public class XURLConnection extends URLConnection {
private final ClassPathResource resource;
// URL = x:///META-INF/default.properties
protected XURLConnection(URL url) {
super(url);
this.resource = new ClassPathResource(url.getPath());
}
@Override
public void connect() throws IOException {
}
public InputStream getInputStream() throws IOException {
return resource.getInputStream();
}
}测试使用
1
2
3
4
5
6
7
8public class HandlerTest {
public static void main(String[] args) throws IOException {
URL url = new URL("x:///META-INF/default.properties"); // 类似于 classpath:/META-INF/default.properties
InputStream inputStream = url.openStream();
System.out.println(StreamUtils.copyToString(inputStream, Charset.forName("UTF-8")));
}
}
自定义实现
新建类
Handler
,继承sun.net.www.protocol.x.Handle
,类名必须为Handler
,包名无限制1
2
3
4
5
6
7
8
9
10public class Handler extends sun.net.www.protocol.x.Handler {
// -Djava.protocol.handler.pkgs=org.geekbang.thinking.in.spring.resource
public static void main(String[] args) throws IOException {
// springx 协议
URL url = new URL("springx:///META-INF/production.properties"); // 类似于 classpath:/META-INF/default.properties
InputStream inputStream = url.openStream();
System.out.println(StreamUtils.copyToString(inputStream, Charset.forName("UTF-8")));
}
}运行时增加 VM 参数,
-Djava.protocol.handler.pkgs=org.geekbang.thinking.in.spring.resource
高级实现
1 |
|
本文由 简悦 SimpRead 转码, 原文地址 www.cnblogs.com
第十二章:Spring 国际化
Spring 国际化使用场景
- 普通国际化文案
- Bean Validation 校验国际化文案
- Web 站点页面渲染
- Web MVC 错误消息提示
Spring 国际化接口
- 核心接口 -
org.springframework.context.MessageSource
- 主要概念
- 文案模板编码(code)
- 文案模板参数(args)
- 区域(Locale)
层次性 MessageSource
- Spring 层次性接口回顾
org.springframework.beans.factory.HierarchicalBeanFactory
org.springframework.context.ApplicationContext
org.springframework.beans.factory.config.BeanDefinition
- Spring 层次性国际化接口
org.springframework.context.HierarchicalMessageSource
Java 国际化标准实现
核心接口
- 抽象类实现 -
java.util.ResourceBundle
- Properties 资源实现 -
java.util.PropertyResourceBundle
- 例举实现 -
java.util.ListResourceBundle
- Properties 资源实现 -
ResourceBundle
核心特性
- Key-Value 设计
- 键唯一地标识了包中特定于语言环境的对象
- value 就是 文案模板编码(code)
- 层次性设计
- 缓存设计
- 字符编码控制 -
java.util.ResourceBundle.Control
(@since 1.6) - Control SPI 扩展 -
java.util.spi.ResourceBundleControlProvider
(@since 1.8)
Java 文本格式化
核心接口 - java.text.MessageFormat
- 基本用法
- 设置消息格式模式 -
new MessageFormat(...)
- 格式化 -
format(new Object[]{...})
- 设置消息格式模式 -
- 消息格式模式
- 格式元素:
{ArgumentIndex (,FormatType,(FormatStyle))}
FormatType
:消息格式类型,可选项,每种类型在number
、date
、time
和choice
类型选其一FormatStyle
:消息格式风格,可选项,包括:short
、medium
、long
、full
、integer
、currency
、percent
- 格式元素:
高级特性
- 重置消息格式模式
- 重置
java.util.Locale
- 重置
java.text.Format
MessageSource 开箱即用实现
- 基于
ResourceBundle
+MessageFormat
组合MessageSource
实现org.springframework.context.support.ResourceBundleMessageSource
- 可重载
Properties
+MessageFormat
组合MessageSource
实现org.springframework.context.support.ReloadableResourceBundleMessageSource
MessageSource 內建依赖
MessageSource
內建 Bean 可能来源
- 预注册 Bean 名称为:
messageSource
,类型为:MessageSource
- 默认內建实现 -
DelegatingMessageSource
- 层次性查找
MessageSource
对象
- 层次性查找
课外资料
Spring Boot 为什么要新建 MessageSource Bean?
AbstractApplicationContext
的实现决定了MessageSource
內建实现- Spring Boot 通过外部化配置简化
MessageSource
Bean 构建 - Spring Boot 基于 Bean Validation 校验非常普遍
SpringBoot 中关于 MessageSource
的自动配置类
org.springframework.context.support.ResourceBundleMessageSource
面试题
Spring 国际化接口有哪些?
- 核心接口 -
MessageSource
- 层次性接口 -
org.springframework.context.HierarchicalMessageSource
Spring 有哪些 MessageSource 內建实现?
org.springframework.context.support.ResourceBundleMessageSource
org.springframework.context.support.ReloadableResourceBundleMessageSource
org.springframework.context.support.StaticMessageSource
org.springframework.context.support.DelegatingMessageSource
如何实现配置自动更新 MessageSource?
主要技术
- Java NIO 2:
java.nio.file.WatchService
- Java Concurrency :
java.util.concurrent.ExecutorService
- Spring:
org.springframework.context.support.AbstractMessageSource
第十三章:Spring 校验
Spring 校验使用场景
- Spring 常规校验(Validator)
- Spring 数据绑定(DataBinder)
- Spring Web 参数绑定(WebDataBinder)
- Spring Web MVC / Spring WebFlux 处理方法参数校验
Validator 接口设计
org.springframework.validation.Validator
接口职责
- Spring 内部校验器接口,通过编程的方式校验目标对象
核心方法
supports(Class)
:校验目标类能否校验validate(Object,Errors)
:校验目标对象,并将校验失败的内容输出至Errors
对象
配套组件
- 错误收集器:
org.springframework.validation.Errors
- Validator 工具类:
org.springframework.validation.ValidationUtils
- 错误收集器:
Errors 接口设计
org.springframework.validation.Errors
- 接口职责
- 数据绑定和校验错误收集接口,与 Java Bean 和其属性有强关联性
- 核心方法
reject
方法(重载):收集错误文案rejectValue
方法(重载):收集对象字段中的错误文案
- 配套组件
- Java Bean 错误描述:
org.springframework.validation.ObjectError
- Java Bean 属性错误描述:
org.springframework.validation.FieldError
- Java Bean 错误描述:
Errors 文案来源
Errors
文案生成步骤
- 选择
Errors
实现(如:org.springframework.validation.BeanPropertyBindingResult
) - 调用
reject
或rejectValue
方法 - 获取
Errors
对象中ObjectError
或FieldError
- 将
ObjectError
或FieldError
中的code
和args
,关联MessageSource
实现(如:ResourceBundleMessageSource
)
Errors
不能直接生成文案,但是可以提供国际化接口 MessageSource
所需要的 code
和 args
自定义 Validator
实现 org.springframework.validation.Validator
接口
- 实现
supports
方法 - 实现
validate
方法- 通过
Errors
对象收集错误ObjectError
:对象(Bean)错误:FieldError
:对象(Bean)属性(Property)错误
- 通过
ObjectError
和FieldError
关联MessageSource
实现获取最终文案
- 通过
Validator 的救赎
Bean Validation 与 Validator 适配
- 核心组件 -
org.springframework.validation.beanvalidation.LocalValidatorFactoryBean
- 依赖 Bean Validation - JSR-303 or JSR-349 provider
- Bean 方法参数校验 -
org.springframework.validation.beanvalidation.MethodValidationPostProcessor
关联注解:
org.springframework.validation.annotation.Validated
javax.validation.Valid
1 |
|
1 |
|
面试题
Spring 校验接口是哪个?
org.springframework.validation.Validator
Spring 有哪些校验核心组件?
- 检验器:
org.springframework.validation.Validator
- 错误收集器:
org.springframework.validation.Errors
- Java Bean 错误描述:
org.springframework.validation.ObjectError
- Java Bean 属性错误描述:
org.springframework.validation.FieldError
- Bean Validation 适配:
org.springframework.validation.beanvalidation.LocalValidatorFactoryBean
第十四章:Spring 数据绑定
Spring 数据绑定使用场景
- Spring BeanDefinition 到 Bean 实例创建
- Spring 数据绑定(DataBinder)
- Spring Web 参数绑定(WebDataBinder)
Spring 数据绑定组件
- 标准组件
org.springframework.validation.DataBinder
- Web 组件
org.springframework.web.bind.WebDataBinder
org.springframework.web.bind.ServletRequestDataBinder
org.springframework.web.bind.support.WebRequestDataBinder
org.springframework.web.bind.support.WebExchangeDataBinder
(since 5.0)
DataBinder 核心属性
属性 | 说明 |
---|---|
target | 关联目标 Bean |
objectName | 目标 Bean 名称 |
bindingResult | 属性绑定结果 |
typeConverter | 类型转换器 |
conversionService | 类型转换服务 |
messageCodesResolver | 校验错误文案 Code 处理器 |
validators | 关联的 Bean Validator 实例集合 |
DataBinder 绑定方法
bind(PropertyValues)
:将PropertyValues
Key-Value 内容映射到关联 Bean(target)中的属性上- 假设
PropertyValues
中包含 “name = 小马哥” 的键值对,同时 Bean 对象 User 中存在 name 属性,当 bind 方法执行时,User 对象中的 name 属性值将被绑定为 “小马哥”
Spring 数据绑定元数据
DataBinder
元数据 - PropertyValues
特征 | 说明 |
---|---|
数据来源 | BeanDefinition,主要来源 XML 资源配置 BeanDefinition |
数据结构 | 由一个或多个 PropertyValue 组成 |
成员结构 | PropertyValue 包含属性名称,以及属性值(包括原始值、类型转换后的值) |
常见实现 | MutablePropertyValues |
Web 扩展实现 | ServletConfigPropertyValues、ServletRequestParameterPropertyValues |
相关生命周期 | InstantiationAwareBeanPostProcessor#postProcessProperties |
Spring 数据绑定控制参数
DataBinder 绑定特殊场景分析
- 当
PropertyValues
中包含名称 x 的PropertyValue
,目标对象 B 不存在 x 属性,当 bind 方法执行时,会发生什么?- 默认忽略未知的属性,
ignoreUnknownFields
- 默认忽略未知的属性,
- 当
PropertyValues
中包含名称 x 的PropertyValue
,目标对象 B 中存在 x 属性,当 bind 方法执行时,如何避免 B 属性 x 不被绑定?- 设置
disallowedFields
属性
- 设置
- 当
PropertyValues
中包含名称 x.y 的PropertyValue
,目标对象 B 中存在 x 属性(嵌套 y 属性),当 bind 方法执行时,会发生什么?- 默认支持嵌套属性,
autoGrowNestedPaths
- 默认支持嵌套属性,
DataBinder 绑定控制参数
参数名称 | 说明 |
---|---|
ignoreUnknownFields | 是否忽略未知字段,默认值:true |
ignoreInvalidFields | 是否忽略非法字段,默认值:false |
autoGrowNestedPaths | 是否自动增加嵌套路径,默认值:true |
allowedFields | 绑定字段白名单 |
disallowedFields | 绑定字段黑名单 |
requiredFields | 必须绑定字段 |
BeanWrapper 的使用场景
BeanWrapper
- Spring 底层 JavaBeans 基础设施的中心化接口
- 通常不会直接使用,间接用于
BeanFactory
和DataBinder
- 提供标准 JavaBeans 分析和操作,能够单独或批量存储 Java Bean 的属性(properties)
- 支持嵌套属性路径(nested path)
- 实现类
org.springframework.beans.BeanWrapperImpl
Spring 底层 Java Beans 替换实现
- JavaBeans 核心实现 -
java.beans.BeanInfo
- 属性(Property)
java.beans.PropertyEditor
- 方法(Method)
- 事件(Event)
- 表达式(Expression)
- 属性(Property)
- Spring 替代实现 -
org.springframework.beans.BeanWrapper
- 属性(Property)
java.beans.PropertyEditor
- 嵌套属性路径(nested path)
- 属性(Property)
课外资料
标准 JavaBeans 是如何操作属性的?
API | 说明 |
---|---|
java.beans.Introspector | JavaBeans 内省 API |
java.beans.BeanInfo | JavaBeans 元信息 API |
java.beans.BeanDescriptor JavaBeans | 信息描述符 |
java.beans.PropertyDescriptor | JavaBeans 属性描述符 |
java.beans.MethodDescriptor | JavaBeans 方法描述符 |
java.beans.EventSetDescriptor | JavaBeans 事件集合描述符 |
DataBinder 数据校验
DataBinder
与BeanWrapper
bind
方法生成BeanPropertyBindingResult
BeanPropertyBindingResult
关联BeanWrapper
面试题
Spring 数据绑定 API 是什么?
org.springframework.validation.DataBinder
BeanWrapper 与 JavaBeans 之间关系是?
Spring 底层 JavaBeans 基础设施的中心化接口
第十五章:Spring 类型转换
Spring 类型转换的实现
- 基于 JavaBeans 接口的类型转换实现
- 基于
java.beans.PropertyEditor
接口扩展
- 基于
- Spring 3.0+ 通用类型转换实现
org.springframework.core.convert.converter.Converter
org.springframework.core.convert.converter.ConverterFactory
org.springframework.core.convert.ConversionService
使用场景
场景 | 基于 JavaBeans 接口的类型转换实现 | Spring 3.0+ 通用类型转换实现 |
---|---|---|
数据绑定 | YES | YES |
BeanWrapper | YES | YES |
Bean 属性类型装换 | YES | YES |
外部化属性类型转换 | NO | YES |
基于 JavaBeans 接口的类型转换
- 核心职责
- 将 String 类型的内容转化为目标类型的对象
- 扩展原理
- Spring 框架将文本内容传递到
PropertyEditor
实现的setAsText(String)
方法 PropertyEditor#setAsText(String)
方法实现将 String 类型转化为目标类型的对象- 将目标类型的对象传入
PropertyEditor#setValue(Object)
方法 PropertyEditor#setValue(Object)
方法实现需要临时存储传入对象- Spring 框架将通过
PropertyEditor#getValue()
获取类型转换后的对象
- Spring 框架将文本内容传递到
Spring 內建 PropertyEditor 扩展
內建扩展(org.springframework.beans.propertyeditors
包下)
转换场景 | 实现类 |
---|---|
String -> Byte 数组 | org.springframework.beans.propertyeditors.ByteArrayPropertyEditor |
String -> Char | org.springframework.beans.propertyeditors.CharacterEditor |
String -> Char 数组 | org.springframework.beans.propertyeditors.CharArrayPropertyEditor |
String -> Charset | org.springframework.beans.propertyeditors.CharsetEditor |
String -> Class | org.springframework.beans.propertyeditors.ClassEditor |
String -> Currency | org.springframework.beans.propertyeditors.CurrencyEditor |
自定义 PropertyEditor 扩展
- 扩展模式
- 扩展
java.beans.PropertyEditorSupport
类
- 扩展
- 实现
org.springframework.beans.PropertyEditorRegistrar
- 实现
registerCustomEditors(org.springframework.beans.PropertyEditorRegistry)
方法 - 将
PropertyEditorRegistrar
实现注册为 Spring Bean - 声明
org.springframework.beans.factory.config.CustomEditorConfigurer
,并将自定义PropertyEditorRegistrar
加入属性propertyEditorRegistrars
- 实现
- 向
org.springframework.beans.PropertyEditorRegistry
注册自定义PropertyEditor
实现- 通用类型实现
registerCustomEditor(Class<?>, PropertyEditor)
- Java Bean 属性类型实现:
registerCustomEditor(Class<?>, String, PropertyEditor)
- 通用类型实现
注意两个接口的不同:
org.springframework.beans.PropertyEditorRegistrar
org.springframework.beans.PropertyEditorRegistry
相关的两个类:
java.beans.PropertyEditor
java.beans.PropertyEditorSupport
Spring PropertyEditor 的设计缺陷
- 违反职责单一原则
java.beans.PropertyEditor
接口职责太多,除了类型转换,还包括 Java Beans 事件和 Java GUI 交互
java.beans.PropertyEditor
实现类型局限- 来源类型只能为
java.lang.String
类型
- 来源类型只能为
java.beans.PropertyEditor
实现缺少类型安全- 除了实现类命名可以表达语义,实现类无法感知目标转换类型
Spring 3 通用类型转换接口
- 类型转换接口 -
org.springframework.core.convert.converter.Converter<S,T>
- 泛型参数 S:来源类型,参数 T:目标类型
- 核心方法:T convert(S)
- 通用类型转换接口 -
org.springframework.core.convert.converter.GenericConverter
- 核心方法:
convert(Object,TypeDescriptor,TypeDescriptor)
- 配对类型:
org.springframework.core.convert.converter.GenericConverter.ConvertiblePair
- 类型描述:
org.springframework.core.convert.TypeDescriptor
- 核心方法:
Spring 內建类型转换器
转换场景 | 实现类所在包名(package) |
---|---|
日期 / 时间相关 | org.springframework.format.datetime |
Java 8 日期 / 时间相关 | org.springframework.format.datetime.standard |
通用实现 | org.springframework.core.convert.support |
Converter 接口的局限性
- 局限一:缺少 Source Type 和 Target Type 前置判断
- 应对:增加
org.springframework.core.convert.converter.ConditionalConverter
实现- 判断泛型相关的类
org.springframework.core.convert.TypeDescriptor
org.springframework.core.ResolvableType
- 判断泛型相关的类
- 应对:增加
- 局限二:仅能转换单一的 Source Type 和 Target Type,不支持复合类型(比如 Collection、Map、数组等)
- 应对:使用
org.springframework.core.convert.converter.GenericConverter
代替
- 应对:使用
GenericConverter 接口
org.springframework.core.convert.converter.GenericConverter
核心要素 | 说明 |
---|---|
使用场景 | 用于 “复合” 类型转换场景,比如 Collection、Map、数组等 |
转换范围 | Set<ConvertiblePair> getConvertibleTypes() |
配对类型 | org.springframework.core.convert.converter.GenericConverter.ConvertiblePair |
转换方法 | convert(Object,TypeDescriptor,TypeDescriptor) |
类型描述 | org.springframework.core.convert.TypeDescriptor |
GenericConverter
接口处理复合类型,Converter
接口处理简单类型,两者可以相互配合
优化 GenericConverter 接口
GenericConverter
局限性- 缺少 Source Type 和 Target Type 前置判断
- 单一类型转换实现复杂
- GenericConverter 优化接口 -
ConditionalGenericConverter
- 复合类型转换:
org.springframework.core.convert.converter.GenericConverter
- 类型条件判断:
org.springframework.core.convert.converter.ConditionalConverter
- 复合类型转换:
扩展 Spring 类型转换器
- 实现转换器接口
org.springframework.core.convert.converter.Converter
org.springframework.core.convert.converter.ConverterFactory
org.springframework.core.convert.converter.GenericConverter
- 注册转换器实现
- 通过
ConversionServiceFactoryBean
Spring Bean- 声明名称为
conversionService
的ConversionServiceFactoryBean
- 将自定义
Converter
传入属性converters
- 声明名称为
- 通过
org.springframework.core.convert.ConversionService
API
- 通过
统一类型转换服务
org.springframework.core.convert.ConversionService
实现类型 | 说明 |
---|---|
GenericConversionService | 通用 ConversionService 模板实现,不内置转化器实现 |
DefaultConversionService | 基础 ConversionService 实现,内置常用转化器实现 |
FormattingConversionService | 通用 Formatter + GenericConversionService 实现,不内置转化器和 Formatter 实现 |
DefaultFormattingConversionService | DefaultConversionService + 格式化 实现(如:JSR-354 Money & Currency, JSR-310 Date-Time) |
ConversionService 作为依赖
类型转换器底层接口 -
org.springframework.beans.TypeConverter
- 起始版本:Spring 2.0
- 核心方法 -
convertIfNecessary
重载方法 - 抽象实现 -
org.springframework.beans.TypeConverterSupport
- 简单实现 -
org.springframework.beans.SimpleTypeConverter
类型转换器底层抽象实现 -
org.springframework.beans.TypeConverterSupport
- 实现接口 -
org.springframework.beans.TypeConverter
- 扩展实现 -
org.springframework.beans.PropertyEditorRegistrySupport
- 委派实现 -
org.springframework.beans.TypeConverterDelegate
- 实现接口 -
类型转换器底层委派实现 -
org.springframework.beans.TypeConverterDelegate
- 构造来源 -
org.springframework.beans.AbstractNestablePropertyAccessor
实现org.springframework.beans.BeanWrapperImpl
- 依赖 -
java.beans.PropertyEditor
实现- 默认內建实现 -
PropertyEditorRegistrySupport#registerDefaultEditors
- 默认內建实现 -
- 可选依赖 -
org.springframework.core.convert.ConversionService
实现
- 构造来源 -
1 |
|
面试题
Spring 类型转换实现有哪些?
- 基于 JavaBeans PropertyEditor 接口实现
- Spring 3.0+ 通用类型转换实现
Spring 类型转换器接口有哪些?
- 类型转换接口 -
org.springframework.core.convert.converter.Converter
- 通用类型转换接口 -
org.springframework.core.convert.converter.GenericConverter
- 类型条件接口 -
org.springframework.core.convert.converter.ConditionalConverter
- 综合类型转换接口 -
org.springframework.core.convert.converter.ConditionalGenericConverter
第十六章:Spring 泛型处理
Java 泛型基础
泛型类型
- 泛型类型是在类型上参数化的泛型类或接口
泛型使用场景
- 编译时强类型检查
- 避免类型强转
- 实现通用算法
泛型类型擦写
- 泛型被引入到 Java 语言中,以便在编译时提供更严格的类型检查并支持泛型编程。类型擦除确保不会为参数化类型创建新类;因此,泛型不会产生运行时开销。为了实现泛型,编译器将类型擦除应用于:
- 将泛型类型中的所有类型参数替换为其边界,如果类型参数是无边界的,则将其替换为
Object
。因此,生成的字节码只包含普通类、接口和方法。 - 必要时插入类型转换以保持类型安全。
- 生成桥方法以保留扩展泛型类型中的多态性。
- 将泛型类型中的所有类型参数替换为其边界,如果类型参数是无边界的,则将其替换为
- 泛型被引入到 Java 语言中,以便在编译时提供更严格的类型检查并支持泛型编程。类型擦除确保不会为参数化类型创建新类;因此,泛型不会产生运行时开销。为了实现泛型,编译器将类型擦除应用于:
Java 5 类型接口
Java 5 类型接口 - java.lang.reflect.Type
派生类或接口 | 说明 |
---|---|
java.lang.Class | Java 类 API,如 java.lang.String |
java.lang.reflect.GenericArrayType | 泛型数组类型 |
java.lang.reflect.ParameterizedType | 泛型参数类型 |
java.lang.reflect.TypeVariable | 泛型类型变量,如 Collection<E> 中的 E |
java.lang.reflect.WildcardType | 泛型通配类型 |
Java 泛型反射 API
类型 | API |
---|---|
泛型信息(Generics Info) | java.lang.Class#getGenericInfo() |
泛型参数(Parameters) | java.lang.reflect.ParameterizedType |
泛型父类(Super Classes) | java.lang.Class#getGenericSuperclass() |
泛型接口(Interfaces) | java.lang.Class#getGenericInterfaces() |
泛型声明(Generics Declaration) | java.lang.reflect.GenericDeclaration |
Spring 泛型类型辅助类
核心 API - org.springframework.core.GenericTypeResolver
- 版本支持:[2.5.2 ,)
- 处理类型相关(Type)相关方法
resolveReturnType
- 返回给定方法的返回类型
resolveType
- 处理泛型参数类型(ParameterizedType)相关方法
resolveReturnTypeArgument
- 返回给定方法返回类型的泛型参数类型
resolveTypeArgument
resolveTypeArguments
- 处理泛型类型变量(TypeVariable)相关方法
getTypeVariableMap
Spring 泛型集合类型辅助类
核心 API - org.springframework.core.GenericCollectionTypeResolver
- 版本支持:[2.0 , 4.3]
- 替换实现:
org.springframework.core.ResolvableType
- 处理 Collection 相关
getCollection*Type
- 处理 Map 相关
getMapKey*Type
getMapValue*Type
Spring 方法参数封装
核心 API - org.springframework.core.MethodParameter
- 起始版本:[2.0 ,)
- 元信息
- 关联的方法 -
Method
- 关联的构造器 -
Constructor
- 构造器或方法参数索引 -
parameterIndex
- 构造器或方法参数类型 -
parameterType
- 构造器或方法参数泛型类型 -
genericParameterType
- 构造器或方法参数参数名称 -
parameterName
- 所在的类 -
containingClass
- 关联的方法 -
Method
和 Constructor
二选一
MethodParameter
可以表示方法参数、构造器参数、返回类型
Spring 4.0 泛型优化实现 - ResolvableType
核心 API - org.springframework.core.ResolvableType
- 起始版本:[4.0 ,)
- 扮演角色:
GenericTypeResolver
和GenericCollectionTypeResolver
替代者 - 工厂方法:
for*
方法 - 转换方法:
as*
方法 - 处理方法:
resolve*
方法
ResolvableType 的局限性
- 局限一:
ResolvableType
无法处理泛型擦写 - 局限二:
ResolvableType
无法处理非具体化的ParameterizedType
面试题
Java 泛型擦写发生在编译时还是运行时?
运行时
请介绍 Java 5 Type 类型的派生类或接口?
java.lang.Class
java.lang.reflect.GenericArrayType
java.lang.reflect.ParameterizedType
java.lang.reflect.TypeVariable
java.lang.reflect.WildcardType
请说明 ResolvableType 的设计优势?
- 简化 Java 5 Type API 开发,屏蔽复杂 API 的运用,如
ParameterizedType
- 不变性设计(Immutability)
- Fluent API 设计(Builder 模式),链式(流式)编程
第十七章:Spring 事件
Java 事件 / 监听器编程模型
- 设计模式 - 观察者模式扩展
- 可观者对象(消息发送者)-
java.util.Observable
- 观察者 -
java.util.Observer
- 可观者对象(消息发送者)-
- 标准化接口
- 事件对象 -
java.util.EventObject
- 事件监听器 -
java.util.EventListener
- 事件对象 -
面向接口的事件 / 监听器设计模式
事件 / 监听器场景举例
Java 技术规范 | 事件接口 | 监听器接口 |
---|---|---|
JavaBeans | java.beans.PropertyChangeEvent | java.beans.PropertyChangeListener |
Java AWT | java.awt.event.MouseEvent | java.awt.event.MouseListener |
Java Swing | javax.swing.event.MenuEvent | javax.swing.event.MenuListener |
Java Preference | java.util.prefs.PreferenceChangeEvent | java.util.prefs.PreferenceChangeListener |
面向注解的事件 / 监听器设计模式
事件 / 监听器注解场景举例
Java 技术规范 | 事件注解 | 监听器注解 |
---|---|---|
Servlet 3.0+ | @javax.servlet.annotation.WebListener | |
JPA 1.0+ | @javax.persistence.PostPersist | |
Java Common | @PostConstruct | |
EJB 3.0+ | @javax.ejb.PrePassivate | |
JSF 2.0+ | @javax.faces.event.ListenerFor |
Spring 标准事件 - ApplicationEvent
org.springframework.context.ApplicationEvent
- Java 标准事件
java.util.EventObject
扩展- 扩展特性:事件发生时间戳
- Spring 应用上下文
ApplicationEvent
扩展 -ApplicationContextEvent
org.springframework.context.event.ApplicationContextEvent
- Spring 应用上下文(ApplicationContext)作为事件源
- 具体实现:
org.springframework.context.event.ContextClosedEvent
org.springframework.context.event.ContextRefreshedEvent
org.springframework.context.event.ContextStartedEvent
org.springframework.context.event.ContextStoppedEvent
基于接口的 Spring 事件监听器
Java 标准事件监听器 java.util.EventListener
扩展
- 扩展接口 -
org.springframework.context.ApplicationListener
- 设计特点:单一类型事件处理
- 处理方法:
onApplicationEvent(ApplicationEvent)
- 事件类型:
org.springframework.context.ApplicationEvent
基于注解的 Spring 事件监听器
Spring 注解 - @org.springframework.context.event.EventListener
特性 | 说明 |
---|---|
设计特点 | 支持多 ApplicationEvent 类型,无需接口约束 |
注解目标 | 方法 |
是否支持异步执行 | 支持 |
是否支持泛型类型事件 | 支持 |
是指支持顺序控制 | 支持,配合 @Order 注解控制 |
注册 Spring ApplicationListener
- 基于 Spring 接口:向 Spring 应用上下文注册事件
ApplicationListener
作为 Spring Bean 注册- 通过
ConfigurableApplicationContext#addApplicationListener
API 注册
- 基于 Spring 注解:
@org.springframework.context.event.EventListener
Spring 事件发布器
- 方法一:通过
ApplicationEventPublisher
发布 Spring 事件- 获取 ApplicationEventPublisher
- 依赖注入
- 获取 ApplicationEventPublisher
- 方法二:通过
ApplicationEventMulticaster
发布 Spring 事件- 获取
ApplicationEventMulticaster
- 依赖注入
- 依赖查找
- 获取
Spring 层次性上下文事件传播
- 发生说明
- 当 Spring 应用出现多层次 Spring 应用上下文(ApplicationContext)时,如 Spring WebMVC、Spring Boot 或 Spring Cloud 场景下,由子
ApplicationContext
发起 Spring 事件可能会传递到其 ParentApplicationContext
(直到 Root)的过程
- 当 Spring 应用出现多层次 Spring 应用上下文(ApplicationContext)时,如 Spring WebMVC、Spring Boot 或 Spring Cloud 场景下,由子
- 如何避免
- 定位 Spring 事件源(ApplicationContext)进行过滤处理
Spring 内建事件
ApplicationContextEvent
派生事件
ContextRefreshedEvent
:Spring 应用上下文就绪事件ContextStartedEvent
:Spring 应用上下文启动事件ContextStoppedEvent
:Spring 应用上下文停止事件ContextClosedEvent
:Spring 应用上下文关闭事件
Spring 4.2 Payload 事件
Spring Payload 事件 - org.springframework.context.PayloadApplicationEvent
使用场景:简化 Spring 事件发送,关注事件源主体
发送方法
ApplicationEventPublisher#publishEvent(java.lang.Object)
自定义 Spring 事件
- 扩展
org.springframework.context.ApplicationEvent
- 实现
org.springframework.context.ApplicationListener
- 将
org.springframework.context.ApplicationListener
注册到容器内
依赖注入 ApplicationEventPublisher
- 通过
ApplicationEventPublisherAware
回调接口 - 通过
@Autowired ApplicationEventPublisher
依赖查找 ApplicationEventMulticaster
- 查找条件
- Bean 名称:
applicationEventMulticaster
- Bean 类型:
org.springframework.context.event.ApplicationEventMulticaster
- Bean 名称:
1 |
|
ApplicationEventPublisher 底层实现
- 接口:
org.springframework.context.event.ApplicationEventMulticaster
- 抽象类:
org.springframework.context.event.AbstractApplicationEventMulticaster
- 实现类:
org.springframework.context.event.SimpleApplicationEventMulticaster
- 实现类:
- 抽象类:
同步和异步 Spring 事件广播
- 基于实现类 -
org.springframework.context.event.SimpleApplicationEventMulticaster
- 模式切换:
setTaskExecutor(java.util.concurrent.Executor)
方法- 默认模式:同步
- 异步模式:如
java.util.concurrent.ThreadPoolExecutor
- 设计缺陷:不是基于接口契约编程,实现依赖于类本身
- 模式切换:
- 基于注解 -
@org.springframework.context.event.EventListener
- 模式切换
- 默认模式:同步
- 异步模式:标注
@org.springframework.scheduling.annotation.Async
- 实现限制:无法直接实现同步 / 异步动态切换
- 模式切换
区别:
- 使用
SimpleApplicationEventMulticaster#setTaskExecutor
的影响是全局的,使用@Async
是局部的 - 使用
SimpleApplicationEventMulticaster#setTaskExecutor
需要手动关闭线程池,使用@Async
不需要
Spring 4.1 事件异常处理
- Spring 3.0 错误处理接口 -
org.springframework.util.ErrorHandler
- 使用场景
- Spring 事件(Events)
SimpleApplicationEventMulticaster
Spring 4.1 开始支持- Spring 本地调度(Scheduling)
org.springframework.scheduling.concurrent.ConcurrentTaskScheduler
org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler
Spring 事件 / 监听器实现原理
- 核心类 -
org.springframework.context.event.SimpleApplicationEventMulticaster
- 设计模式:观察者模式扩展
- 被观察者 -
org.springframework.context.ApplicationListener
- API 添加
- 依赖查找
- 通知对象 -
org.springframework.context.ApplicationEvent
- 被观察者 -
- 执行模式:同步 / 异步
- 异常处理:
org.springframework.util.ErrorHandler
- 泛型处理:
org.springframework.core.ResolvableType
- 设计模式:观察者模式扩展
课外资料
Spring Boot 事件
事件类型 | 发生时机 |
---|---|
ApplicationStartingEvent | 当 Spring Boot 应用已启动时 |
ApplicationStartedEvent | 当 Spring Boot 应用已启动时 |
ApplicationEnvironmentPreparedEvent | 当 Spring Boot Environment 实例已准备时 |
ApplicationPreparedEvent | 当 Spring Boot 应用预备时 |
ApplicationReadyEvent | 当 Spring Boot 应用完全可用时 |
ApplicationFailedEvent | 当 Spring Boot 应用启动失败时 |
Spring Cloud 事件
事件类型 | 发生时机 |
---|---|
EnvironmentChangeEvent | 当 Environment 示例配置属性发生变化时 |
HeartbeatEvent | 当 Discoveryclient 客户端发送心跳时 |
InstancePreRegisteredEvent | 当服务实例注册前 |
InstanceRegisteredEvent | 当服务实例注册后 |
RefreshEvent | 当 RefreshEndpoint 被调用时 |
RefreshScopeRefreshedEvent | 当 Refresh Scope Bean 刷新后 |
面试题
Spring 事件核心接口 / 组件?
- Spring 事件 -
org.springframework.context.ApplicationEvent
- Spring 事件监听器 -
org.springframework.context.ApplicationListener
- Spring 事件发布器 -
org.springframework.context.ApplicationEventPublisher
- Spring 事件广播器 -
org.springframework.context.event.ApplicationEventMulticaster
Spring 同步和异步事件处理的使用场景?
- Spring 同步事件 - 绝大多数 Spring 使用场景,如
ContextRefreshedEvent
- Spring 异步事件 - 主要
@EventListener
与@Async
配合,实现异步处理,不阻塞主线程,比如长时间的数据计算任务等。不要轻易调整SimpleApplicationEventMulticaster
中关联的taskExecutor
对象,除非使用者非常了解 Spring 事件机制,否则容易出现异常行为。
第十八章:Spring 注解
Spring 注解驱动编程发展历程
- 注解驱动启蒙时代:Spring Framework 1.x
@Transactional
@ManagedResource
- 注解驱动过渡时代:Spring Framework 2.x
@Component
@Repository
@Service
@Controller
- 注解驱动黄金时代:Spring Framework 3.x
@Bean
@Profile
@Import
@ImportResource
@ComponentScan
@Lazy
@PropertySource
- 注解驱动完善时代:Spring Framework 4.x
@Conditional
- 注解驱动当下时代:Spring Framework 5.x
@Indexed
Spring 核心注解场景分类
Spring 模式注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@Repository | 数据仓储模式注解 | 2.0 |
@Component | 通用组件模式注解 | 2.5 |
@Service | 服务模式注解 | 2.5 |
@Controller | Web 控制器模式注解 | 2.5 |
@Configuration | 配置类模式注解 | 3.0 |
装配注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@lmportResource | 替换 XML 元素 <import> | 2.5 |
@lmport | 导入 Configuration 类 | 2.5 |
@ComponentScan | 扫描指定 package 下标注 Spring 模式注解的类 | 3.1 |
依赖注入注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@Autowired | Bean 依赖注入,支持多种依赖查找方式 | 2.5 |
@Qualifier | 细粒度的 @Autowired 依赖查找 | 2.5 |
Spring 注解编程模型
- 编程模型
- 元注解(Meta-Annotations)
- Spring 模式注解(Stereotype Annotations)
- Spring 组合注解(Composed Annotations)
- Spring 注解属性别名和覆盖(Attribute Aliases and Overrides)
Spring 元注解(Meta-Annotations)
java.lang.annotation.Documented
java.lang.annotation.Inherited
java.lang.annotation.Repeatable
Spring 模式注解(Stereotype An notations)
理解
@Component
“派生性”- 元标注
@Component
的注解在 XML 元素<context:component-scan>
或注解@ComponentScan
扫描中 “派生” 了@Component
的特性,并且从 Spring Framework 4.0 开始支持多层次 ” 派生性 “。
- 元标注
举例说明
@Repository
@Service
@Controller
@Configuration
@SpringBootConfiguration
(Spring Boot)
@Component
“派生性” 原理- 核心组件 -
org.springframework.context.annotation.ClassPathBeanDefinitionScanner
org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider
- 资源处理 -
org.springframework.core.io.support.ResourcePatternResolver
- 资源 - 类元信息
org.springframework.core.type.classreading.MetadataReaderFactory
- 类元信息 -
org.springframework.core.type.ClassMetadata
- ASM 实现 -
org.springframework.core.type.classreading.ClassMetadataReadingVisitor
- 反射实现 -
org.springframework.core.type.StandardAnnotationMetadata
- ASM 实现 -
- 注解元信息 -
org.springframework.core.type.AnnotationMetadata
- ASM 实现 -
org.springframework.core.type.classreading.AnnotationMetadataReadingVisitor
- 反射实现 -
org.springframework.core.type.StandardAnnotationMetadata
- ASM 实现 -
- 核心组件 -
org.springframework.context.annotation.ComponentScanAnnotationParser
Spring 组合注解(Composed Annotations)
- 基本定义
- Spring 组合注解(Composed Annotations)中的元注解允许是 Spring 模式注解(Stereotype Annotation)与 其他 Spring 功能性注解的任意组合。
相关类:
org.springframework.context.annotation.ConfigurationClassParser
org.springframework.core.annotation.AnnotationAttributes
Spring 注解属性别名(Attribute Aliases)
- 显性别名:一个注解类中两个属性通过
@AliasFor
互相声明别名org.springframework.context.annotation.ComponentScan
的value
和basePackages
- 隐形别名:通过在注解属性上
@AliasFor
元注解的属性org.springframework.boot.autoconfigure.SpringBootApplication
的exclude
、excludeName
- 传递隐式别名:给定一个批注中的两个或更多属性,它们通过
@AliasFor
声明为元注解中的属性的显式替代,如果这些属性有效地替代了元注解中的同一属性,则它们是可传递的隐式别名。
Spring 注解属性覆盖(Attribute Overrides)
- 隐式覆盖:注解中存在和元注解中名称相同的属性
- 显式覆盖:不同名称属性,使用
@AliasFor
声明为元注解属性的别名 - 传递显式覆盖:
Spring @Enable 模块驱动
@Enable 模块驱动
- @Enable 模块驱动是以
@Enable
为前缀的注解驱动编程模型。所谓 “模块” 是指具备相同领域的功能组件集合,组合所形成一个独立的单元。比如 WebMVC 模块、AspectJ 代理模块、Caching (缓存)模块、JMX (Java 管理扩展)模块、Async (异步处理)模块等。
- @Enable 模块驱动是以
举例说明
@EnableWebMvc
@EnableTransactionManagement
@EnableCaching
@EnableMBeanExport
@EnableAsync
@Enable 模块驱动编程模式
- 驱动注解:@EnableXXX
- 导入注解:
@lmport
具体实现 - 具体实现
- 基于 Configuration Class
- 基于
ImportSelector
接口实现 - 基于
ImportBeanDefinitionRegistrar
接口实现
Spring 条件注解
基于配置条件注解 -
@org.springframework.context.annotation.Profile
- 关联对象 -
org.springframework.core.env.Environment
中的 Profiles - 实现变化:从 Spring 4.0 开始,
@Profile
基于@Conditional
实现
- 关联对象 -
基于编程条件注解 -
@org.springframework.context.annotation.Conditional
- 关联对象 -
org.springframework.context.annotation.Condition
具体实现
- 关联对象 -
@Conditional
实现原理- 上下文对象 -
org.springframework.context.annotation.ConditionContext
- 条件判断 -
org.springframework.context.annotation.ConditionEvaluator
- 配置阶段 -
org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase
- 判断入口 -
org.springframework.context.annotation.ConfigurationClassPostProcessor
org.springframework.context.annotation.ConfigurationClassParser
- 上下文对象 -
@Conditional
属性可传入多个 Condition
类作为条件,这些条件按照 Order 排序,如果一个条件通过,就返回 true
课外资料
- Spring Boot 注解
注解 | 场景说明 | 起始版本 |
---|---|---|
@SpringBootConfiguration | Spring Boot 配置类 | 1.4.0 |
@SpringBootApplication | Spring Boot 应用引导注解 | 1.2.0 |
@EnableAutoConfiguration | Spring Boot 激活自动装配 | 1.0.0 |
- Spring Cloud 注解
注解 | 场景说明 | 起始版本 |
---|---|---|
@SpringCloudApplication | Spring Cloud 应用引导注解 | 1.0.0 |
@EnableDiscoveryClient | Spring Cloud 激活服务发现客户端注解 | 1.0.0 |
@EnableCircuitBreaker | Spring Cloud 激活熔断注解 | 1.0.0 |
面试题
Spring 模式注解有哪些?
@org.springframework.stereotype.Component
@org.springframework.stereotype.Repository
@org.springframework.stereotype.Service
@org.springframework.stereotype.Controller
@org.springframework.context.annotation.Configuration
@EventListener 的工作原理?
源码导读 - org.springframework.context.event.EventListenerMethodProcessor
@PropertySource 的工作原理?
本文由 简悦 SimpRead 转码, 原文地址 www.cnblogs.com
第十九章:Spring Environment 抽象
理解 Spring Environment 抽象
统一的 Spring 配置属性管理
PropertySource
- Spring Framework 3.1 开始引入
Environment
抽象,它统一 Spring 配置属性的存储,包括占位符处理和类型转换,不仅完整地替换PropertyPlaceholderConfigurer
,而且还支持更丰富的配置属性源(PropertySource) PropertyPlaceholderConfigurer
在 Spring 5.2 已过期
条件化 Spring Bean 装配管理
- Profile
- 通过 Environment Profiles 信息,帮助 Spring 容器提供条件化地装配 Bean
Environment 接口功能分析
- 继承了
org.springframework.core.env.PropertyResolver
接口,此接口提供属性管理和解析占位符的能力 org.springframework.core.env.Environment
接口提供管理 Profiles 的能力
- 继承了
Spring 5.2 以后,
PropertySourcesPlaceholderConfigurer
取代PropertyPlaceholderConfigurer
,两者功能类似,都继承自PlaceholderConfigurerSupport
优势在于Environment
和PropertySource
Spring Environment 接口使用场景
- 用于属性占位符处理
- 用于转换 Spring 配置属性类型
- 用于存储 Spring 配置属性源(PropertySource)
- 用于 Profiles 状态的维护
Environment 占位符处理
Spring 3.1 前占位符处理
- 组件:
org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
- 接口:
org.springframework.util.StringValueResolver
- 组件:
Spring 3.1+ 占位符处理
- 组件:
org.springframework.context.support.PropertySourcesPlaceholderConfigurer
- 实现类:
org.springframework.beans.factory.config.EmbeddedValueResolver
- 实现了
StringValueResolver
接口
- 实现了
- 组件:
PropertyPlaceholderConfigurer
和PropertySourcesPlaceholderConfigurer
都实现了BeanFactoryPostProcessor
,两者对占位符的处理都位于BeanFactoryPostProcessor#postProcessBeanFactory
方法中
理解条件配置 Spring Profiles
Spring 3.1 条件配置
- API:
org.springframework.core.env.ConfigurableEnvironment
- 修改:
addActiveProfile(String
)、setActiveProfiles(String...)
和setDefaultProfiles(String...)
- 获取:
getActiveProfiles()
和getDefaultProfiles()
- 匹配:
acceptsProfiles(String...)
和acceptsProfiles(Profiles)
- 修改:
- API:
注解:
@org.springframework.context.annotation.Profile
属性值常量:
org.springframework.core.env.AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME
- 即
spring.profiles.active
,可以通过设置此属性,设置 active Profiles
- 即
Spring 4 重构 @Profile
- 基于 Spring 4 接口实现
@org.springframework.context.annotation.Conditional
org.springframework.context.annotation.Condition
org.springframework.context.annotation.ProfileCondition
依赖注入 Environment
直接依赖注入
- 通过
EnvironmentAware
接口回调 - 通过
@Autowired
注入Environment
- 通过
间接依赖注入
- 通过
ApplicationContextAware
接口回调 - 通过
@Autowired
注入ApplicationContext
- 通过
ApplicationContext
和Environment
是一一对应的在
AbstractApplicationContext#prepareBeanFactory
中,以单例形式,将Environment
注入了BeanFactory
1
2
3if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
依赖查找 Environment
直接依赖查找
- 通过
org.springframework.context.ConfigurableApplicationContext#ENVIRONMENT_BEAN_NAME
- 通过
间接依赖查找
- 通过
org.springframework.context.ConfigurableApplicationContext#getEnvironment
- 通过
依赖注入 @Value
通过注入
@Value
实现 -
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
@Value
注解的解析在populateBean
阶段解析的生命周期在
InstantiationAwareBeanPostProcessor#postProcessProperties
AutowiredAnnotationBeanPostProcessor
实现InstantiationAwareBeanPostProcessor
解析方法位于
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
Spring 类型转换在 Environment 中的运用
Environment
底层实现- 底层实现 -
org.springframework.core.env.PropertySourcesPropertyResolver
- 核心方法 -
convertValueIfNecessary(Object, Class)
- 核心方法 -
- 底层服务 -
org.springframework.core.convert.ConversionService
- 默认实现 -
org.springframework.core.convert.support.DefaultConversionService
- 默认实现 -
- 底层实现 -
Environment#getProperty
,从这个方法开始分析AbstractEnvironment#getProperty
使用PropertySourcesPropertyResolver
,PropertySourcesPropertyResolver
使用ConversionService
Spring 类型转换在 @Value 中的运用
@Value
底层实现- 底层实现 -
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
- 底层服务 -
org.springframework.beans.TypeConverter
- 默认实现 -
org.springframework.beans.TypeConverterDelegate
java.beans.PropertyEditor
org.springframework.core.convert.ConversionService
- 默认实现 -
- 底层实现 -
Spring 配置属性源 PropertySource
- API
- 单配置属性源 -
org.springframework.core.env.PropertySource
- 多配置属性源 -
org.springframework.core.env.PropertySources
- 单配置属性源 -
- 注解
- 单配置属性源 -
@org.springframework.context.annotation.PropertySource
- 多配置属性源 -
@org.springframework.context.annotation.PropertySources
- 单配置属性源 -
- 关联
- 存储对象 -
org.springframework.core.env.MutablePropertySources
- 关联方法 -
org.springframework.core.env.ConfigurableEnvironment#getPropertySources
- 存储对象 -
Spring 内建的配置属性源
- 內建
PropertySource
PropertySource 类型 | 说明 |
---|---|
org.springframework.core.env.CommandLinePropertySource | 命令行配置属性源 |
org.springframework.jndi.JndiPropertySource | JDNI 配置属性源 |
org.springframework.core.env.PropertiesPropertySource | Properties 配置属性源 |
org.springframework.web.context.support.ServletConfigPropertySource | Servlet 配置属性源 |
org.springframework.web.context.support.ServletContextPropertySource | ServletContext 配置属性源 |
org.springframework.core.env.SystemEnvironmentPropertySource | 环境变量配置属性源 |
基于注解扩展 Spring 配置属性源
@org.springframework.context.annotation.PropertySource
实现原理- 入口 -
org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass
org.springframework.context.annotation.ConfigurationClassParser#processPropertySource
- 4.3 新增语义
- 配置属性字符编码 -
encoding
org.springframework.core.io.support.PropertySourceFactory
- 配置属性字符编码 -
- 适配对象 -
org.springframework.core.env.CompositePropertySource
- 入口 -
PropertySource
之前只支持 properties 文件,从 Spring 4.3 开始支持其他格式文件org.springframework.context.annotation.PropertySource#factory
org.springframework.core.io.support.EncodedResource
基于 API 扩展 Spring 配置属性源
Spring 应用上下文启动前装配
PropertySource
Spring 应用上下文启动后装配
PropertySource
修改
PropertySource
里的属性值,是否影响 Bean 里的注入属性值,需要考虑到 Bean 的初始化时机PropertySource
存在顺序,总是取先匹配到的
课外资料
- Spring 4.1 测试配置属性源 -
@TestPropertySource
面试题
简单介绍 Spring Environment 接口?
核心接口 -
org.springframework.core.env.Environment
父接口 -
org.springframework.core.env.PropertyResolver
可配置接口 -
org.springframework.core.env.ConfigurableEnvironment
职责:
- 管理 Spring 配置属性源
- 管理 Profiles
如何控制 PropertySource 的优先级?
org.springframework.core.env.ConfigurableEnvironment#getPropertySources
org.springframework.core.env.MutablePropertySources
MutablePropertySources
中存在控制 PropertySource 顺序的方法
Environment 完整的生命周期是怎样的?
第二十章:Spring 应用上下文生命周期
ApplicationContext 接口继承关系
Spring 应用上下文生命周期
AbstractApplicationContext#refresh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// 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);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// 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();
}
}
}
Spring 应用上下文启动准备阶段
AbstractApplicationContext#prepareRefresh()
方法- 启动时间 -
startupDate
- 状态标识 -
closed(false)
、active(true)
- 初始化
PropertySources
-initPropertySources()
- 默认为空方法,子类可继承
- Web 应用上下文继承这个方法,并将 Web 参数初始化为
PropertySource
- 检验
Environment
中必须属性AbstractPropertyResolver#requiredProperties
,默认为空,可设置
- 初始化事件监听器集合
earlyApplicationListeners
applicationListeners
- 初始化早期 Spring 事件集合
earlyApplicationEvents
- 启动时间 -
BeanFactory 创建阶段
AbstractApplicationContext#obtainFreshBeanFactory
方法- 抽象方法
- 子类实现,
AbstractRefreshableApplicationContext#refreshBeanFactory
- 刷新 Spring 应用上下文底层
BeanFactory
-refreshBeanFactory()
- 销毁或关闭
BeanFactory
,如果已存在的话 - 创建
BeanFactory
-createBeanFactory()
DefaultListableBeanFactory
- 设置 BeanFactory Id
- 自定义
BeanFactory
属性 -customizeBeanFactory(beanFactory)
- 设置 “是否允许 BeanDefinition 重复定义” -
customizeBeanFactory(DefaultListableBeanFactory)
AbstractRefreshableApplicationContext#allowBeanDefinitionOverriding
- 默认为 true
- 设置 “是否允许循环引用(依赖)” -
customizeBeanFactory(DefaultListableBeanFactory)
AbstractRefreshableApplicationContext#allowCircularReferences
- 默认为 true
- 加载
BeanDefinition
-loadBeanDefinitions(DefaultListableBeanFactory)
方法- 抽象方法
- 关联新建
BeanFactory
到 Spring 应用上下文
- 销毁或关闭
- 刷新 Spring 应用上下文底层
- 返回 Spring 应用上下文底层
BeanFactory
-getBeanFactory()
- 抽象方法
BeanFactory 准备阶段
AbstractApplicationContext#prepareBeanFactory(ConfigurableListableBeanFactory)
方法- 关联
ClassLoader
- 设置 Bean 表达式处理器
- 与 SpEL 表达式相关
org.springframework.context.expression.StandardBeanExpressionResolver
- 添加
PropertyEditorRegistrar
实现 -ResourceEditorRegistrar
org.springframework.beans.support.ResourceEditorRegistrar
- 添加
Aware
回调接口BeanPostProcessor
实现 -ApplicationContextAwareProcessor
EnvironmentAware
EmbeddedValueResolverAware
ResourceLoaderAware
ApplicationEventPublisherAware
MessageSourceAware
ApplicationContextAware
- 忽略
Aware
回调接口作为依赖注入接口 - 注册 ResolvableDependency 对象 -
BeanFactory
、ResourceLoader
、ApplicationEventPublisher
以及Applicationcontext
BeanFactory
是ApplicationContext
关联的BeanFactory
ResourceLoader
、ApplicationEventPublisher
以及Applicationcontext
都是ApplicationContext
- 添加
BeanPostProcessor
-ApplicationListenerDetector
- 在
BeanPostProcessor#postProcessAfterInitialization
阶段,将单例的ApplicationListener
加入ApplicationContext
- 在
- 如果包含 beanName 是
loadTimeWeaver
的 bean,注册BeanPostProcessor
-LoadTimeWeaverAwareProcessor
对象,并设置容器的临时ClassLoader
,AbstractBeanFactory#tempClassLoader
- 与 AOP 相关
- 注册单例对象 -
Environment
、Java System Properties 以及 OS 环境变量environment
-ApplicationContext#environment
systemProperties
-(Map) System.getProperties()
systemEnvironment
-(Map) System.getenv()
- 关联
BeanFactory 后置处理阶段
AbstractApplicationContext#postProcessBeanFactory(ConfigurableListableBeanFactory)
方法- 由子类覆盖该方法
org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory)
方法- 判断
BeanFactory
是不是BeanDefinitionRegistry
的实例DefaultListableBeanFactory
实现BeanDefinitionRegistry
- 如果是,调用
BeanFactoryPostProcessor
或BeanDefinitionRegistryPostProcessor
后置处理方法BeanDefinitionRegistryPostProcessor
继承BeanFactoryPostProcessor
BeanFactoryPostProcessor#postProcessBeanFactory
BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry
- 如果不是,只调用
BeanFactoryPostProcessor
后置处理方法BeanFactoryPostProcessor#postProcessBeanFactory
- 如果包含 beanName 是
loadTimeWeaver
的 bean,注册BeanPostProcessor
-LoadTimeWeaverAwareProcessor
对象,并设置容器的临时ClassLoader
,AbstractBeanFactory#tempClassLoader
- 与 AOP 相关
- 判断
执行顺序:
- 对
BeanDefinitionRegistryPostProcessor
进行处理- 执行
BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry
- 按照添加顺序执行,
AbstractApplicationContext#beanFactoryPostProcessors
中的BeanDefinitionRegistryPostProcessor
- 按照 Order 顺序执行,
BeanFactory
中实现了PriorityOrdered
的BeanDefinitionRegistryPostProcessor
Bean - 按照 Order 顺序执行,
BeanFactory
中实现了Ordered
的BeanDefinitionRegistryPostProcessor
Bean - 按照 Order 顺序执行,其他
BeanFactory
中的BeanDefinitionRegistryPostProcessor
Bean
- 按照添加顺序执行,
- 执行
BeanFactoryPostProcessor#postProcessBeanFactory
AbstractApplicationContext#beanFactoryPostProcessors
中的普通BeanFactoryPostProcessor
BeanFactory
中BeanDefinitionRegistryPostProcessor
- 执行
- 对
BeanFactoryPostProcessor
继续处理,BeanFactoryPostProcessor#postProcessBeanFactory
- 按照 Order 顺序执行,实现
PriorityOrdered
接口的BeanFactoryPostProcessor
- 按照 Order 顺序执行,实现
Ordered
接口的BeanFactoryPostProcessor
- 其他常规
BeanFactoryPostProcessor
- 按照 Order 顺序执行,实现
BeanFactory 注册 BeanPostProcessor 阶段
AbstractApplicationContext#registerBeanPostProcessors(ConfigurableListableBeanFactory)
方 法- 注册
PriorityOrdered
类型的BeanPostProcessor
Beans - 注册
Ordered
类型的BeanPostProcessor
Beans - 注册普通
BeanPostProcessor
Beans - 注册
MergedBeanDefinitionPostProcessor
BeansMergedBeanDefinitionPostProcessor
继承BeanPostProcessor
,生命周期在 MergedBeanDefinition 后
- 重新注册
ApplicationListenerDetector
对象- 为了将
ApplicationListenerDetector
的顺序放到最后
- 为了将
- 注册
初始化內建 Bean: MessageSource
AbstractApplicationContext#initMessageSource
方法- 如果
BeanFactory
中存在 beanName 为messageSource
的MessageSource
,则使用,否则注册DelegatingMessageSource
- 回顾章节 - 第十二章 Spring 国际化 -
MessageSource
内建依赖
- 如果
初始化內建 Bean: Spring 事件广播器
AbstractApplicationContext#initApplicationEventMulticaster
方法- 如果
BeanFactory
中存在 beanName 为applicationEventMulticaster
的ApplicationEventMulticaster
,则使用,否则注册SimpleApplicationEventMulticaster
- 回顾章节 - 第十七章 Spring 事件 -
ApplicationEventPublisher
底层实现
- 如果
Spring 应用上下文刷新阶段
AbstractApplicationContext#onRefresh
方法- 空方法,由子类覆盖该方法
org.springframework.web.context.support.AbstractRefreshableWebApplicationContext#onRefresh
org.springframework.web.context.support.GenericWebApplicationContext#onRefresh
org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext#onRefresh
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh
org.springframework.web.context.support.StaticWebApplicationContext#onRefresh
- 空方法,由子类覆盖该方法
Spring 事件监听器注册阶段
AbstractApplicationContext#registerListeners
方法- 将
ApplicationListener
添加到AbstractApplicationContext#applicationEventMulticaster
- 添加当前应用上下文所关联的
ApplicationListener
对象(集合) - 添加
BeanFactory
所注册ApplicationListener
Beans
- 添加当前应用上下文所关联的
- 广播早期 Spring 事件
AbstractApplicationContext#earlyApplicationEvents
- 将
BeanFactory 初始化完成阶段
AbstractApplicationContext#finishBeanFactoryInitialization(ConfigurableListableBeanFactory)
方法BeanFactory
关联ConversionService
Bean,如果存在- beanName 为
conversionService
的ConversionService
- beanName 为
添加
StringValueResolver
对象如果
AbstractBeanFactory#embeddedValueResolvers
为空,添加一个1
2
3if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
依赖查找
LoadTimeWeaverAware
BeanBeanFactory
临时ClassLoader
置为null
BeanFactory
冻结配置DefaultListableBeanFactory#configurationFrozen
DefaultListableBeanFactory#frozenBeanDefinitionNames
BeanFactory
初始化非延迟单例 Beans- 初始化非延迟单例 Bean
- 触发单例 Bean 中的
SmartInitializingSingleton
的生命周期,SmartInitializingSingleton#afterSingletonsInstantiated
Spring 应用上下文刷新完成阶段
AbstractApplicationContext#finishRefresh
方法- 清除
ResourceLoader
缓存 -clearResourceCaches()
@since 5.0 - 初始化
LifecycleProcessor
对象 -initLifecycleProcessor()
- 如果不存在 beanName 为
lifecycleProcessor
的LifecycleProcessor
,则使用DefaultLifecycleProcessor
- 如果不存在 beanName 为
- 调用
LifecycleProcessor#onRefresh()
方法 - 发布 Spring 应用上下文已刷新事件 -
ContextRefreshedEvent
- 向
MBeanServer
托管 Live Beans
- 清除
Spring 应用上下文启动阶段
AbstractApplicationContext#start()
方法- 启动
LifecycleProcessor
- 依赖查找
Lifecycle
Beans - 启动
Lifecycle
Beans
- 依赖查找
- 启动
- 发布 Spring 应用上下文已启动事件 -
ContextStartedEvent
Spring 应用上下文停止阶段
AbstractApplicationContext#stop()
方法- 停止
LifecycleProcessor
- 依赖查找
Lifecycle
Beans - 停止
Lifecycle
Beans
- 停止
- 发布 Spring 应用上下文已停止事件 -
ContextStoppedEvent
Spring 应用上下文关闭阶段
AbstractApplicationContext#close()
方法- 状态标识:
active(false)
、closed(true)
- Live Beans JMX 撤销托管
LiveBeansView#unregisterApplicationContext(ConfigurableApplicationContext)
- 发布 Spring 应用上下文已关闭事件 -
ContextCLosedEvent
- 关闭
LifecycleProcessor
- 依赖查找
Lifecycle
Beans - 停止
Lifecycle
Beans
- 依赖查找
- 销毁 Spring Beans
- 关闭
BeanFactory
- 回调
onClose()
- 注册 Shutdown Hook 线程(如果曾注册)
面试题
Spring 应用上下文生命周期有哪些阶段?
- 刷新阶段 -
ConfigurableApplicationContext#refresh()
- 启动阶段 -
ConfigurableApplicationContext#start()
- 停止阶段 -
ConfigurableApplicationContext#stop()
- 关闭阶段 -
ConfigurableApplicationContext#close()
Environment 完整的生命周期是怎样的?
Spring 应用上下文生命周期执行动作?
内容讨论
为什么说 ObjectFactory 提供的是延迟依赖查找?
- 原因
ObjectFactory
(或ObjectProvider
)可关联某一类型 BeanObjectFactory
和ObjectProvider
对象在被依赖注入和依赖查询时并未实时查找关联类型的 BeanObjectFactory
(或ObjectProvider
)调用getObject()
方法时,目标 Bean 才被依赖查找
- 总结
ObjectFactory
(或ObjectProvider
)相当于某一类型 Bean 依赖查找代理对象
依赖查找 (注入) 的 Bean 会被缓存吗?
- 单例 Bean (Singleton) - 会
- 缓存位置:
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#singletonObjects
属性
- 缓存位置:
- 原型 Bean (Prototype) - 不会
- 当依赖查询或依赖注入时,根据
BeanDefinition
每次创建
- 当依赖查询或依赖注入时,根据
- 其他 Scope Bean
- request : 每个 ServletRequest 内部缓存,生命周期维持在每次 HTTP 请求
- session : 每个 HttpSession 内部缓存,生命周期维持在每个用户 HTTP 会话
- application : 当前 Servlet 应用内部缓存
@Bean 的处理流程是怎样的?
- 解析范围 - Configuration Class 中的
@Bean
方法 - 方法类型 - 静态
@Bean
方法和实例@Bean
方法
BeanFactory 是如何处理循环依赖的?
- 循环依赖开关(方法)-
AbstractAutowireCapableBeanFactory#setAllowCircularReferences
- 单例工程(属性)-
DefaultSingletonBeanRegistry#singletonFactories
- 获取早期未处理 Bean (方法)-
AbstractAutowireCapableBeanFactory#getEarlyBeanReference
- 早期未处理 Bean (属性)-
DefaultSingletonBeanRegistry#earlySingletonObjects
MyBatis 与 Spring Framework 是如何集成的?
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!