thinking-in-spirng

第一章:Spring Framework 总览(Overview)

Spring Framework 版本Java 标准版Java 企业版
1.x1.3+J2EE 1.3 +
2.x1.4.2+J2EE 1.3 +
3.x5+J2EE 1.4 和 Java EE 5
4.x6+Java EE 6 和 7
5.x8+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 名称 + 类型查找 beanFactory.getBean("user", User.class);
  • 根据 Java 注解查找
  • 单个 Bean 对象
    • 集合 Bean 对象

3.2 Spring IoC 依赖注入:

  • 根据 Bean 名称注入
  • 根据 Bean 类型注入
    • 单个 Bean 对象
    • 集合 Bean 对象
  • 注入容器內建 Bean 对象
  • 注入非 Bean 对象
  • 注入类型
    • 实时注入
    • 延迟注入

延迟查找和延迟注入,使用到接口 org.springframework.beans.factory.ObjectProviderorg.springframework.beans.factory.ObjectFactoryObjectProvider 继承 ObjectFactory

BeanFactoryApplicationContext 谁才是 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...)
  • 外部单例对象注册
    • Java API 配置元信息
      • SingletonBeanRegistry#registerSingleton

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)

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)

第五章: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 5.1 Bean 延迟查找
      • getBeanProvider(Class)
      • getBeanProvider(ResolvableType)
  • 根据 Bean 名称 + 类型查找:getBean(String,Class)

集合类型依赖查找接口 - ListableBeanFactory

  • 根据 Bean 类型查找
    • 获取同类型 Bean 名称列表
      • getBeanNamesForType(Class)
      • Spring 4.2 getBeanNamesForType(ResolvableType)
    • 获取同类型 Bean 实例列表
      • getBeansOfType(Class) 以及重载方法
  • 通过注解类型查找
    • 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>)

层次性依赖查找接口 - HierarchicalBeanFactory

  • 双亲 BeanFactory:getParentBeanFactory()
  • 层次性查找
    • 根据 Bean 名称查找
      • 基于 containsLocalBean 方法实现
    • 根据 Bean 类型查找实例列表
      • 单一类型:BeanFactoryUtils#beanOfType
      • 集合类型:BeanFactoryUtils#beansOfTypeIncludingAncestors
    • 根据 Java 注解查找名称列表
      • BeanFactoryUtils#beanNamesForTypeIncludingAncestors

Bean 延迟依赖查找接口

  • org.springframework.beans.factory.ObjectFactory
  • org.springframework.beans.factory.ObjectProvider
    • Spring 5 对 Java 8 特性扩展
      • 函数式接口
        • getIfAvailable(Supplier)
        • ifAvailable(Consumer)
      • Stream 扩展 - stream()

依赖查找安全性对比:

依赖查找类型代表实现是否安全
单一类型查找BeanFactory#getBean
ObjectFactory#getObject
ObjectProvider#getIfAvailable
集合类型查找ListableBeanFactory#getBeansOfType
ObjectProvider#stream

注意:层次性依赖查找的安全性取决于其扩展的单一或集合类型的 BeanFactory 接口

AbstractApplicationContext 内建可查找的依赖

Bean 名称Bean 实例使用场景
environmentEnvironment 对象外部化配置以及 Profiles
systemPropertiesjava.util.Properties 对象Java 系统属性
systemEnvironmentjava.util.Map 对象操作系统环境变量
messageSourceMessageSource 对象国际化文案
lifecycleProcessorLifecycleProcessor 对象Lifecycle Bean 处理器
applicationEventMulticasterApplicationEventMulticaster 对 象Spring 事件广播器

注解驱动 Spring 应用上下文内建可查找的依赖

