Spring擴展點探索之BeanFactoryPostProcessor

只需低頭努力,剩下的交給時光,時間會公平地幫你處理這一切

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天堂】公衆號,我會定期分享自己的學習成果,第一時間推送給您

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章