20201108 小马哥讲Spring核心编程思想 - 笔记 1-11
第一章:Spring Framework总览(Overview)
| Spring Framework 版本 | Java 标准版 | Java 企业版 | 
|---|---|---|
| 1.x | 1.3+ | J2EE 1.3 + | 
| 2.x | 1.4.2+ | J2EE 1.3 + | 
| 3.x | 5+ | J2EE 1.4 和 Java EE 5 | 
| 4.x | 6+ | Java EE 6 和 7 | 
| 5.x | 8+ | 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
IoC 容器的职责:
- 通用职责
- 依赖处理
- 依赖查找
- 依赖注入
 
- 生命周期管理
- 容器
- 托管的资源(Java Beans 或其他资源)
 
- 配置
- 容器
- 外部化配置
- 托管的资源(Java Beans 或其他资源)
 
 
- 依赖处理
Spring 作为 IoC 容器的优势:
- 典型的 IoC 管理,依赖查找和依赖注入
- AOP 抽象
- 事务抽象
- 事件机制
- SPI 扩展
- 强大的第三方整合
- 易测试性
- 更好的面向对象
第三章:Spring IoC 容器概述
Spring IoC 依赖查找:
- 根据 Bean 名称查找
- 实时查找
- 延迟查找
 
- 根据 Bean 类型查找
- 单个 Bean 对象
- 集合 Bean 对象
 
- 根据 Bean 名称 + 类型查找
- 根据 Java 注解查找
- 单个 Bean 对象
- 集合 Bean 对象
 
Spring IoC 依赖注入:
- 根据 Bean 名称注入
- 根据 Bean 类型注入
- 单个 Bean 对象
- 集合 Bean 对象
 
- 注入容器內建 Bean 对象
- 注入非 Bean 对象
- 注入类型
- 实时注入
- 延迟注入
 
延迟查找和延迟注入,使用到接口 org.springframework.beans.factory.ObjectProvider 和 org.springframework.beans.factory.ObjectFactory ,ObjectProvider 继承 ObjectFactory
BeanFactory 和 ApplicationContext 谁才是 Spring IoC 容器?
- BeanFactory是 Spring 底层 IoC 容器
- ApplicationContext是具备应用特性的- BeanFactory超集
- BeanFactory是基本的 IoC 容器,- ApplicationContext实现- BeanFactory接口,并在内部使用- ConfigurableListableBeanFactory实现接口方法。
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 name="..." ... />
 
- Java 注解配置元信息
- @Bean
- @Component
- @Import
 
- Java API 配置元信息
- 命名方式:BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)
- 非命名方式:BeanDefinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition,Be
 anDefinitionRegistry)
- 配置类方式:AnnotatedBeanDefinitionReader#register(Class...)
 
- 命名方式:
 
- XML 配置元信息
- 外部单例对象注册
- Java API 配置元信息
- SingletonBeanRegistry#registerSingleton
 
 
- Java API 配置元信息
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)
 
- XML 配置:
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)
 
- XML 配置:
第五章: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 3.0 : 
- Spring 5.1 Bean 延迟查找
- getBeanProvider(Class)
- getBeanProvider(ResolvableType)
 
 
- Bean 实时查找
- 根据 Bean 名称 + 类型查找:getBean(String,Class)
集合类型依赖查找接口 - ListableBeanFactory
- 根据 Bean 类型查找
- 获取同类型 Bean 名称列表
- getBeanNamesForType(Class)
- Spring 4.2 getBeanNamesForType(ResolvableType)
 
- 获取同类型 Bean 实例列表
- getBeansOfType(Class)以及重载方法
 
 
- 获取同类型 Bean 名称列表
- 通过注解类型查找
- 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>)
 
 
- Spring 3.0 获取标注类型 Bean 名称列表
层次性依赖查找接口 - HierarchicalBeanFactory
- 双亲 BeanFactory:getParentBeanFactory()
- 层次性查找
- 根据 Bean 名称查找
- 基于 containsLocalBean方法实现
 