Bean 名称Bean 实例使用场景
org.springframework.context.annotation.internalConfigurationAnnotationProcessorConfigurationClassPostProcesso处理 Spring 配置类
org.springframework.context.annotation.internalAutowiredAnnotationProcessorAutowiredAnnotationBeanPostProcessor 对象处理 @Autowired 以及 @Value 注解
org.springframework.context.annotation.internalCommonAnnotationProcessorCommonAnnotationBeanPostProcessor 对象(条件激活)处理 JSR-250 注解,如 @PostConstruct 等
org.springframework.context.event.internalEventListenerProcessorEventListenerMethodProcessor 对象处理标注 @EventListener 的 Spring 事件监听方法
org.springframework.context.event.internalEventListenerFactoryDefaultEventListenerFactory 对象@EventListener 事件监听方法适配为 ApplicationListener
org.springframework.context.annotation.internalPersistenceAnnotationProcessorPersistenceAnnotationBeanPostProcessor 对象(条件激活)处理 JPA 注解场景

依赖查找中的经典异常,BeansException 子类型

异常类型触发条件(举例)场景举例
NoSuchBeanDefinitionException当查找 Bean 不存在于 IoC 容器时 BeanFactory#getBeanObjectFactory#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
  • 延迟依赖注入

  • 使用 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 依赖来源

来源配置元数据注册 APISpring Bean 对象生命周期管理配置元信息使用场景
Spring BeanDefinition<bean>
@Bean public User user(){...}
BeanDefinitionBuilder
BeanDefinitionRegistry#registerBeanDefinition依赖查找、依赖注入
单例对象API 实现SingletonBeanRegistry#registerSingleton依赖查找、依赖注入
非 Spring 容器管理对象Resolvable DependencyConfigurableListableBeanFactory#registerResolvableDependency依赖注入
外部化配置@ValueObject 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
2
3
4
5
6
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

后三个实际上都是同一个 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
2
3
4
5
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public static User prototypeUser() {
return createUser();
}

“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
  • 面向注解 BeanDefinition 解析 - AnnotatedBeanDefinitionReader

Spring Bean 注册阶段

BeanDefinition 注册接口

BeanDefinitionRegistry

Spring BeanDefinition 合并阶段

BeanDefinition 合并

父子 BeanDefinition 合并

  • 当前 BeanFactory 查找
  • 层次性 BeanFactory 查找
1
2
3
4
5
6
7
8
9
<bean id="user" class="org.geekbang.thinking.in.spring.ioc.overview.domain.User">
<property />
...
</bean>

<bean id="superUser" class="org.geekbang.thinking.in.spring.ioc.overview.domain.SuperUser" parent="user"
primary="true">
<property />
</bean>

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
2
3
4
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>) () ->
doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
}

临时 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 之前,对它们进行处理。

在依赖注入( byNamebyType )之后,在将配置的属性赋值给 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 ,这个方法做了两件事情:

  1. 将已注册的 BeanDefinition 初始化成 Spring Bean
  2. 调用所有 SmartInitializingSingleton#afterSingletonsInstantiated

Spring Bean 销毁前阶段

  • 方法回调
    • DestructionAwareBeanPostProcessor#postProcessBeforeDestruction

执行 ConfigurableBeanFactory#destroyBean 时,触发 Bean 前销毁阶段

@PreDestroy 的处理需要依赖于注解驱动,CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction

Spring Bean 销毁阶段

Bean 销毁(Destroy)

  • @PreDestroy 标注方法
  • 实现 DisposableBean 接口的 destroy() 方法
  • 自定义销毁方法

@PreDestroy 的处理需要依赖于注解驱动,CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction

CommonAnnotationBeanPostProcessorDestructionAwareBeanPostProcessor 的实现类之一

如果其他 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 元素属性默认值使用场景
profilenull(留空)Spring Profiles 配置值
default-lazy-initdefault当 outter beans “default-lazy-init” 属性存在时,继承该值,否则为 “false”
default-mergedefault当 outter beans “default-merge” 属性存在时,继承该值,否则为 “false”
default-autowiredefault当 outter beans “default-autowire” 属性存在时,继承该值,否则为 “no”
default-autowire-candidatesnull(留空)默认 Spring Beans 名称 pattern
default-init-methodnull(留空)默认 Spring Beans 自定义初始化方法
default-destroy-methodnull(留空)默认 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

  1. 判断 beans 标签的 profile 属性,如果不在激活状态,直接返回,不再向下解析
  2. 如果是 beans 标签下的特殊元素,进行特殊处理,方法为 DefaultBeanDefinitionDocumentReader#parseDefaultElement
    • beans
    • bean
    • alias
    • import
  3. 否则,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
