
在日常使用Spring框架的業務開發中,利用框架提供的擴展點完成某些功能的設計是很常見的,了解這些擴展點的原理也對理解框架非常有幫助。這里做一個簡單的整理、總結。
1. BeanPostProcessor
BeanPostProcessor 接口定義了基本的Bean初始化回調方法,可以實現對應的回調方法來在Spring容器完成Bean的實例化、初始化前后實現某些自定義邏輯。
一段來自注釋中的翻譯:
ApplicationContext可以在其 beanDefinitions 中自動檢測框架中預置和我們自行擴展的BeanPostProcessor,並將這些后處理器應用於隨后創建的任何 bean。
在ApplicationContext中自動檢測的BeanPostProcessor bean 將根據PriorityOrdered和Ordered語義進行排序。 相比之下,以編程方式注冊到BeanFactory BeanPostProcessor bean 將按注冊順序應用; 對於以編程方式注冊的后處理器,通過實現PriorityOrdered或Ordered接口表達的任何排序語義都將被忽略。
所謂的編程方式就是說通過手動調用BeanFactory的addBeanPostProcessor方法進行添加BeanPostProcessor。
下面是BeanPostProcessor的接口定義。
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
1.1 BeanPostProcessor 基本示例:
下面這個PersonBeanPostProcessor 對於每一個完成實例化的Bean判斷其 BeanName ,如果與 person相等就打印一行日志
@Component
public class Person {
private Integer id;
private String name;
//省略 Getter、Setter
}
@Component
public class PersonBeanPostProcessor implements BeanPostProcessor {
private final Logger logger = LoggerFactory.getLogger(PersonBeanPostProcessor.class);
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("person".equals(beanName)) {
logger.info("person完成實例化");
}
return null;
}
}
//啟動應用:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.8.RELEASE)
2021-06-24 07:40:41.126 INFO 27308 --- [ main] com.landscape.spring.Application : No active profile set, falling back to default profiles: default
2021-06-24 07:40:41.508 INFO 27308 --- [ main] c.l.spring.bean.PersonBeanPostProcessor : person完成實例化
2021-06-24 07:40:41.592 INFO 27308 --- [ main] com.landscape.spring.Application : Started Application in 0.939 seconds (JVM running for 2.145)
可以看到,第二行日志中自定義的 BeanPostProcessor 生效並按照預期的打印出了日志。
1.2 BeanPostProcessor 實際使用
從一個簡單的示例可能無法感受到它能在實際的開發中做什么,現在找一點實際的例子來看BeanPostProcessor的用處。一個非常簡單且有效的例子是Spring Validation包下的 BeanValidationPostProcessor,它負責對Spring中的實例化的Bean做JSR-303的注解校驗,如果違反了校驗規則就拋出異常。
public class BeanValidationPostProcessor implements BeanPostProcessor, InitializingBean {
@Nullable
private Validator validator;
//省略主題無關的代碼
//通過一個變量 afterInitialization 來判斷是在初始化前還是在初始化后做判斷
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!this.afterInitialization) {
doValidate(bean);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (this.afterInitialization) {
doValidate(bean);
}
return bean;
}
/**
* Perform validation of the given bean.
* @param bean the bean instance to validate
* @see javax.validation.Validator#validate
*/
protected void doValidate(Object bean) {
//省略主題無關的代碼
}
}
不過這個處理器並不是默認注入到容器的,所以需要我們手動配置:
@Configuration
public class BeanValidationConfiguration {
@Bean
public BeanValidationPostProcessor beanValidationPostProcessor() {
return new BeanValidationPostProcessor();
}
}
現在寫一個帶有JSR-303注解的實體類:
@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class Person {
@Min(1)
@NotNull
private Integer id;
@NotBlank
private String name;
@NotBlank
private String address;
private LocalDateTime birthday;
public Person() {
}
}
//由於這個Bean的作用域被設置為 prototype ,所以必須要手動獲取才會觸發實例化:
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringBootContainer.class, args);
System.out.println(context.getBean(Person.class));
}
//運行后拋出異常:
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:602)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:342)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:227)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1175)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:420)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:349)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1127)
at com.landscape.demo.SpringBootContainer.main(SpringBootContainer.java:19)
Caused by: org.springframework.beans.factory.BeanInitializationException: Bean state is invalid: Bean state is invalid: address - 不能為空; name - 不能為空; id - 不能為null
at org.springframework.validation.beanvalidation.BeanValidationPostProcessor.doValidate(BeanValidationPostProcessor.java:127)
at
如果稍微改變一下代碼,給實體類屬性加上默認值即可通過校驗。同理,在實際的開發中,也可以使用BeanPostProcessor類似的進行Bean校驗、設值、掃包等操作。
1.3 BeanPostProcessor 的調用時機
1.3.1 BeanPostProcessor
現在來看一些原理上的細節。首先,BeanPostProcessor 的實現方法是在什么時候進行回調的?下圖是整體Spring Bean的實例化過程,而紅框標注的部分就是 BeanPostProcessor 的調用