- 基于 
- 根据 Bean 类型查找实例列表
- 单一类型:BeanFactoryUtils#beanOfType
- 集合类型:BeanFactoryUtils#beansOfTypeIncludingAncestors
 
- 单一类型:
- 根据 Java 注解查找名称列表
- BeanFactoryUtils#beanNamesForTypeIncludingAncestors
 
 
- 根据 Bean 名称查找
Bean 延迟依赖查找接口
- org.springframework.beans.factory.ObjectFactory
- org.springframework.beans.factory.ObjectProvider- Spring 5 对 Java 8 特性扩展
- 函数式接口
- getIfAvailable(Supplier)
- ifAvailable(Consumer)
 
- Stream 扩展 - stream()
 
- 函数式接口
 
- Spring 5 对 Java 8 特性扩展
依赖查找安全性对比:
| 依赖查找类型 | 代表实现 | 是否安全 | 
|---|---|---|
| 单一类型查找 | BeanFactory#getBean | 否 | 
| ObjectFactory#getObject | 否 | |
| ObjectProvider#getIfAvailable | 是 | |
| 集合类型查找 | ListableBeanFactory#getBeansOfType | 是 | 
| ObjectProvider#stream | 是 | 
注意:层次性依赖查找的安全性取决于其扩展的单一或集合类型的 BeanFactory 接口
AbstractApplicationContext 内建可查找的依赖
| Bean 名称 | Bean 实例 | 使用场景 | 
|---|---|---|
| environment | Environment 对象 | 外部化配置以及 Profiles | 
| systemProperties | java.util.Properties 对象 | Java 系统属性 | 
| systemEnvironment | java.util.Map 对象 | 操作系统环境变量 | 
| messageSource | MessageSource 对象 | 国际化文案 | 
| lifecycleProcessor | LifecycleProcessor 对象 | Lifecycle Bean 处理器 | 
| applicationEventMulticaster | ApplicationEventMulticaster 对 象 | Spring 事件广播器 | 
注解驱动 Spring 应用上下文内建可查找的依赖
| Bean 名称 | Bean 实例 | 使用场景 | 
|---|---|---|
| org.springframework.context.annotation.internalConfigurationAnnotationProcessor | ConfigurationClassPostProcesso | 处理 Spring 配置类 | 
| org.springframework.context.annotation.internalAutowiredAnnotationProcessor | AutowiredAnnotationBeanPostProcessor 对象 | 处理 @Autowired 以及 @Value 注解 | 
| org.springframework.context.annotation.internalCommonAnnotationProcessor | CommonAnnotationBeanPostProcessor 对象 | (条件激活)处理 JSR-250 注解,如 @PostConstruct 等 | 
| org.springframework.context.event.internalEventListenerProcessor | EventListenerMethodProcessor 对象 | 处理标注 @EventListener 的 Spring 事件监听方法 | 
| org.springframework.context.event.internalEventListenerFactory | DefaultEventListenerFactory 对象 | @EventListener 事件监听方法适配为 ApplicationListener | 
| org.springframework.context.annotation.internalPersistenceAnnotationProcessor | PersistenceAnnotationBeanPostProcessor 对象 | (条件激活)处理 JPA 注解场景 | 
依赖查找中的经典异常,BeansException 子类型
| 异常类型 | 触发条件(举例) | 场景举例 | 
|---|---|---|
| NoSuchBeanDefinitionException | 当查找 Bean 不存在于 IoC 容器时 BeanFactory#getBean | ObjectFactory#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 name="user" ref="userBean"/> | 
| 构造器 | <constructor-arg name="user" ref="userBean" /> | 
| 字段 | @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 依赖 <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
 
 
- 使用注解 @Qualifier 限定
- 
延迟依赖注入 
- 
使用 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依赖来源
| 来源 | 配置元数据 | 注册API | Spring Bean 对象 | 生命周期管理 | 配置元信息 | 使用场景 | 
|---|---|---|---|---|---|---|
| Spring BeanDefinition | <bean id="user" class="org.geekbang...User">@Bean public User user(){...}BeanDefinitionBuilder | BeanDefinitionRegistry#registerBeanDefinition | 是 | 是 | 有 | 依赖查找、依赖注入 | 
| 单例对象 | API 实现 | SingletonBeanRegistry#registerSingleton | 是 | 否 | 无 | 依赖查找、依赖注入 | 
| 非 Spring 容器管理对象 | Resolvable Dependency | ConfigurableListableBeanFactory#registerResolvableDependency | 否 | 否 | 无 | 依赖注入 | 
| 外部化配置 | @Value | Object 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
// 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 :
@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
- 
配置 <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <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
 
