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 优势在于 EnvironmentPropertySource

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 接口
  • PropertyPlaceholderConfigurerPropertySourcesPlaceholderConfigurer 都实现了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)
  • 注解:@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
  • ApplicationContextEnvironment 是一一对应的

  • 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 使用 PropertySourcesPropertyResolverPropertySourcesPropertyResolver 使用 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 接口继承关系

img

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 应用上下文底层 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 对象 - BeanFactoryResourceLoaderApplicationEventPublisher 以及 Applicationcontext
      • BeanFactoryApplicationContext 关联的 BeanFactory
      • ResourceLoaderApplicationEventPublisher 以及 Applicationcontext 都是 ApplicationContext
    • 添加 BeanPostProcessor - ApplicationListenerDetector
      • BeanPostProcessor#postProcessAfterInitialization 阶段,将单例的 ApplicationListener 加入 ApplicationContext
    • 如果包含 beanName 是 loadTimeWeaver 的 bean,注册 BeanPostProcessor - LoadTimeWeaverAwareProcessor 对象,并设置容器的临时 ClassLoaderAbstractBeanFactory#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
      • 如果是,调用 BeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor 后置处理方法
        • BeanDefinitionRegistryPostProcessor 继承 BeanFactoryPostProcessor
        • BeanFactoryPostProcessor#postProcessBeanFactory
        • BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry
      • 如果不是,只调用 BeanFactoryPostProcessor 后置处理方法 BeanFactoryPostProcessor#postProcessBeanFactory
    • 如果包含 beanName 是 loadTimeWeaver 的 bean,注册 BeanPostProcessor - LoadTimeWeaverAwareProcessor 对象,并设置容器的临时 ClassLoaderAbstractBeanFactory#tempClassLoader
      • 与 AOP 相关

执行顺序:

  1. BeanDefinitionRegistryPostProcessor 进行处理
    1. 执行 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry
      1. 按照添加顺序执行, AbstractApplicationContext#beanFactoryPostProcessors 中的 BeanDefinitionRegistryPostProcessor
      2. 按照 Order 顺序执行,BeanFactory 中实现了 PriorityOrderedBeanDefinitionRegistryPostProcessor Bean
      3. 按照 Order 顺序执行,BeanFactory 中实现了 OrderedBeanDefinitionRegistryPostProcessor Bean
      4. 按照 Order 顺序执行,其他 BeanFactory 中的 BeanDefinitionRegistryPostProcessor Bean
    2. 执行 BeanFactoryPostProcessor#postProcessBeanFactory
      1. AbstractApplicationContext#beanFactoryPostProcessors 中的普通 BeanFactoryPostProcessor
      2. BeanFactoryBeanDefinitionRegistryPostProcessor
  2. BeanFactoryPostProcessor 继续处理,BeanFactoryPostProcessor#postProcessBeanFactory
    1. 按照 Order 顺序执行,实现 PriorityOrdered 接口的 BeanFactoryPostProcessor
    2. 按照 Order 顺序执行,实现 Ordered 接口的 BeanFactoryPostProcessor
    3. 其他常规 BeanFactoryPostProcessor

BeanFactory 注册 BeanPostProcessor 阶段

  • AbstractApplicationContext#registerBeanPostProcessors(ConfigurableListableBeanFactory) 方 法
    • 注册 PriorityOrdered 类型的 BeanPostProcessor Beans
    • 注册 Ordered 类型的 BeanPostProcessor Beans
    • 注册普通 BeanPostProcessor Beans
    • 注册 MergedBeanDefinitionPostProcessor Beans
      • MergedBeanDefinitionPostProcessor 继承 BeanPostProcessor,生命周期在 MergedBeanDefinition 后
    • 重新注册 ApplicationListenerDetector 对象
      • 为了将 ApplicationListenerDetector 的顺序放到最后

初始化內建 Bean: MessageSource

  • AbstractApplicationContext#initMessageSource 方法
    • 如果 BeanFactory 中存在 beanName 为 messageSourceMessageSource ,则使用,否则注册 DelegatingMessageSource
    • 回顾章节 - 第十二章 Spring 国际化 - MessageSource 内建依赖

初始化內建 Bean: Spring 事件广播器

  • AbstractApplicationContext#initApplicationEventMulticaster 方法
    • 如果 BeanFactory 中存在 beanName 为 applicationEventMulticasterApplicationEventMulticaster ,则使用,否则注册 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 为 conversionServiceConversionService
    • 添加 StringValueResolver 对象

      • 如果 AbstractBeanFactory#embeddedValueResolvers 为空,添加一个

        if (!beanFactory.hasEmbeddedValueResolver()) {
        	beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
        }
        
    • 依赖查找 LoadTimeWeaverAware Bean

    • BeanFactory 临时 ClassLoader 置为 null

    • BeanFactory 冻结配置

      • DefaultListableBeanFactory#configurationFrozen
      • DefaultListableBeanFactory#frozenBeanDefinitionNames
    • BeanFactory 初始化非延迟单例 Beans

      1. 初始化非延迟单例 Bean
      2. 触发单例 Bean 中的 SmartInitializingSingleton 的生命周期, SmartInitializingSingleton#afterSingletonsInstantiated

Spring 应用上下文刷新完成阶段

  • AbstractApplicationContext#finishRefresh 方法
    • 清除 ResourceLoader 缓存 - clearResourceCaches() @since 5.0
    • 初始化 LifecycleProcessor 对象 - initLifecycleProcessor()
      • 如果不存在 beanName 为 lifecycleProcessorLifecycleProcessor,则使用 DefaultLifecycleProcessor
    • 调用 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 )可关联某一类型 Bean
    • ObjectFactoryObjectProvider 对象在被依赖注入和依赖查询时并未实时查找关联类型的 Bean
    • ObjectFactory (或 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 是如何集成的?

posted @ 2020-11-08 21:45  流星<。)#)))≦  阅读(558)  评论(0编辑  收藏  举报