@ControllerWeb 控制器模式注解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 注解场景说明起始版本
@AutowiredBean 依赖注入,支持多种依赖查找方式2.5
@Qualifier细粒度的 @Autowired 依赖查找2.5

AutowiredAnnotationBeanPostProcessor@Autowired 相关

Java 注解场景说明起始版本
@Resource类似于 @Autowired2.5
@Inject类似于 @Autowired2.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="..." />InitializingBean2.5
@PreDestroy替换 XML 元素 <bean destroy-method="..." />DisposableBean2.5

CommonAnnotationBeanPostProcessor

Spring Bean 配置元信息底层实现

Spring BeanDefinition 解析与注册

实现场景实现类起始版本
XML 资源XmlBeanDefinitionReader1.0
Properties 资源PropertiesBeanDefinitionReader1.0
Java 注解AnnotatedBeanDefinitionReader3.0
  • XmlBeanDefinitionReaderPropertiesBeanDefinitionReader 都继承自 AbstractBeanDefinitionReader,实现了 BeanDefinitionReader 接口,与资源(Resource)相关联

  • AnnotatedBeanDefinitionReader 是独立的类,与 Resource 无关

  • Spring XML 资源 BeanDefinition 解析与注册

    • 核心 API - XmlBeanDefinitionReader
      • 资源 - Resource
      • 底层 - BeanDefinitionDocumentReader
        • XML 解析 - Java DOM Level 3 API
        • BeanDefinition 解析 - BeanDefinitionParserDelegate
        • BeanDefinition 注册 - BeanDefinitionRegistry
  • Spring Properties 资源 BeanDefinition 解析与注册

    • 核心 API - PropertiesBeanDefinitionReader
      • 资源
        • 字节流 - Resource
        • 字符流 - EncodedResouce
      • 底层
        • 存储 - java.util.Properties
        • BeanDefinition 解析 - API 内部实现
        • BeanDefinition 注册 - BeanDefinitionRegistry
  • Spring Java 注册 BeanDefinition 解析与注册

    • 核心 API - AnnotatedBeanDefinitionReader
      • 资源
        • 类对象 - java.lang.Class
      • 底层
        • 条件评估 - ConditionEvaluator
        • Bean 范围解析 - ScopeMetadataResolver
        • BeanDefinition 解析 - 内部 API 实现
        • BeanDefinition 处理 - AnnotationConfigUtils.processCommonDefinitionAnnotations
        • BeanDefinition 注册 - BeanDefinitionRegistry

Properties 资源加载默认编码是 ISO-8859-1

AnnotatedBeanDefinitionReader 使用 ConditionEvaluator 判断 Bean 的元信息,如果其中存在 @Conditional 条件,判断此条件通过才会将 Bean 加入容器

基于 XML 资源装载 Spring IoC 容器配置元信息

Spring IoC 容器相关 XML 配置

命名空间所属模块Schema 资源 URL
beansspring-beanshttps://www.springframework.org/schema/beans/spring-beans.xsd
contextspring-contexthttps://www.springframework.org/schema/context/spring-context.xsd
aopspring-aophttps://www.springframework.org/schema/aop/spring-aop.xsd
txspring-txhttps://www.springframework.org/schema/tx/spring-tx.xsd
utilspring-beanshttps://www.springframework.org/schema/util/spring-util.xsd
toolspring-beanshttps://www.springframework.org/schema/tool/spring-tool.xsd

基于 Java 注解装载 Spring IoC 容器配置元信息

Spring IoC 容器装配注解

