第十九章: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
if (!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
@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
为空,添加一个if (!beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); }
-
-
依赖查找
LoadTimeWeaverAware
Bean -
BeanFactory
临时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