只需低頭努力,剩下的交給時光,時間會公平地幫你處理這一切
BeanFactoryPostProcessor是用來處理BeanFactory中Bean屬性的后置處理器,也就是說在Bean初始化之前,Spirng提供了一個鉤子可以讓你根據自己的實際情況修改Bean的屬性,最常見的應用就是我們的Bean中會有一些占位符,那么在Bean實體化之前這些占位符肯定是要被實際的配置引數填充的,這個填充的程序就是通過BeanFactoryPostProcessor的后置處理完成的
定義
BeanFactoryPostProcessor介面很簡單,只有一個方法
/**
* Allows for custom modification of an application context's bean definitions,
* adapting the bean property values of the context's underlying bean factory.
*
* <p>Application contexts can auto-detect BeanFactoryPostProcessor beans in
* their bean definitions and apply them before any other beans get created.
*
* <p>Useful for custom config files targeted at system administrators that
* override bean properties configured in the application context.
*
* <p>See PropertyResourceConfigurer and its concrete implementations
* for out-of-the-box solutions that address such configuration needs.
*
* <p>A BeanFactoryPostProcessor may interact with and modify bean
* definitions, but never bean instances. Doing so may cause premature bean
* instantiation, violating the container and causing unintended side-effects.
* If bean instance interaction is required, consider implementing
* {@link BeanPostProcessor} instead.
*
* @author Juergen Hoeller
* @since 06.07.2003
* @see BeanPostProcessor
* @see PropertyResourceConfigurer
*/
@FunctionalInterface
public interface BeanFactoryPostProcessor {
/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for overriding or adding
* properties even to eager-initializing beans.
* @param beanFactory the bean factory used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
從注釋可以看出來:
- BeanFactoryPostProcessor介面允許修改背景關系中Bean的定義(definitions),可以調整Bean的屬性
- 背景關系可以自動檢測BeanFactoryPostProcessor,并且在Bean實體化之前呼叫
注意事項:
- BeanFactoryPostProcessor可以在Bean實體化之前修改Bean的屬性,但不適合在BeanFactoryPostProcessor中做Bean的實體化,這樣會導致一些意想不到的副作用,就是不要把Spring玩壞了,若需要做Bean的實體化可以使用BeanPostProcessor
寫個例子
1、定義一個User類
public class User {
private String userName;
private int age;
public User(String userName,int age){
this.userName = userName;
this.age = age;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
2、配置類
@Component
public class Configuration {
@Bean(name = "user")
public User getUser(){
return new User("Jack",18);
}
}
3、測驗類
public class Main {
public static void main(String[] args){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("org.kxg.springDemo.beanFactoryPostProcessor");
User user = applicationContext.getBean("user",User.class);
System.out.println(user.getUserName());
}
}
輸出結果:
Jack
以上是一個Spring入門級的例子,把User物件注冊到容器中,然后從容器中取出User物件,并且列印userName屬性
下面我們自定義一個BeanFactoryPostProcessor來修改這個User物件的屬性
1、自定義BeanFactoryPostProcessor
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("呼叫自定義BeanFactoryPostProcessor");
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("user");
System.out.println("開始修改屬性的值");
beanDefinition.getPropertyValues().add("userName","Tom");
}
}
自定義一個MyBeanFactoryPostProcessor實作BeanFactoryPostProcessor介面,重寫postProcessBeanFactory()方法來實作對User Bean定義的修改
2、將MyBeanFactoryPostProcessor注冊到Spring容器中
@Component
public class Configuration {
@Bean(name = "user")
public User getUser(){
return new User("Jack",18);
}
@Bean
public BeanFactoryPostProcessor custom(){
return new MyBeanFactoryPostProcessor();
}
}
再次運行上面的main方法,運行結果如下:
呼叫自定義BeanFactoryPostProcessor
開始修改屬性的值
Tom
從運行結果來看,雖然一開始定義User類的userName屬性是Jack,但在MyBeanFactoryPostProcessor中將userName屬性修改成Tom,最后獲取到的User物件是修改后的物件,至此Bean的屬性在實體化之前被修改了,這就是BeanFactoryPostProcessor的作用
原始碼分析
上面我們知道,BeanFactoryPostProcessor是在Bean被實體化之前對Bean的定義資訊進行修改,那么Spring是如何實作對自定義BeanFactoryPostProcessor的呼叫的,下面通過原始碼來看一下,首先還是從refresh()方法入手,在refresh()方法中會呼叫invokeBeanFactoryPostProcessors(beanFactory);
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//主要是這一行
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
/**因代碼太長,省略了***/
//這里從beanFacoty中通過BeanFactoryPostProcessor型別來獲取Bean名稱,就可以拿到我們自定義的BeanFactoryPostProcessor
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
//這里是優先級的處理,如果我們有多個自定義的BeanFactoryPostProcessor,可以通過優先級來定義執行順序
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
//這里先處理實作了PriorityOrdered介面的BeanFactoryPostProcessor,也就是定義了優先級的先處理
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
//再處理實作了Ordered介面的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
//這里才到了處理普通的自定義BeanFactoryPostProcessors
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}
private static void invokeBeanFactoryPostProcessors(
Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
for (BeanFactoryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanFactory(beanFactory);
}
}
invokeBeanFactoryPostProcessors()方法的邏輯很簡單,就是去遍歷容器中的BeanFactoryPostProcessor,然后呼叫postProcessBeanFactory()方法,這個方法就是我們自定義BeanFactoryPostProcessor時需要去實作的方法,至此整個流程就已經很清晰了
總結
- BeanFactoryPostProcessor是用來處理BeanFacoty中Bean屬性的后置處理器
- BeanFactoryPostProcessor介面只定義了一個簡單的方法postProcessBeanFactory()
- BeanFactoryPostProcessor介面允許修改背景關系中Bean的定義(definitions),可以調整Bean的屬性
- 背景關系可以自動檢測BeanFactoryPostProcessor,并且在Bean實體化之前呼叫
- 注意事項:BeanFactoryPostProcessor可以在Bean實體化之前修改Bean的屬性,但不適合在BeanFactoryPostProcessor中做Bean的實體化,這樣會導致一些意想不到的副作用,就是不要把Spring玩壞了_ ,若需要做Bean的實體化可以使用BeanPostProcessor
如果感覺對你有些幫忙,請收藏好,你的關注和點贊是對我最大的鼓勵!
如果想跟我一起學習,堅信技術改變世界,請關注【Java天堂】公眾號,我會定期分享自己的學習成果,第一時間推送給您

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/236636.html
標籤:其他