Spring 注解场景说明起始版本
@ImportResource替换 XML 元素 <import>3.0
@Import导入 Configuration Class3.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
2
3
4
@PropertySource(
name = "yamlPropertySource",
value = "classpath:/META-INF/user.yaml",
factory = YamlPropertySourceFactory.class)

面试题

Spring 內建 XML Schema 常见有哪些?

命名空间所属模块Schema 资源 URL
beansspring-beanshttps://www.springframework.org/schema/beans/spring-beans.xsd
contextspring-contexthttps://www.springframework.org/schema/context/spring-context.xsd
aopspring-aophttps://www.springframework.org/schema/aop/spring-aop.xsd
txspring-txhttps://www.springframework.org/schema/tx/spring-tx.xsd
utilspring-beanshttps://www.springframework.org/schema/util/spring-util.xsd
toolspring-beanshttps://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 內建协议实现

协议实现类
filesun.net.www.protocol.file.Handler
ftpsun.net.www.protocol.ftp.Handler
httpsun.net.www.protocol.http.Handler
httpssun.net.www.protocol.https.Handler
jarsun.net.www.protocol.jar.Handler
mailtosun.net.www.protocol.mailto.Handler
netdocsun.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
URLURL 支持的协议org.springframework.core.io.UrlResource
ServletContextorg.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

Spring 通配路径资源扩展

  1. 实现 org.springframework.util.PathMatcher
  2. 重置 PathMatcher
    • PathMatchingResourcePatternResolver#setPathMatcher

依赖注入 Spring Resource

基于 @Value 实现

1
2
3
4
5
@Value("classpath:/...") 
private Resource resource;

@Value("classpath*:/META-INF/*.properties")
private Resource[] propertiesResources;

依赖注入 ResourceLoader

  • 方法一:实现 ResourceLoaderAware 回调
  • 方法二:@Autowired 注入 ResourceLoader
  • 方法三:注入 ApplicationContext 作为 ResourceLoader

ApplicationContext 接口继承 ResourcePatternResolver 继承 ResourceLoader

ResourceLoaderAware 回调在 实例初始化(@PostConstruct 等)之前

面试题

Spring 配置资源中有哪些常见类型?

  • XML 资源
  • Properties 资源
  • YAML 资源

请例举不同类型 Spring 配置资源?

  • XML 资源
    • 普通 Bean Definition XML 配置资源 - *.xml
    • Spring Schema 资源 - *.xsd
  • Properties 资源
    • 普通 Properties 格式资源 - *.properties
    • Spring Handler 实现类映射文件 - META-INF/spring.handlers
    • Spring Schema 资源映射文件 - META-INF/spring.schemas
  • YAML 资源
    • 普通 YAML 配置资源 - *.yaml*.yml

Java 标准资源管理扩展的步骤?

  • 简易实现
    • 实现 URLStreamHandler 并放置在 sun.net.www.protocol.${protocol}.Handler 包下
  • 自定义实现
    • 实现 URLStreamHandler
    • 添加 -Djava.protocol.handler.pkgs 启动参数,指向 URLStreamHandler 实现类的包下
  • 高级实现
    • 实现 URLStreamHandlerFactory 并传递到 URL 之中
简易实现实例
  1. 扩展 x 协议,新建类 sun.net.www.protocol.x.Handler,类名格式必须符合规范

    1
    2
    3
    4
    5
    6
    public class Handler extends URLStreamHandler {
    @Override
    protected URLConnection openConnection(URL u) throws IOException {
    return new XURLConnection(u);
    }
    }
  2. 新建类 XURLConnection ,实现 java.net.URLConnection

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public 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();
    }
    }
  3. 测试使用

    1
    2
    3
    4
    5
    6
    7
    8
    public 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")));
    }
    }
自定义实现
  1. 新建类 Handler,继承 sun.net.www.protocol.x.Handle,类名必须为 Handler,包名无限制

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public 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")));
    }
    }
  2. 运行时增加 VM 参数,-Djava.protocol.handler.pkgs=org.geekbang.thinking.in.spring.resource

