20201108 小马哥讲Spring核心编程思想 - 笔记 19-20
第十九章: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.Conditionalorg.springframework.context.annotation.Conditionorg.springframework.context.annotation.ProfileCondition
依赖注入 Environment
-
直接依赖注入
- 通过
EnvironmentAware接口回调 - 通过
@Autowired注入Environment
- 通过
-
间接依赖注入
- 通过
ApplicationContextAware接口回调 - 通过
@Autowired注入ApplicationContext
- 通过
-
ApplicationContext和Environment是一一对应的 -
在
AbstractApplicationContext#prepareBeanFactory中,以单例形式,将Environment注入了BeanFactoryif (!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#injectorg.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.AutowiredAnnotationBeanPostProcessororg.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
- 底层服务 -
org.springframework.beans.TypeConverter- 默认实现 -
org.springframework.beans.TypeConverterDelegatejava.beans.PropertyEditororg.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#doProcessConfigurationClassorg.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#factoryorg.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#getPropertySourcesorg.springframework.core.env.MutablePropertySourcesMutablePropertySources中存在控制 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,默认为空,可设置
- 初始化事件监听器集合
earlyApplicationListenersapplicationListeners
- 初始化早期 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实现 -ResourceEditorRegistrarorg.springframework.beans.support.ResourceEditorRegistrar
- 添加
Aware回调接口BeanPostProcessor实现 -ApplicationContextAwareProcessorEnvironmentAwareEmbeddedValueResolverAwareResourceLoaderAwareApplicationEventPublisherAwareMessageSourceAwareApplicationContextAware
- 忽略
Aware回调接口作为依赖注入接口 - 注册 ResolvableDependency 对象 -
BeanFactory、ResourceLoader、ApplicationEventPublisher以及ApplicationcontextBeanFactory是ApplicationContext关联的BeanFactoryResourceLoader、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#environmentsystemProperties-(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继承BeanFactoryPostProcessorBeanFactoryPostProcessor#postProcessBeanFactoryBeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry
- 如果不是,只调用
BeanFactoryPostProcessor后置处理方法BeanFactoryPostProcessor#postProcessBeanFactory
- 如果包含 beanName 是
loadTimeWeaver的 bean,注册BeanPostProcessor-LoadTimeWeaverAwareProcessor对象,并设置容器的临时ClassLoader,AbstractBeanFactory#tempClassLoader- 与 AOP 相关
- 判断
执行顺序:
- 对
BeanDefinitionRegistryPostProcessor进行处理- 执行
BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry- 按照添加顺序执行,
AbstractApplicationContext#beanFactoryPostProcessors中的BeanDefinitionRegistryPostProcessor - 按照 Order 顺序执行,
BeanFactory中实现了PriorityOrdered的BeanDefinitionRegistryPostProcessorBean - 按照 Order 顺序执行,
BeanFactory中实现了Ordered的BeanDefinitionRegistryPostProcessorBean - 按照 Order 顺序执行,其他
BeanFactory中的BeanDefinitionRegistryPostProcessorBean
- 按照添加顺序执行,
- 执行
BeanFactoryPostProcessor#postProcessBeanFactoryAbstractApplicationContext#beanFactoryPostProcessors中的普通BeanFactoryPostProcessorBeanFactory中BeanDefinitionRegistryPostProcessor
- 执行
- 对
BeanFactoryPostProcessor继续处理,BeanFactoryPostProcessor#postProcessBeanFactory- 按照 Order 顺序执行,实现
PriorityOrdered接口的BeanFactoryPostProcessor - 按照 Order 顺序执行,实现
Ordered接口的BeanFactoryPostProcessor - 其他常规
BeanFactoryPostProcessor
- 按照 Order 顺序执行,实现
BeanFactory 注册 BeanPostProcessor 阶段
AbstractApplicationContext#registerBeanPostProcessors(ConfigurableListableBeanFactory)方 法- 注册
PriorityOrdered类型的BeanPostProcessorBeans - 注册
Ordered类型的BeanPostProcessorBeans - 注册普通
BeanPostProcessorBeans - 注册
MergedBeanDefinitionPostProcessorBeansMergedBeanDefinitionPostProcessor继承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#onRefreshorg.springframework.web.context.support.GenericWebApplicationContext#onRefreshorg.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext#onRefreshorg.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefreshorg.springframework.web.context.support.StaticWebApplicationContext#onRefresh
- 空方法,由子类覆盖该方法
Spring 事件监听器注册阶段
AbstractApplicationContext#registerListeners方法- 将
ApplicationListener添加到AbstractApplicationContext#applicationEventMulticaster- 添加当前应用上下文所关联的
ApplicationListener对象(集合) - 添加
BeanFactory所注册ApplicationListenerBeans
- 添加当前应用上下文所关联的
- 广播早期 Spring 事件
AbstractApplicationContext#earlyApplicationEvents
- 将
BeanFactory 初始化完成阶段
AbstractApplicationContext#finishBeanFactoryInitialization(ConfigurableListableBeanFactory)方法-
BeanFactory关联ConversionServiceBean,如果存在- beanName 为
conversionService的ConversionService
- beanName 为
-
添加
StringValueResolver对象-
如果
AbstractBeanFactory#embeddedValueResolvers为空,添加一个if (!beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); }
-
-
依赖查找
LoadTimeWeaverAwareBean -
BeanFactory临时ClassLoader置为null -
BeanFactory冻结配置DefaultListableBeanFactory#configurationFrozenDefaultListableBeanFactory#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- 依赖查找
LifecycleBeans - 启动
LifecycleBeans
- 依赖查找
- 启动
- 发布Spring应用上下文已启动事件 -
ContextStartedEvent
Spring 应用上下文停止阶段
AbstractApplicationContext#stop()方法- 停止
LifecycleProcessor - 依赖查找
LifecycleBeans - 停止
LifecycleBeans
- 停止
- 发布 Spring 应用上下文已停止事件 -
ContextStoppedEvent
Spring 应用上下文关闭阶段
AbstractApplicationContext#close()方法- 状态标识:
active(false)、closed(true) - Live Beans JMX 撤销托管
LiveBeansView#unregisterApplicationContext(ConfigurableApplicationContext)
- 发布 Spring 应用上下文已关闭事件 -
ContextCLosedEvent - 关闭
LifecycleProcessor- 依赖查找
LifecycleBeans - 停止
LifecycleBeans
- 依赖查找
- 销毁 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
浙公网安备 33010602011771号