第一章: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.BeanDefinitionBeanDefinition是 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.ObjectFactoryorg.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.InstantiationAwareBeanPostProcessororg.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 ,會注入一些單例對象,名稱為:
environmentsystemPropertiessystemEnvironment
單例對象由 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
@RequestScopeRequestScope
"session" Bean 作用域
配置
- XML -
<bean class= "..." scope = "session" /> - Java 注解 -
@RequestScope或@Scope(WebApplicationContext.SCOPE_REQUEST)
實現 API
@SessionScopeSessionScope
"application" Bean 作用域
配置
- XML -
<bean class= "..." scope = "application" /> - Java 注解 -
@ApplicationScope或@Scope(WebApplicationContext.SCOPE_APPLICATION)
實現 API
@ApplicationScopeServletContextScope
實現方式與 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 接口,執行順序從上到下
BeanNameAwareBeanClassLoaderAwareBeanFactoryAware
依賴於 ApplicationContext :
EnvironmentAwareEmbeddedValueResolverAwareResourceLoaderAwareApplicationEventPublisherAwareMessageSourceAwareApplicationContextAware
在初始化 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:通用型BeanDefinitionRootBeanDefinition:無 Parent 的BeanDefinition或者合並后BeanDefinitionAnnotatedBeanDefinition:注解標注的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 表示第 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" /> |
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 注解 | 場景說明 | 起始版本 |
|---|---|---|
| @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.PropertySourceorg.springframework.core.env.PropertySources
基於 YAML 資源裝載外部化配置
API 編程
org.springframework.beans.factory.config.YamlProcessororg.springframework.beans.factory.config.YamlMapFactoryBeanorg.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.WritableResourceorg.springframework.core.io.FileSystemResourceorg.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.ResourceLoaderorg.springframework.core.io.DefaultResourceLoaderorg.springframework.core.io.FileSystemResourceLoaderorg.springframework.core.io.ClassRelativeResourceLoaderorg.springframework.context.support.AbstractApplicationContext
Spring 通配路徑資源加載器
- 通配路徑 ResourceLoader
org.springframework.core.io.support.ResourcePatternResolverorg.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")));
}
}