高级实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MyURLStreamHandlerFactory implements URLStreamHandlerFactory {
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
return new Handler();
}

public static void main(String[] args) throws IOException {
// URL 设置 URLStreamHandlerFactory,必须在创建 URL 实例之前
URL.setURLStreamHandlerFactory(new MyURLStreamHandlerFactory());
// 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")));
}
}

本文由 简悦 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

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:消息格式类型,可选项,每种类型在 numberdatetimechoice 类型选其一
    • FormatStyle:消息格式风格,可选项,包括:shortmediumlongfullintegercurrencypercent

高级特性

  • 重置消息格式模式
  • 重置 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

Errors 文案来源

Errors 文案生成步骤

  • 选择 Errors 实现(如:org.springframework.validation.BeanPropertyBindingResult
  • 调用 rejectrejectValue 方法
  • 获取 Errors 对象中 ObjectErrorFieldError
  • ObjectErrorFieldError 中的 codeargs,关联 MessageSource 实现(如:ResourceBundleMessageSource

Errors 不能直接生成文案,但是可以提供国际化接口 MessageSource 所需要的 codeargs

自定义 Validator

实现 org.springframework.validation.Validator 接口

  • 实现 supports 方法
  • 实现 validate 方法
    • 通过 Errors 对象收集错误
      • ObjectError:对象(Bean)错误:
      • FieldError:对象(Bean)属性(Property)错误
    • 通过 ObjectErrorFieldError 关联 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
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
public class SpringBeanValidationDemo {

public static void main(String[] args) {
// 配置 XML 配置文件
// 启动 Spring 应用上下文
ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-validation-context.xml");

// Validator validator = applicationContext.getBean(Validator.class);
// System.out.println(validator instanceof LocalValidatorFactoryBean);

UserProcessor userProcessor = applicationContext.getBean(UserProcessor.class);
userProcessor.process(new User());

// 关闭应用上下文
applicationContext.close();
}

@Component
@Validated
static class UserProcessor {

public void process(@Valid User user) {
System.out.println(user);
}

}

static class User {

@NotNull
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "User{" +
" + name + '\'' +
'}';
}
}
}
1
2
3
4
5
6
7
8
<context:component-scan base-package="org.geekbang.thinking.in.spring.validation"/>

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>


<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor">
<property />
</bean>

面试题

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 基础设施的中心化接口
  • 通常不会直接使用,间接用于 BeanFactoryDataBinder
  • 提供标准 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)

课外资料

标准 JavaBeans 是如何操作属性的?

API说明
java.beans.IntrospectorJavaBeans 内省 API
java.beans.BeanInfoJavaBeans 元信息 API
java.beans.BeanDescriptor JavaBeans信息描述符
java.beans.PropertyDescriptorJavaBeans 属性描述符
java.beans.MethodDescriptorJavaBeans 方法描述符
java.beans.EventSetDescriptorJavaBeans 事件集合描述符

DataBinder 数据校验

  • DataBinderBeanWrapper
    • 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+ 通用类型转换实现
数据绑定YESYES
BeanWrapperYESYES
Bean 属性类型装换YESYES
外部化属性类型转换NOYES

基于 JavaBeans 接口的类型转换

  • 核心职责
    • 将 String 类型的内容转化为目标类型的对象
  • 扩展原理
    1. Spring 框架将文本内容传递到 PropertyEditor 实现的 setAsText(String) 方法
    2. PropertyEditor#setAsText(String) 方法实现将 String 类型转化为目标类型的对象
    3. 将目标类型的对象传入 PropertyEditor#setValue(Object) 方法
    4. PropertyEditor#setValue(Object) 方法实现需要临时存储传入对象
    5. Spring 框架将通过 PropertyEditor#getValue() 获取类型转换后的对象

Spring 內建 PropertyEditor 扩展

內建扩展(org.springframework.beans.propertyeditors 包下)