圖片來源:Hands-On High Performance with Spring 5
結合着Spring源碼來看:
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
//這里是Spring框架運行過程中創建Bean的方法
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
//省略前面創建Bean的過程
// Initialize the bean instance.
Object exposedObject = bean;
try {
//這里是填充Bean的屬性
populateBean(beanName, mbd, instanceWrapper);
//執行Bean的初始化過程,BeanPostProcessor在這里被調用
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
//省略主題無關的代碼
return exposedObject;
}
//下面是initializeBean方法內部的邏輯
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//這里執行了BeanPostProcessor的 postProcessBeforeInitialization方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//這里執行了BeanPostProcessor的 postProcessAfterInitialization方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
另外 BeanPostProcessor 還有一些比較重要的子接口,Spring官方並不推薦我們使用這些子接口,因為大多屬於內置功能,不過了解一下也對理解框架原理很有幫助。來看一下各自的作用和源碼中的調用位置:

1.3.2 InstantiationAwareBeanPostProcessor
BeanPostProcessor子接口,用於添加實例化前回調,以及實例化后但在設置顯式屬性或自動裝配之前的回調。從名字上就能看出來是與Bean的實例化相關的處理器。之所以這里重點介紹這個接口是因為AOP不少相關的類都是這個通過這個接口來返回代理對象的。
通常用於抑制特定目標 bean 的默認實例化,例如創建具有特殊 TargetSource 的代理(池化目標、延遲初始化目標等),或實現額外的注入策略,例如字段注入。Spring文檔中並沒有提到這個接口,因為該接口是一個特殊用途的接口,主要供框架內部使用。
邏輯上該接口的postProcessBeforeInstantiation方法調用處於下圖位置(真正實例化Bean之前)(自己整理的思維導圖,截了一小部分,可能不是很全面= =)

從代碼中看則位於:
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean()
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
//省略主題無關代碼
//resolveBeanClass
//prepareMethodOverrides
try {
// InstantiationAwareBeanPostProcessor 接口的調用在這里,下面這行注釋也解釋的很清楚了
// 給BeanPostProcessors一個返回代理而不是目標bean實例的機會。
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
//如果沒有相關的InstantiationAwareBeanPostProcessor返回作為替代的Bean則立即進入實際的創建Bean過程
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
//省略異常處理
}
//進入到resolveBeforeInstantiation方法體中:
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
//可以看到如果Bean在這一步如果被代理對象替代則立即進入到 AfterInitialization 的后處理中
//因為不會繼續標准化的實例化流程了
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
而 postProcessAfterInstantiation 方法的調用則處於屬性填充之前,這是在Spring的自動裝配開始之前,在給定的bean實例上執行自定義字段注入的理想回調。(這個方法的返回值是 boolean類型,用於告訴Spring是否應該繼續后續的屬性填充過程)
//org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
邏輯視圖處於屬性填充方法的開始部分,如果返回值為false 則不會進行后面的屬性注入

代碼視圖如下:
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 給任何InstantiationAwareBeanPostProcessors 一個機會在屬性設置之前修改bean的狀態。
// 例如,這可以用於支持字段注入的樣式。
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//在這里進行 postProcessAfterInstantiation 方法的調用
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
//這里省略了一段屬性填充的過程
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
//下面這一部分分別調用了 postProcessProperties 和 postProcessPropertyValues 方法
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
1.3.3 其他子接口
-
DestructionAwareBeanPostProcessor 用於添加銷毀前回調的BeanPostProcessor子接口。典型的用法是在特定的 bean 類型上調用自定義銷毀回調,匹配相應的初始化回調。實現方法將在Bean的destroy方法之前被調用。
-
MergedBeanDefinitionPostProcessor 運行時合並bean 定義的后處理器回調接口。 BeanPostProcessor實現可以實現這個子接口,以便對 Spring BeanFactory用來創建 bean 實例的合並 bean 定義(原始 bean 定義的處理副本)進行后處理。
1.4 BeanPostProcessor本身的實例化時機
同樣是被標記 @Component 注解或者以其他方式被聲明為一個Bean,Spring如何保證 BeanPostProcessor 的實現能處理到每一個Bean?
首先,BeanPostProcessor 本身是在容器刷新時被初始化:

