只需低頭努力,剩下的交給時光,時間會公平地幫你處理這一切
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天堂】公衆號,我會定期分享自己的學習成果,第一時間推送給您