转换场景实现类
String -> Byte 数组org.springframework.beans.propertyeditors.ByteArrayPropertyEditor
String -> Charorg.springframework.beans.propertyeditors.CharacterEditor
String -> Char 数组org.springframework.beans.propertyeditors.CharArrayPropertyEditor
String -> Charsetorg.springframework.beans.propertyeditors.CharsetEditor
String -> Classorg.springframework.beans.propertyeditors.ClassEditor
String -> Currencyorg.springframework.beans.propertyeditors.CurrencyEditor

自定义 PropertyEditor 扩展

  1. 扩展模式
    • 扩展 java.beans.PropertyEditorSupport
  2. 实现 org.springframework.beans.PropertyEditorRegistrar
    • 实现 registerCustomEditors(org.springframework.beans.PropertyEditorRegistry) 方法
    • PropertyEditorRegistrar 实现注册为 Spring Bean
    • 声明 org.springframework.beans.factory.config.CustomEditorConfigurer,并将自定义 PropertyEditorRegistrar 加入属性 propertyEditorRegistrars
  3. 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
      • 声明名称为 conversionServiceConversionServiceFactoryBean
      • 将自定义 Converter 传入属性 converters
    • 通过 org.springframework.core.convert.ConversionService API

统一类型转换服务

  • org.springframework.core.convert.ConversionService