而在代碼中實際調用的是 PostProcessorRegistrationDelegate 的 registerBeanPostProcessors 的方法:
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
//篇幅問題,省略下面的方法
}
這個方法內看着步驟挺多的,事實上只是對BeanPostProcessor進行有序注冊,步驟為:
- 獲取所有BeanPostProcessor的Name
- 將內建的BeanPostProcessor和應用程序的BeanPostProcessor進行計數+1(計數+1是因為緊接着添加了一個BeanPostProcessorChecker,這個類本身也是一個BeanPostProcessor)
- 注冊所有實現了PriorityOrdered 的BeanPostProcessor
- 注冊所有實現了Ordered 的BeanPostProcessor
- 注冊所有其他的BeanPostProcessor
- 重新注冊所有內部的BeanPostProcessor(這里的“內建”指的是實現了MergedBeanDefinitionPostProcessor的BeanPostProcessor,將他們重新注冊到列表的末尾)
- 重新注冊一個ApplicationListenerDetector到列表末尾(這里的重新注冊內建BeanPostProcessor和ListenerDetector都是為了內建的組件能夠獲取到被代理取代后的對象)
對於使用Spring進行業務開發的我們來說,上述步驟里我們需要關心的只有BeanPostProcessor 的接口排序而已,也就是:
- 優先注冊所有實現了PriorityOrdered 的BeanPostProcessor
- 其次是實現了Ordered 的BeanPostProcessor
- 最后是沒有實現任何接口的BeanPostProcessor
其他的步驟都屬於Spring框架內建代碼使用的功能,除非需要對Spring框架做深度擴展,否則無需關心。
1.5 BeanPostProcessor並不能處理所有Bean
這個很好理解,首先BeanPostProcessor本身就是被聲明的Bean,那么就一定有先后順序,優先實例化的BeanPostProcessor可以處理后面實例化的BeanPostProcessor,這沒什么問題。
一個很好的例子是Spring文檔中關於AOP的說明:
因為 AOP 自動代理被實現為
BeanPostProcessor本身,不是BeanPostProcessor實例或它們直接引用的bean都符合自動代理的條件,反之則不包含切面。
也就是說我們在實際的開發中需要避免在BeanPostProcessor內嵌入業務或者讓BeanPostProcessor依賴業務組件。
來一個例子演示一下。第一步,找到實現AOP功能的BeanPostProcessor,在容器完成BeanPostProcessor的創建后觀察它的位置:

這個類的繼承關系中存在Ordered接口,也就是說我們也實現一個Ordered,並且優先級比它高,或者直接實現 PriorityOrdered 就好了。
准備以下代碼:
/**
* 這個注解只是標注一下要切入的類,接口或注解都可以
* @author landscape
* @date 2021-06-26
*/
public @interface BusinessAnnotation {
}
/**
* @author landscape
* @date 2021-06-26
*/
@Aspect
@Component
public class BusinessAspect {
@Around("@within(com.landscape.demo.component.BusinessAnnotation)")
public Object monitor(ProceedingJoinPoint joinPoint) {
System.out.println("\n————————————————————————————————————————————————————");
System.out.println(joinPoint.getTarget().getClass().getSimpleName() + ": 打工人開始工作");
try {
Object proceed = joinPoint.proceed();
System.out.println(joinPoint.getTarget().getClass().getSimpleName() + ": 打工人結束工作");
System.out.println("————————————————————————————————————————————————————");
return proceed;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
}
//准備兩個打工人:
@Component
@BusinessAnnotation
public class Worker1 {
public void work() {
System.out.println("Worker1 working...");
}
}
@Component
@BusinessAnnotation
public class Worker2 {
public void work() {
System.out.println("Worker2 working...");
}
}
//准備兩個資本家:
@Component
public class Manager1 implements BeanPostProcessor, Ordered {
@Autowired
private Worker1 worker1;
@Override
public int getOrder() {
//只要排在 AspectJAwareAdvisorAutoProxyCreator 之前就好了,設多少無所謂
return Ordered.LOWEST_PRECEDENCE - 1;
}
}
@Component
public class Manager2 implements BeanPostProcessor {
@Autowired
private Worker2 worker2;
}
//代碼部分就完成啦!:-D
畫圖解釋一下上面的代碼:

上面的代碼共有三種角色:
- Aspect,監視者切面
- Manager,實現了BeanPostProcessor,內部依賴Worker
- Worker,被切面增強
但是應該很快就能發現,圖中Manager1的優先級比 AOP實現類的優先級更高,而Manager1的初始化將導致 Worker1的實例化(原本Worker不應該在這個階段實例化),所以Worker1根本就不可能被切面監控。相對后面的Manager2和Worker2,他們實例化的時候已經存在AOP處理類了,所以可以被AOP切面監控。
運行容器代碼:
@SpringBootApplication
public class SpringBootContainer {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringBootContainer.class, args);
context.getBean(Worker1.class).work();
context.getBean(Worker2.class).work();
}
}
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.10.RELEASE)
2021-06-26 15:30:29.750 INFO 13764 --- [ main] com.landscape.demo.SpringBootContainer : No active profile set, falling back to default profiles: default
2021-06-26 15:30:30.164 INFO 13764 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'worker1' of type [com.landscape.demo.component.Worker1] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-06-26 15:30:30.225 INFO 13764 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'worker2' of type [com.landscape.demo.component.Worker2] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-06-26 15:30:30.647 INFO 13764 --- [ main] com.landscape.demo.SpringBootContainer : Started SpringBootContainer in 1.14 seconds (JVM running for 2.145)
Worker1 working...
————————————————————————————————————————————————————
Worker2: 打工人開始工作
Worker2 working...
Worker2: 打工人結束工作
————————————————————————————————————————————————————
Process finished with exit code 0
Bean 'worker1' of type [com.landscape.demo.component.Worker1] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
可以看到Worker1並沒有被切面切入,而Worker2的執行方法則成功的被切面增強。日志中的這兩行也很好的說明了這種情況。
2. BeanFactoryPostProcessor
上一章的BeanPostProcessor是針對容器運行過程中實例化的Bean進行處理操作的擴展組件,而本章的BeanFactoryPostProcessor顧名思義,是對BeanFactory進行處理操作的組件。
BeanFactoryPostProcessor操作bean配置元數據。也就是說,SpringIoC容器允許BeanFactoryPostProcessor讀取配置元數據並可能對其進行更改以前容器實例化除BeanFactoryPostProcessor實例。
BeanFactoryPostProcessor實例的作用域為每個容器。這只有在使用容器層次結構時才相關。如果您在一個容器中定義了BeanFactoryPostProcessor,那么它只應用於該容器中的bean定義。一個容器中的Bean定義不會被另一個容器中的BeanFactoryPostProcessor實例進行后處理,即使兩個容器都屬於相同的層次結構。
在Spring框架中BeanFactoryPostProcessor的子接口只有一個(這里不包含其他擴展框架,只針對Spring Framework 源碼):

這里以 ConfigurationClassPostProcessor為例子來幫助理解BeanFactoryPostProcessor接口。從它的實現關系上大致上就可以推測出它的特性、實例化時機、調用時機等信息:
- 實現了 BeanFactoryPostProcessor,所以它可以對BeanFactory進行元數據配置
- 實現了 BeanDefinitionRegistryPostProcessor,用來對BeanDefinitionRegistry 做配置。
- 實現了 PriorityOrdered,在處理順序上較為優先。