- XML 解析器 - 
- 面向注解 BeanDefinition 解析 - AnnotatedBeanDefinitionReader
Spring Bean 注册阶段
BeanDefinition 注册接口
BeanDefinitionRegistry
Spring BeanDefinition 合并阶段
BeanDefinition 合并
父子 BeanDefinition 合并
- 当前 BeanFactory 查找
- 层次性 BeanFactory 查找
<bean id="user" class="org.geekbang.thinking.in.spring.ioc.overview.domain.User">
    <property name="id" value="1"/>
    ...
</bean>
<bean id="superUser" class="org.geekbang.thinking.in.spring.ioc.overview.domain.SuperUser" parent="user"
      primary="true">
    <property name="address" value="杭州"/>
</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 安全控制 相关
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 之前,对它们进行处理。
在依赖注入( byName 或 byType )之后,在将配置的属性赋值给 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  ,这个方法做了两件事情:
- 将已注册的 BeanDefinition初始化成 Spring Bean
- 调用所有 SmartInitializingSingleton#afterSingletonsInstantiated
Spring Bean 销毁前阶段
- 方法回调
- DestructionAwareBeanPostProcessor#postProcessBeforeDestruction
 
执行 ConfigurableBeanFactory#destroyBean 时,触发 Bean 前销毁阶段
对 @PreDestroy 的处理需要依赖于注解驱动,CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction
Spring Bean 销毁阶段
Bean 销毁(Destroy)
- @PreDestroy标注方法
- 实现 DisposableBean接口的destroy()方法
- 自定义销毁方法
对 @PreDestroy 的处理需要依赖于注解驱动,CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction
CommonAnnotationBeanPostProcessor 是 DestructionAwareBeanPostProcessor 的实现类之一
如果其他 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 元素属性 | 默认值 | 使用场景 | 
|---|---|---|
| profile | null(留空) | Spring Profiles 配置值 | 
| default-lazy-init | default | 当 outter beans “default-lazy-init” 属性存在时,继承该值,否则为“false” | 
| default-merge | default | 当 outter beans “default-merge” 属性存在时,继承该值,否则为“false” | 
| default-autowire | default | 当 outter beans “default-autowire” 属性存在时,继承该值,否则为“no” | 
| default-autowire-candidates | null(留空) | 默认 Spring Beans 名称 pattern | 
| default-init-method | null(留空) | 默认 Spring Beans 自定义初始化方法 | 
| default-destroy-method | null(留空) | 默认 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
- 判断 beans 标签的 profile 属性,如果不在激活状态,直接返回,不再向下解析
- 如果是 beans 标签下的特殊元素,进行特殊处理,方法为 DefaultBeanDefinitionDocumentReader#parseDefaultElement- beans
- bean
- alias
- import
 
