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.URLConnection
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(); } }
-
测试使用
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")));
}
}