按照執行順序來看,先看 ConfigurationClassPostProcessor 這個類對於 BeanDefinitionRegistryPostProcessor 接口的實現:
//org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
/**
* 從注冊中心中的配置類派生進一步的bean定義。
* Derive further bean definitions from the configuration classes in the registry.
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
//對於 BeanDefinitionRegistryPostProcessor 接口的實現其實重點是下面調用的方法
processConfigBeanDefinitions(registry);
}
//org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions
/**
* Build and validate a configuration model based on the registry of
* {@link Configuration} classes.
*/
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//省略一段尋找候選的配置類、校驗、排序的過程
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
//這里的parse步驟做的事情非常多,處理了一個配置類中可能出現的配置元數據,例如@Import、@ComponentScan、內部配置類等很多事情
//但主題是BeanFactoryPostProcessor,這里不做過多解釋
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//這一步也非常重要,以眾多配置類為起點,加載路徑中所有的BeanDefinition。所以如果直接走過這一步會發現
//BeanFactory中的 BeanDefinitionMap 中多了很多Bean,是 SpringBoot 非常重要的加載步驟
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// 將ImportRegistry注冊為bean,以支持ImportAware @Configuration類
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
以上核心邏輯已經添加到代碼注釋中,省略了很多細節,從對BeanDefinitionRegistryPostProcessor實現的角度來看,只需要感受到它對BeanDefinitionRegistry的改動即可,也就是我們通過@Component、@Bean等方式定義的Bean都已經被讀入到容器中。
下面再來看ConfigurationClassPostProcessor 對於BeanFactoryPostProcessor 的實現部分:
//org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanFactory
/**
* 用cglib增強的子類替換Configuration類,以便在運行時為bean請求提供服務。
* Prepare the Configuration classes for servicing bean requests at runtime
* by replacing them with CGLIB-enhanced subclasses.
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
//這個實現里最重要的部分在下面這行方法調用,也就是增強配置類
enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
增強的邏輯這里就不貼代碼了(數量很多),簡單的概括就是將@Bean注解標注的方法進行一次代理,只有真正需要構造Bean的時候才實際的調用方法,而后面的調用都將通過BeanName從BeanFactory中獲取。
由於主題是 BeanFactoryPostProcessor 而不是增強的邏輯所以不做過多解析,后面可能專門加一篇文章來解析這方面的邏輯,大致的內容可參考ConfigurationClassEnhancer 及幾個內部類的注釋。
從對 BeanFactoryPostProcessor 的實現的角度來看,只需要注意到相關的配置類成功的被修改了元數據,實例換成了被 CGLIB 增強的子類即可。
3. FactoryBean
摘抄一下來自Spring文檔的翻譯:
FactoryBean接口是一個可插入到Spring IoC容器的實例化邏輯的點。如果您有復雜的初始化代碼,可以用Java更好地表達,而不是(可能)冗長的XML,那么您可以創建自己的FactoryBean,在該類中編寫復雜的初始化,然后將自定義的FactoryBean插入到容器中。
- T getObject(): 返回該工廠創建的對象的一個實例。該實例可能被共享,這取決於該工廠返回的是單例還是原型。
- boolean isSingleton(): 如果FactoryBean返回單例,則返回true,否則返回false。該方法的默認實現返回true。
- Class <?> getObjectType() : 返回getObject()方法返回的對象類型,如果事先不知道該類型,則返回null。
另外,如果想要獲取FactoryBean本身,則需要在BeanName前面加上“&”,來自文檔的翻譯:
當您需要向容器請求一個實際的FactoryBean實例本身,而不是它生成的bean時,在調用ApplicationContext的getBean()方法時,在bean的id前面加上&符號。因此,對於一個id為myBean的給定FactoryBean,在容器上調用getBean("myBean")將返回FactoryBean的產品,而調用getBean("&myBean")將返回FactoryBean實例本身。
在Spring的擴展點中,FactoryBean是一個相對簡單的概念,下面是一個簡單的小Demo,同時跟進源碼加深理解:
public class Person {
@Min(1)
@NotNull
private Integer id = 1;
private String name ;
private String address ;
private LocalDateTime birthday;
//省略Getter\Setter等方法
}
@Component
public class PersonFactory implements FactoryBean<Person> {
@Override
public boolean isSingleton() {
return true;
}
@Override
public Person getObject() throws Exception {
Person person = new Person();
person.setId(1)
.setName("abc")
.setAddress("南京")
.setBirthday(LocalDateTime.now())
;
return person;
}
@Override
public Class<?> getObjectType() {
return Person.class;
}
}
運行啟動代碼:
@SpringBootApplication
public class SpringBootContainer {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringBootContainer.class, args);
context.getBean(Person.class);
}
}
Debug斷點打到Spring開始初始化Bean的時候,流程看代碼注釋:
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//1. 因為我們定義的是FactoryBean,所以會進入到這個分支
if (isFactoryBean(beanName)) {
//2. 這里的getBean實例化的是工廠本身,也就是 PersonFactory,而不是目標對象Person
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
//3. 這里如果實現的是 SmartFactoryBean 且需要提前初始化目標對象才會進入分支
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
//省略了一些后置處理器的觸發代碼
}
到容器初始化完成,進行實例化的也只是PersonFactory而已,而真正使FactoryBean開始實例化目標對象則是實際需要目標對象時,跟着源碼可以走到下面這段核心代碼:
//org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
//如果factory管理的對象是單例且beanName已經在該BeanFactory的單例對象的緩存Map集合DefaultListableBeanFactory.singletonObjects中
if (factory.isSingleton() && containsSingleton(beanName)) {
//獲取線程互斥鎖定對象
synchronized (getSingletonMutex()) {
//如果是被創建過的對象則不會重復創建而是從緩存中獲取
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
//這里調用了實際的getObject方法,里面的邏輯很簡單,除了一些權限驗證和異常處理就是實際調用getObject
//所以不貼跟進代碼了
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
//模版回調方法
beforeSingletonCreation(beanName);
try {
//這里調用了BeanPostProcessor對目標對象進行處理
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
//模版回調方法
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
//單例對象放到緩存里去
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
到此為止,FactoryBean本身的實例化、目標對象的實例化流程就走完了。
希望這次對Spring知識點中擴展點的整理可以對自己和讀到這里的同學有一點幫助。