- 否则,BeanDefinitionParserDelegate#parseCustomElement
基于 Properties 资源装载 Spring Bean 配置元信息
| Properties 属性名 | 使用场景 | 
|---|---|
| (class) | Bean 类全称限定名 | 
| (abstract) | 是否为抽象的 BeanDefinition | 
| (parent) | 指定 parent BeanDefinition 名称 | 
| (lazy-init) | 是否为延迟初始化 | 
| (ref) | 引用其他 Bean 的名称 | 
| (scope) | 设置 Bean 的 scope 属性 | 
| $ | n 表示第 n+1 个构造器参数 | 
底层实现 - PropertiesBeanDefinitionReader
如果出现重复的 Bean 定义,后者不会被注册进 BeanFactory 中
基于 Java 注解装载 Spring Bean 配置元信息
Spring 模式注解
| Spring 注解 | 场景说明 | 起始版本 | 
|---|---|---|
| @Repository | 数据仓储模式注解 | 2.0 | 
| @Component | 通用组件模式注解 | 2.5 | 
| @Service | 服务模式注解 | 2.5 | 
| @Controller | Web 控制器模式注解 | 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" />` | 
| @Primary | 替换 XML 元素 `<bean primary="true | false" />` | 
| @Role | 替换 XML 元素 <bean role="..." /> | 3.1 | 
| @Lookup | 替代 XML 属性 <bean lookup-method="..."> | 4.1 | 
Spring Bean 依赖注入注解
| Spring 注解 | 场景说明 | 起始版本 | 
|---|---|---|
| @Autowired | Bean 依赖注入,支持多种依赖查找方式 | 2.5 | 
| @Qualifier | 细粒度的 @Autowired 依赖查找 | 2.5 | 
AutowiredAnnotationBeanPostProcessor 与 @Autowired 相关
| Java 注解 | 场景说明 | 起始版本 | 
|---|---|---|
| @Resource | 类似于 @Autowired | 2.5 | 
| @Inject | 类似于 @Autowired | 2.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="..." />或InitializingBean | 2.5 | 
| @PreDestroy | 替换 XML 元素 <bean destroy-method="..." />或DisposableBean | 2.5 | 
CommonAnnotationBeanPostProcessor
Spring Bean 配置元信息底层实现
Spring BeanDefinition 解析与注册
| 实现场景 | 实现类 | 起始版本 | 
|---|---|---|
| XML 资源 | XmlBeanDefinitionReader | 1.0 | 
| Properties 资源 | PropertiesBeanDefinitionReader | 1.0 | 
| Java 注解 | AnnotatedBeanDefinitionReader | 3.0 | 
- 
XmlBeanDefinitionReader和PropertiesBeanDefinitionReader都继承自AbstractBeanDefinitionReader,实现了BeanDefinitionReader接口,与资源(Resource)相关联
- 
AnnotatedBeanDefinitionReader是独立的类,与Resource无关
- 
Spring XML 资源 BeanDefinition 解析与注册 - 核心 API - XmlBeanDefinitionReader- 资源 - Resource
- 底层 - BeanDefinitionDocumentReader- XML 解析 - Java DOM Level 3 API
- BeanDefinition 解析 - BeanDefinitionParserDelegate
- BeanDefinition 注册 - BeanDefinitionRegistry
 
 
 
- 核心 API - 
- 
Spring Properties 资源 BeanDefinition 解析与注册 - 核心 API - PropertiesBeanDefinitionReader- 资源
- 字节流 - Resource
- 字符流 - EncodedResouce
 
- 字节流 - 
- 底层
- 存储 - java.util.Properties
- BeanDefinition 解析 - API 内部实现
- BeanDefinition 注册 - BeanDefinitionRegistry
 
- 存储 - 
 
- 资源
 
- 核心 API - 
- 
Spring Java 注册 BeanDefinition 解析与注册 - 核心 API - AnnotatedBeanDefinitionReader- 资源
- 类对象 - java.lang.Class
 
- 类对象 - 
- 底层
- 条件评估 - ConditionEvaluator
- Bean 范围解析 - ScopeMetadataResolver
- BeanDefinition 解析 - 内部 API 实现
- BeanDefinition 处理 - AnnotationConfigUtils.processCommonDefinitionAnnotations
- BeanDefinition 注册 - BeanDefinitionRegistry
 
- 条件评估 - 
 
- 资源
 