实现类型说明
GenericConversionService通用 ConversionService 模板实现,不内置转化器实现
DefaultConversionService基础 ConversionService 实现,内置常用转化器实现
FormattingConversionService通用 Formatter + GenericConversionService 实现,不内置转化器和 Formatter 实现
DefaultFormattingConversionServiceDefaultConversionService + 格式化 实现(如: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
2
3
4
5
6
7
8
整体流程:
// AbstractApplicationContext -> "conversionService" ConversionService Bean
// -> ConfigurableBeanFactory#setConversionService(ConversionService)
// -> AbstractAutowireCapableBeanFactory.instantiateBean
// -> AbstractBeanFactory#getConversionService ->
// BeanDefinition -> BeanWrapper -> 属性转换(数据来源:PropertyValues)->
// setPropertyValues(PropertyValues) -> TypeConverter#convertIfNecessnary
// TypeConverterDelegate#convertIfNecessnary -> PropertyEditor or ConversionService

面试题

Spring 类型转换实现有哪些?

  1. 基于 JavaBeans PropertyEditor 接口实现
  2. 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 5 类型接口

Java 5 类型接口 - java.lang.reflect.Type

派生类或接口说明
java.lang.ClassJava 类 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

MethodConstructor 二选一

MethodParameter 可以表示方法参数、构造器参数、返回类型

Spring 4.0 泛型优化实现 - ResolvableType

核心 API - org.springframework.core.ResolvableType

  • 起始版本:[4.0 ,)
  • 扮演角色:GenericTypeResolverGenericCollectionTypeResolver 替代者
  • 工厂方法: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 技术规范事件接口监听器接口
JavaBeansjava.beans.PropertyChangeEventjava.beans.PropertyChangeListener
Java AWTjava.awt.event.MouseEventjava.awt.event.MouseListener
Java Swingjavax.swing.event.MenuEventjavax.swing.event.MenuListener
Java Preferencejava.util.prefs.PreferenceChangeEventjava.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
      • 依赖注入
  • 方法二:通过 ApplicationEventMulticaster 发布 Spring 事件
    • 获取 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 事件

  1. 扩展 org.springframework.context.ApplicationEvent
  2. 实现 org.springframework.context.ApplicationListener
  3. org.springframework.context.ApplicationListener 注册到容器内

依赖注入 ApplicationEventPublisher

  • 通过 ApplicationEventPublisherAware 回调接口
  • 通过 @Autowired ApplicationEventPublisher

依赖查找 ApplicationEventMulticaster

  • 查找条件
    • Bean 名称:applicationEventMulticaster
    • Bean 类型:org.springframework.context.event.ApplicationEventMulticaster
1
2
3
AbstractApplicationContext#earlyApplicationEventsprepareRefresh() 中从 null 被赋值,在 registerListeners() 的最后,重新被赋值为 null,并进行了早期事件的发布,
因为可能存在一个 Bean 同时实现 BeanPostProcessorApplicationEventPublisherAware,并在 ApplicationEventPublisherAware#setApplicationEventPublisher 方法中发送事件
因为实现了 BeanPostProcessor,所以这个 BeanregisterBeanPostProcessors(beanFactory); 这个方法中初始化,而此时 initApplicationEventMulticaster(); 还没有执行,所以 AbstractApplicationContext#applicationEventMulticaster 为空,无法发布事件,所以先将事件保存在 AbstractApplicationContext#earlyApplicationEvents

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
@ControllerWeb 控制器模式注解2.5
@Configuration配置类模式注解3.0

装配注解

Spring 注解场景说明起始版本
@lmportResource替换 XML 元素 <import>2.5
@lmport导入 Configuration 类2.5
@ComponentScan扫描指定 package 下标注 Spring 模式注解的类3.1

依赖注入注解

Spring 注解场景说明起始版本
@AutowiredBean 依赖注入,支持多种依赖查找方式2.5
@Qualifier细粒度的 @Autowired 依赖查找2.5

Spring 注解编程模型

  • 编程模型
  • 元注解(Meta-Annotations)
  • Spring 模式注解(Stereotype Annotations)
  • Spring 组合注解(Composed Annotations)
  • Spring 注解属性别名和覆盖(Attribute Aliases and Overrides)

Wiki

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
    • 注解元信息 - org.springframework.core.type.AnnotationMetadata
      • ASM 实现 - org.springframework.core.type.classreading.AnnotationMetadataReadingVisitor
      • 反射实现 - org.springframework.core.type.StandardAnnotationMetadata
  • 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.ComponentScanvaluebasePackages
  • 隐形别名:通过在注解属性上 @AliasFor 元注解的属性
    • org.springframework.boot.autoconfigure.SpringBootApplicationexcludeexcludeName
  • 传递隐式别名:给定一个批注中的两个或更多属性,它们通过 @AliasFor 声明为元注解中的属性的显式替代,如果这些属性有效地替代了元注解中的同一属性,则它们是可传递的隐式别名。

Spring 注解属性覆盖(Attribute Overrides)

  • 隐式覆盖:注解中存在和元注解中名称相同的属性
  • 显式覆盖:不同名称属性,使用 @AliasFor 声明为元注解属性的别名
  • 传递显式覆盖:

Spring @Enable 模块驱动

  • @Enable 模块驱动

    • @Enable 模块驱动是以 @Enable 为前缀的注解驱动编程模型。所谓 “模块” 是指具备相同领域的功能组件集合,组合所形成一个独立的单元。比如 WebMVC 模块、AspectJ 代理模块、Caching (缓存)模块、JMX (Java 管理扩展)模块、Async (异步处理)模块等。
  • 举例说明

    • @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 注解
注解场景说明起始版本
@SpringBootConfigurationSpring Boot 配置类1.4.0
@SpringBootApplicationSpring Boot 应用引导注解1.2.0
@EnableAutoConfigurationSpring Boot 激活自动装配1.0.0
  • Spring Cloud 注解
注解场景说明起始版本
@SpringCloudApplicationSpring Cloud 应用引导注解1.0.0
@EnableDiscoveryClientSpring Cloud 激活服务发现客户端注解1.0.0
@EnableCircuitBreakerSpring 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 优势在于 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

    1
    2
    3
    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.JndiPropertySourceJDNI 配置属性源
org.springframework.core.env.PropertiesPropertySourceProperties 配置属性源
org.springframework.web.context.support.ServletConfigPropertySourceServlet 配置属性源
org.springframework.web.context.support.ServletContextPropertySourceServletContext 配置属性源
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 应用上下文底层 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 为空,添加一个

        1
        2
        3
        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 是如何集成的?


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!