Spring 应用上下文生命周期
Spring 应用上下文生命周期
Spring 应用上下文启动准备阶段
AbstractApplicationContext#prepareRefresh() 方法
- 启动时间 - startupDate
- 状态标识 - closed(false)、active(true)
- 初始化 PropertySources - initPropertySources()
- 检验 Environment 中必须属性
- 初始化事件监听器集合
- 初始化早期 Spring 事件集合
BeanFactory 创建阶段
AbstractApplicationContext#obtainFreshBeanFactory() 方法
- 刷新 Spring 应用上下文底层 BeanFactory - refreshBeanFactory()
- 销毁或关闭 BeanFactory,如果已存在的话
- 创建 BeanFactory - createBeanFactory()
- 设置 BeanFactory Id
- 设置“是否允许 BeanDefinition 重复定义” - customizeBeanFactory(DefaultListableBeanFactory)
- 设置“是否允许循环引用(依赖)” - customizeBeanFactory(DefaultListableBeanFactory)
- 加载 BeanDefinition - loadBeanDefinitions(DefaultListableBeanFactory) 方法
- 关联新建 BeanFactory 到 Spring 应用上下文
- 返回 Spring 应用上下文底层 BeanFactory - getBeanFactory()
BeanFactory 准备阶段
AbstractApplicationContext#prepareBeanFactory(ConfigurableListableBeanFactory) 方法
- 关联 ClassLoader
- 设置 Bean 表达式处理器
- 添加 PropertyEditorRegistrar 实现 - ResourceEditorRegistrar
- 添加 Aware 回调接口 BeanPostProcessor 实现 - ApplicationContextAwareProcessor
- 忽略 Aware 回调接口作为依赖注入接口
- 注册 ResolvableDependency 对象 - BeanFactory、ResourceLoader、ApplicationEventPublisher 以及 ApplicationContext
- 注册 ApplicationListenerDetector 对象
- 注册 LoadTimeWeaverAwareProcessor 对象
- 注册单例对象 - Environment、Java System Properties 以及 OS 环境变量
BeanFactory 后置处理阶段
- AbstractApplicationContext#postProcessBeanFactory(ConfigurableListableBeanFactory) 方法
- 由子类覆盖该方法
- AbstractApplicationContext#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory 方法
- 调用 BeanFactoryPostProcessor 或 BeanDefinitionRegistry 后置处理方法
- 注册 LoadTimeWeaverAwareProcessor 对象
BeanFactory 注册 BeanPostProcessor 阶段
AbstractApplicationContext#registerBeanPostProcessors(ConfigurableListableBeanFactory) 方法
- 注册 PriorityOrdered 类型的 BeanPostProcessor Beans
- 注册 Ordered 类型的 BeanPostProcessor Beans
- 注册普通 BeanPostProcessor Beans
- 注册 MergedBeanDefinitionPostProcessor Beans
- 注册 ApplicationListenerDetector 对象
初始化內建 Bean:MessageSource
AbstractApplicationContext#initMessageSource() 方法
初始化內建 Bean:Spring 事件广播器
AbstractApplicationContext#initApplicationEventMulticaster() 方法
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 对象(集合)
- 添加 BeanFactory 所注册 ApplicationListener Beans
- 广播早期 Spring 事件
BeanFactory 初始化完成阶段
AbstractApplicationContext#finishBeanFactoryInitialization(ConfigurableListableBeanFactory) 方法
- BeanFactory 关联 ConversionService Bean,如果存在
- 添加 StringValueResolver 对象
- 依赖查找 LoadTimeWeaverAware Bean
- BeanFactory 临时 ClassLoader 置为 null
- BeanFactory 冻结配置
- BeanFactory 初始化非延迟单例 Beans
Spring 应用上下刷新完成阶段
AbstractApplicationContext#finishRefresh() 方法
- 清除 ResourceLoader 缓存 - clearResourceCaches() @since 5.0
- 初始化 LifecycleProcessor 对象 - initLifecycleProcessor()
- 调用 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()
参考资料
Spring Environment 抽象
Spring Environment 抽象
理解 Spring Environment 抽象
统一的 Spring 配置属性管理
Spring Framework 3.1 开始引入 Environment 抽象,它统一 Spring 配置属性的存储,包括占位符处理和类型转换,不仅完整地替换 PropertyPlaceholderConfigurer,而且还支持更丰富的配置属性源(PropertySource)
条件化 Spring Bean 装配管理
通过 Environment Profiles 信息,帮助 Spring 容器提供条件化地装配 Bean
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
理解条件配置 Spring Profiles
Spring 3.1 条件配置
- API:org.springframework.core.env.ConfigurableEnvironment
- 修改:addActiveProfile(String)、setActiveProfiles(String…) 和 setDefaultProfiles(String…)
- 获取:getActiveProfiles() 和 getDefaultProfiles()
- 匹配:#acceptsProfiles(String…) 和 acceptsProfiles(Profiles)
- 注解:@org.springframework.context.annotation.Profile
Spring 4 重构 @Profile
基于 Spring 4 org.springframework.context.annotation.Condition 接口实现
org.springframework.context.annotation.ProfileCondition
依赖注入 Environment
直接依赖注入
- 通过 EnvironmentAware 接口回调
- 通过 @Autowired 注入 Environment
间接依赖注入
- 通过 ApplicationContextAware 接口回调
- 通过 @Autowired 注入 ApplicationContext
依赖查找 Environment
直接依赖查找
- 通过 org.springframework.context.ConfigurableApplicationContext#ENVIRONMENT_BEAN_NAME
间接依赖查找
- 通过 org.springframework.context.ConfigurableApplicationContext#getEnvironment
依赖注入 @Value
通过注入 @Value
实现 - org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
Spring 类型转换在 Environment 中的运用
Environment 底层实现
- 底层实现 - org.springframework.core.env.PropertySourcesPropertyResolver
- 核心方法 - convertValueIfNecessary(Object,Class)
- 底层服务 - org.springframework.core.convert.ConversionService
- 默认实现 - org.springframework.core.convert.support.DefaultConversionService
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
- 默认实现 - org.springframework.beans.TypeConverterDelegate
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
基于 API 扩展 Spring 配置属性源
- Spring 应用上下文启动前装配 PropertySource
- Spring 应用上下文启动后装配 PropertySource
问题
简单介绍 Spring Environment 接口?
- 核心接口 - org.springframework.core.env.Environment
- 父接口 - org.springframework.core.env.PropertyResolver
- 可配置接口 - org.springframework.core.env.ConfigurableEnvironment
- 职责:
- 管理 Spring 配置属性源
- 管理 Profiles
参考资料
Spring 注解
Spring 注解
Spring 注解驱动编程发展历程
- 注解驱动启蒙时代:Spring Framework 1.x
- 注解驱动过渡时代:Spring Framework 2.x
- 注解驱动黄金时代:Spring Framework 3.x
- 注解驱动完善时代:Spring Framework 4.x
- 注解驱动当下时代:Spring Framework 5.x
Spring 核心注解场景分类
Spring 模式注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@Repository | 数据仓储模式注解 | 2.0 |
@Component | 通用组件模式注解 | 2.5 |
@Service | 服务模式注解 | 2.5 |
@Controller | Web 控制器模式注解 | 2.5 |
@Configuration | 配置类模式注解 | 3.0 |
装配注解
Spring 注解 | 场景说明 | 起始版本 |
---|---|---|
@ImportResource | 替换 XML 元素 <import> |
2.5 |
@Import | 导入 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 Annotations)
理解 @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
- 注解元信息 - org.springframework.core.type.AnnotationMetadata
- ASM 实现 - org.springframework.core.type.classreading.AnnotationMetadataReadingVisitor
- 反射实现 - org.springframework.core.type.StandardAnnotationMetadata
Spring 组合注解(Composed Annotations)
Spring 组合注解(Composed Annotations)中的元注允许是 Spring 模式注解(Stereotype Annotation)与其他 Spring 功能性注解的任意组合。
Spring 注解属性别名(Attribute Aliases)
Spring 注解属性覆盖(Attribute Overrides)
Spring @Enable 模块驱动
@Enable 模块驱动
@Enable 模块驱动是以 @Enable 为前缀的注解驱动编程模型。所谓“模块”是指具备相同领域的功能组件集合,组合所形成⼀个独⽴的单元。⽐如 Web MVC 模块、AspectJ 代理模块、Caching(缓存)模块、JMX(Java 管理扩展)模块、Async(异步处理)模块等。
举例说明
- @EnableWebMvc
- @EnableTransactionManagement
- @EnableCaching
- @EnableMBeanExport
- @EnableAsync
@Enable 模块驱动编程模式
- 驱动注解:@EnableXXX
- 导入注解:@Import 具体实现
- 具体实现
- 基于 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
参考资料
Spring 事件
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
Java 标准事件 java.util.EventObject
扩展
- 扩展特性:事件发生事件戳
- Spring 应用上下文 ApplicationEvent 扩展 -
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
- 方法一:ApplicationListener 作为 Spring Bean 注册
- 方法二:通过 ConfigurableApplicationContext API 注册
Spring 事件发布器
- 方法一:通过 ApplicationEventPublisher 发布 Spring 事件
- 获取 ApplicationEventPublisher
- 依赖注入
- 获取 ApplicationEventPublisher
- 方法二:通过 ApplicationEventMulticaster 发布 Spring 事件
- 获取 ApplicationEventMulticaster
- 依赖注入
- 依赖查找
- 获取 ApplicationEventMulticaster
Spring 层次性上下文事件传播
- 发生说明
- 当 Spring 应用出现多层次 Spring 应用上下文(ApplicationContext)时,如 Spring WebMVC、Spring Boot 或 Spring Cloud 场景下,由子 ApplicationContext 发起 Spring 事件可能会传递到其 Parent ApplicationContext(直到 Root)的过程
- 如何避免
- 定位 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
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
- 实现限制:无法直接实现同步/异步动态切换
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.context.ApplicationListener
- 执行模式:同步/异步
- 异常处理: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 泛型处理
Java 泛型基础
泛型类型
- 泛型类型是在类型上参数化的泛型类或接口
泛型使用场景
- 编译时强类型检查
- 避免类型强转
- 实现通用算法
泛型类型擦写
- 泛型被引入到 Java 语言中,以便在编译时提供更严格的类型检查并支持泛型编程。类型擦除确保不会
为参数化类型创建新类;因此,泛型不会产生运行时开销。为了实现泛型,编译器将类型擦除应用于:- 将泛型类型中的所有类型参数替换为其边界,如果类型参数是无边界的,则将其替换为
“Object”。因此,生成的字节码只包含普通类、接口和方法 - 必要时插入类型转换以保持类型安全
- 生成桥方法以保留扩展泛型类型中的多态性
- 将泛型类型中的所有类型参数替换为其边界,如果类型参数是无边界的,则将其替换为
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 方法参数封装 - MethodParameter
核心 API - org.springframework.core.MethodParameter
- 起始版本:[2.0 , )
- 元信息
- 关联的方法 - Method
- 关联的构造器 - Constructor
- 构造器或方法参数索引 - parameterIndex
- 构造器或方法参数类型 - parameterType
- 构造器或方法参数泛型类型 - genericParameterType
- 构造器或方法参数参数名称 - parameterName
- 所在的类 - containingClass
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 类型转换
Spring 类型转换
Spring 类型转换的实现
- 基于 JavaBeans 接口的类型转换实现
- 基于 java.beans.PropertyEditor 接口扩展
- Spring 3.0+ 通用类型转换实现
使用场景
场景 | 基于 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 內建 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.PropertyEditorRegistry
注册自定义 PropertyEditor 实现
- 通用类型实现
registerCustomEditor(Class<?>, PropertyEditor)
- Java Bean 属性类型实现:
registerCustomEditor(Class<?>, String, PropertyEditor)
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 实现
局限二:仅能转换单一的 Source Type 和 Target Type
- 应对:使用 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 接口
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 - 通过
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
实现
问题
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 数据绑定
Spring 数据绑定
Spring 数据绑定(Data Binding)的作用是将用户的输入动态绑定到 JavaBean。换句话说,Spring 数据绑定机制是将属性值设置到目标对象中。
在 Spring 中,数据绑定功能主要由 DataBinder
类实现。此外,BeanWrapper
也具有类似的功能,但 DataBinder
额外支持字段验证、字段格式化和绑定结果分析。
快速入门
定义一个用于测试的 JavaBean
1 | public class TestBean { |
数据绑定示例
1 | public class DataBindingDemo { |
Spring 数据绑定使用场景
- Spring
BeanDefinition
到 Bean 实例创建 - Spring 数据绑定(
DataBinder
) - Spring Web 参数绑定(
WebDataBinder
)
DataBinder
在 Spring 中,DataBinder
类是数据绑定功能的基类。WebDataBinder
是 DataBinder
的子类,主要用于 Spring Web 数据绑定,此外,还有一些 WebDataBinder
的扩展子类,其类族如下图所示:
DataBinder 核心属性:
属性 | 说明 |
---|---|
target |
关联目标 Bean |
objectName |
目标 Bean 名称 |
bindingResult |
属性绑定结果 |
typeConverter |
类型转换器 |
conversionService |
类型转换服务 |
messageCodesResolver |
校验错误文案 Code 处理器 |
validators |
关联的 Bean Validator 实例集合 |
DataBinder
类的核心方法是 bind(PropertyValues)
:将 PropertyValues Key-Value 内容映射到关联 Bean(target)中的属性上
- 假设 PropertyValues 中包含 name=dunwu 的键值对时, 同时 Bean 对象 User 中存在 name 属性, 当 bind 方法执行时, User 对象中的 name 属性值将被绑定为 dunwu
Spring 数据绑定元数据
DataBinder 元数据 - PropertyValues
特征 | 说明 |
---|---|
数据来源 | BeanDefinition,主要来源 XML 资源配置 BeanDefinition |
数据结构 | 由一个或多个 PropertyValue 组成 |
成员结构 | PropertyValue 包含属性名称,以及属性值(包括原始值、类型转换后的值) |
常见实现 | MutablePropertyValues |
Web 扩展实现 | ServletConfigPropertyValues、ServletRequestParameterPropertyValues |
相关生命周期 | InstantiationAwareBeanPostProcessor#postProcessProperties |
Spring 数据绑定控制参数
DataBinder 绑定特殊场景分析
- 当 PropertyValues 中包含名称 x 的 PropertyValue,目标对象 B 不存在 x 属性,当 bind 方法执
行时,会发生什么? - 当 PropertyValues 中包含名称 x 的 PropertyValue,目标对象 B 中存在 x 属性,当 bind 方法执
行时,如何避免 B 属性 x 不被绑定? - 当 PropertyValues 中包含名称 x.y 的 PropertyValue,目标对象 B 中存在 x 属性(嵌套 y 属性)
,当 bind 方法执行时,会发生什么?
DataBinder 绑定控制参数
参数名称 | 说明 |
---|---|
ignoreUnknownFields | 是否忽略未知字段,默认值:true |
ignoreInvalidFields | 是否忽略非法字段,默认值:false |
autoGrowNestedPaths | 是否自动增加嵌套路径,默认值:true |
allowedFields | 绑定字段白名单 |
disallowedFields | 绑定字段黑名单 |
requiredFields | 必须绑定字段 |
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)
Spring 替代实现 - org.springframework.beans.BeanWrapper
- 属性(Property)
java.beans.PropertyEditor
- 嵌套属性路径(nested path)
DataBinder 数据校验
DataBinder 与 BeanWrapper
- bind 方法生成 BeanPropertyBindingResult
- BeanPropertyBindingResult 关联 BeanWrapper
问题
标准 JavaBeans 是如何操作属性的?
API | 说明 |
---|---|
java.beans.Introspector | Java Beans 内省 API |
java.beans.BeanInfo | Java Bean 元信息 API |
java.beans.BeanDescriptor | Java Bean 信息描述符 |
java.beans.PropertyDescriptor | Java Bean 属性描述符 |
java.beans.MethodDescriptor | Java Bean 方法描述符 |
java.beans.EventSetDescriptor | Java Bean 事件集合描述符 |
参考资料
Spring 校验
Spring 校验
Java API 规范(JSR303
)定义了Bean
校验的标准validation-api
,但没有提供实现。hibernate validation
是对这个规范的实现,并增加了校验注解如@Email
、@Length
等。Spring Validation
是对hibernate validation
的二次封装,用于支持spring mvc
参数自动校验。
快速入门
引入依赖
如果 spring-boot 版本小于 2.3.x,spring-boot-starter-web 会自动传入 hibernate-validator 依赖。如果 spring-boot 版本大于 2.3.x,则需要手动引入依赖:
1 | <dependency> |
对于 web 服务来说,为防止非法参数对业务造成影响,在 Controller 层一定要做参数校验的!大部分情况下,请求参数分为如下两种形式:
- POST、PUT 请求,使用 requestBody 传递参数;
- GET 请求,使用 requestParam/PathVariable 传递参数。
实际上,不管是 requestBody 参数校验还是方法级别的校验,最终都是调用 Hibernate Validator 执行校验,Spring Validation 只是做了一层封装。
校验示例
(1)在实体上标记校验注解
1 | @Data |
(2)在方法参数上声明校验注解
1 | @Slf4j |
(3)如果请求参数不满足校验规则,则会抛出 ConstraintViolationException
或 MethodArgumentNotValidException
异常。
统一异常处理
在实际项目开发中,通常会用统一异常处理来返回一个更友好的提示。
1 | @Slf4j |
进阶使用
分组校验
在实际项目中,可能多个方法需要使用同一个 DTO 类来接收参数,而不同方法的校验规则很可能是不一样的。这个时候,简单地在 DTO 类的字段上加约束注解无法解决这个问题。因此,spring-validation 支持了分组校验的功能,专门用来解决这类问题。
(1)定义分组
1 | @Target({ ElementType.FIELD, ElementType.PARAMETER }) |
(2)在实体上标记校验注解
1 | @Data |
(3)在方法上根据不同场景进行校验分组
1 | @Slf4j |
嵌套校验
前面的示例中,DTO 类里面的字段都是基本数据类型和 String 类型。但是实际场景中,有可能某个字段也是一个对象,这种情况先,可以使用嵌套校验。
post
比如,上面保存 User 信息的时候同时还带有 Job 信息。需要注意的是,此时 DTO 类的对应字段必须标记@Valid 注解。
1 | @Data |
嵌套校验可以结合分组校验一起使用。还有就是嵌套集合校验会对集合里面的每一项都进行校验,例如List<Job>
字段会对这个 list 里面的每一个 Job 对象都进行校验
自定义校验注解
(1)自定义校验注解 @IsMobile
1 | @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) |
(2)实现 ConstraintValidator
接口,编写 @IsMobile
校验注解的解析器
1 | import cn.hutool.core.util.StrUtil; |
自定义校验
可以通过实现 org.springframework.validation.Validator
接口来自定义校验。
有以下要点
- 实现
supports
方法 - 实现
validate
方法- 通过
Errors
对象收集错误ObjectError
:对象(Bean)错误:FieldError
:对象(Bean)属性(Property)错误
- 通过
ObjectError
和FieldError
关联MessageSource
实现获取最终的错误文案
- 通过
1 | package io.github.dunwu.spring.core.validation; |
快速失败(Fail Fast)
Spring Validation 默认会校验完所有字段,然后才抛出异常。可以通过一些简单的配置,开启 Fali Fast 模式,一旦校验失败就立即返回。
1 | @Bean |
Spring 校验原理
Spring 校验使用场景
- Spring 常规校验(Validator)
- Spring 数据绑定(DataBinder)
- Spring Web 参数绑定(WebDataBinder)
- Spring WebMVC/WebFlux 处理方法参数校验
Validator 接口设计
- 接口职责
- Spring 内部校验器接口,通过编程的方式校验目标对象
- 核心方法
supports(Class)
:校验目标类能否校验validate(Object,Errors)
:校验目标对象,并将校验失败的内容输出至 Errors 对象
- 配套组件
- 错误收集器:
org.springframework.validation.Errors
- Validator 工具类:
org.springframework.validation.ValidationUtils
- 错误收集器:
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
)
spring web 校验原理
RequestBody 参数校验实现原理
在 spring-mvc 中,RequestResponseBodyMethodProcessor
是用于解析 @RequestBody
标注的参数以及处理@ResponseBody
标注方法的返回值的。其中,执行参数校验的逻辑肯定就在解析参数的方法 resolveArgument()
中:
1 | @Override |
可以看到,resolveArgument()调用了 validateIfApplicable()进行参数校验。
1 | protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) { |
以上代码,就解释了 Spring 为什么能同时支持 @Validated
、@Valid
两个注解。
接下来,看一下 WebDataBinder.validate() 的实现:
1 | @Override |
通过上面代码,可以看出 Spring 校验实际上是基于 Hibernate Validator 的封装。
方法级别的参数校验实现原理
Spring 支持根据方法去进行拦截、校验,原理就在于应用了 AOP 技术。具体来说,是通过 MethodValidationPostProcessor
动态注册 AOP 切面,然后使用 MethodValidationInterceptor
对切点方法织入增强。
1 | public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessorimplements InitializingBean { |
接着看一下 MethodValidationInterceptor
:
1 | public class MethodValidationInterceptor implements MethodInterceptor { |
实际上,不管是 requestBody 参数校验还是方法级别的校验,最终都是调用 Hibernate Validator 执行校验,Spring Validation 只是做了一层封装。
问题
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 国际化使用场景
- 普通国际化文案
- 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
ResourceBundle
核心特性
- Key-Value 设计
- 层次性设计
- 缓存设计
- 字符编码控制 -
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 Bean
- 默认內建实现 - DelegatingMessageSource
- 层次性查找 MessageSource 对象
问题
Spring Boot 为什么要新建 MessageSource Bean?
- AbstractApplicationContext 的实现决定了 MessageSource 內建实现
- Spring Boot 通过外部化配置简化 MessageSource Bean 构建
- Spring Boot 基于 Bean Validation 校验非常普遍
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