- 核心 API - 
Properties 资源加载默认编码是 ISO-8859-1
AnnotatedBeanDefinitionReader 使用 ConditionEvaluator 判断 Bean 的元信息,如果其中存在 @Conditional 条件,判断此条件通过才会将 Bean 加入容器
基于 XML 资源装载 Spring IoC 容器配置元信息
Spring IoC 容器相关 XML 配置
| 命名空间 | 所属模块 | Schema 资源 URL | 
|---|---|---|
| beans | spring-beans | https://www.springframework.org/schema/beans/spring-beans.xsd | 
| context | spring-context | https://www.springframework.org/schema/context/spring-context.xsd | 
| aop | spring-aop | https://www.springframework.org/schema/aop/spring-aop.xsd | 
| tx | spring-tx | https://www.springframework.org/schema/tx/spring-tx.xsd | 
| util | spring-beans | https://www.springframework.org/schema/util/spring-util.xsd | 
| tool | spring-beans | https://www.springframework.org/schema/tool/spring-tool.xsd | 
基于 Java 注解装载 Spring IoC 容器配置元信息
Spring IoC 容器装配注解
| Spring 注解 | 场景说明 | 起始版本 | 
|---|---|---|
| @ImportResource | 替换 XML 元素 <import> | 3.0 | 
| @Import | 导入 Configuration Class | 3.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
@PropertySource(
        name = "yamlPropertySource",
        value = "classpath:/META-INF/user.yaml",
        factory = YamlPropertySourceFactory.class)
面试题
Spring 內建 XML Schema 常见有哪些?
| 命名空间 | 所属模块 | Schema 资源 URL | 
|---|---|---|
| beans | spring-beans | https://www.springframework.org/schema/beans/spring-beans.xsd | 
| context | spring-context | https://www.springframework.org/schema/context/spring-context.xsd | 
| aop | spring-aop | https://www.springframework.org/schema/aop/spring-aop.xsd | 
| tx | spring-tx | https://www.springframework.org/schema/tx/spring-tx.xsd | 
| util | spring-beans | https://www.springframework.org/schema/util/spring-util.xsd | 
| tool | spring-beans | https://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 內建协议实现
| 协议 | 实现类 | 
|---|---|
| file | sun.net.www.protocol.file.Handler | 
| ftp | sun.net.www.protocol.ftp.Handler | 
| http | sun.net.www.protocol.http.Handler | 
| https | sun.net.www.protocol.https.Handler | 
| jar | sun.net.www.protocol.jar.Handler | 
| mailto | sun.net.www.protocol.mailto.Handler | 
| netdoc | sun.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 | 
| URL | URL 支持的协议 | org.springframework.core.io.UrlResource | 
| ServletContext | 无 | org.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
 
- Ant 模式匹配实现 - 
 
Spring 通配路径资源扩展
- 实现 org.springframework.util.PathMatcher
- 重置 PathMatcher
- PathMatchingResourcePatternResolver#setPathMatcher
 
依赖注入 Spring Resource
基于 @Value 实现
@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
 
- 普通 Bean Definition XML 配置资源 - 
- Properties 资源
- 普通 Properties 格式资源 - *.properties
- Spring Handler 实现类映射文件 - META-INF/spring.handlers
- Spring Schema 资源映射文件 - META-INF/spring.schemas
 
- 普通 Properties 格式资源 - 
- YAML 资源
- 普通 YAML 配置资源 - *.yaml或*.yml
 
- 普通 YAML 配置资源 - 
Java 标准资源管理扩展的步骤?
- 简易实现
- 实现 URLStreamHandler并放置在sun.net.www.protocol.${protocol}.Handler包下
 
- 实现 
- 自定义实现
- 实现 URLStreamHandler
- 添加 -Djava.protocol.handler.pkgs启动参数,指向URLStreamHandler实现类的包下
 
- 实现 
- 高级实现
- 实现 URLStreamHandlerFactory并传递到 URL 之中
 
- 实现 
简易实现实例
- 
扩展 x 协议,新建类 sun.net.www.protocol.x.Handler,类名格式必须符合规范public class Handler extends URLStreamHandler { @Override protected URLConnection openConnection(URL u) throws IOException { return new XURLConnection(u); } }
- 
新建类 XURLConnection,实现java.net.URLConnectionpublic 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(); } }
- 
测试使用 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"))); } }
自定义实现
- 
新建类 Handler,继承sun.net.www.protocol.x.Handle,类名必须为Handler,包名无限制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"))); } }
- 
运行时增加 VM 参数, -Djava.protocol.handler.pkgs=org.geekbang.thinking.in.spring.resource
高级实现
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")));
    }
}
 
                    
                 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号