Spring扩展点探索之BeanFactoryPostProcessor

ゞ 浴缸里的玫瑰 2022-12-28 12:32 237阅读 0赞

只需低头努力,剩下的交给时光,时间会公平地帮你处理这一切

BeanFactoryPostProcessor是用来处理BeanFactory中Bean属性的后置处理器,也就是说在Bean初始化之前,Spirng提供了一个钩子可以让你根据自己的实际情况修改Bean的属性,最常见的应用就是我们的Bean中会有一些占位符,那么在Bean实例化之前这些占位符肯定是要被实际的配置参数填充的,这个填充的过程就是通过BeanFactoryPostProcessor的后置处理完成的

定义

BeanFactoryPostProcessor接口很简单,只有一个方法

  1. /** * 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 */
  2. @FunctionalInterface
  3. public interface BeanFactoryPostProcessor {
  4. /** * 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 */
  5. void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
  6. }

从注释可以看出来:

  • BeanFactoryPostProcessor接口允许修改上下文中Bean的定义(definitions),可以调整Bean的属性
  • 上下文可以自动检测BeanFactoryPostProcessor,并且在Bean实例化之前调用

注意事项:

  • BeanFactoryPostProcessor可以在Bean实例化之前修改Bean的属性,但不适合在BeanFactoryPostProcessor中做Bean的实例化,这样会导致一些意想不到的副作用,就是不要把Spring玩坏了,若需要做Bean的实例化可以使用BeanPostProcessor

写个例子

1、定义一个User类

  1. public class User {
  2. private String userName;
  3. private int age;
  4. public User(String userName,int age){
  5. this.userName = userName;
  6. this.age = age;
  7. }
  8. public String getUserName() {
  9. return userName;
  10. }
  11. public void setUserName(String userName) {
  12. this.userName = userName;
  13. }
  14. public int getAge() {
  15. return age;
  16. }
  17. public void setAge(int age) {
  18. this.age = age;
  19. }
  20. }

2、配置类

  1. @Component
  2. public class Configuration {
  3. @Bean(name = "user")
  4. public User getUser(){
  5. return new User("Jack",18);
  6. }
  7. }

3、测试类

  1. public class Main {
  2. public static void main(String[] args){
  3. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("org.kxg.springDemo.beanFactoryPostProcessor");
  4. User user = applicationContext.getBean("user",User.class);
  5. System.out.println(user.getUserName());
  6. }
  7. }

输出结果:

  1. Jack

以上是一个Spring入门级的例子,把User对象注册到容器中,然后从容器中取出User对象,并且打印userName属性

下面我们自定义一个BeanFactoryPostProcessor来修改这个User对象的属性

1、自定义BeanFactoryPostProcessor

  1. public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
  2. @Override
  3. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  4. System.out.println("调用自定义BeanFactoryPostProcessor");
  5. BeanDefinition beanDefinition = beanFactory.getBeanDefinition("user");
  6. System.out.println("开始修改属性的值");
  7. beanDefinition.getPropertyValues().add("userName","Tom");
  8. }
  9. }

自定义一个MyBeanFactoryPostProcessor实现BeanFactoryPostProcessor接口,重写postProcessBeanFactory()方法来实现对User Bean定义的修改

2、将MyBeanFactoryPostProcessor注册到Spring容器中

  1. @Component
  2. public class Configuration {
  3. @Bean(name = "user")
  4. public User getUser(){
  5. return new User("Jack",18);
  6. }
  7. @Bean
  8. public BeanFactoryPostProcessor custom(){
  9. return new MyBeanFactoryPostProcessor();
  10. }
  11. }

再次运行上面的main方法,运行结果如下:

  1. 调用自定义BeanFactoryPostProcessor
  2. 开始修改属性的值
  3. Tom

从运行结果来看,虽然一开始定义User类的userName属性是Jack,但在MyBeanFactoryPostProcessor中将userName属性修改成Tom,最后获取到的User对象是修改后的对象,至此Bean的属性在实例化之前被修改了,这就是BeanFactoryPostProcessor的作用

源码分析

上面我们知道,BeanFactoryPostProcessor是在Bean被实例化之前对Bean的定义信息进行修改,那么Spring是如何实现对自定义BeanFactoryPostProcessor的调用的,下面通过源码来看一下,首先还是从refresh()方法入手,在refresh()方法中会调用invokeBeanFactoryPostProcessors(beanFactory);

  1. protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
  2. //主要是这一行
  3. PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
  4. // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
  5. // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
  6. if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
  7. beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
  8. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
  9. }
  10. }
  11. public static void invokeBeanFactoryPostProcessors(
  12. ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
  13. /**因代码太长,省略了***/
  14. //这里从beanFacoty中通过BeanFactoryPostProcessor类型来获取Bean名称,就可以拿到我们自定义的BeanFactoryPostProcessor
  15. String[] postProcessorNames =
  16. beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
  17. List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
  18. List<String> orderedPostProcessorNames = new ArrayList<>();
  19. List<String> nonOrderedPostProcessorNames = new ArrayList<>();
  20. for (String ppName : postProcessorNames) {
  21. if (processedBeans.contains(ppName)) {
  22. // skip - already processed in first phase above
  23. }
  24. //这里是优先级的处理,如果我们有多个自定义的BeanFactoryPostProcessor,可以通过优先级来定义执行顺序
  25. else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
  26. priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
  27. }
  28. else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
  29. orderedPostProcessorNames.add(ppName);
  30. }
  31. else {
  32. nonOrderedPostProcessorNames.add(ppName);
  33. }
  34. }
  35. // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
  36. //这里先处理实现了PriorityOrdered接口的BeanFactoryPostProcessor,也就是定义了优先级的先处理
  37. sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
  38. invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
  39. // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
  40. //再处理实现了Ordered接口的BeanFactoryPostProcessor
  41. List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
  42. for (String postProcessorName : orderedPostProcessorNames) {
  43. orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
  44. }
  45. sortPostProcessors(orderedPostProcessors, beanFactory);
  46. invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
  47. // Finally, invoke all other BeanFactoryPostProcessors.
  48. List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
  49. for (String postProcessorName : nonOrderedPostProcessorNames) {
  50. nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
  51. }
  52. //这里才到了处理普通的自定义BeanFactoryPostProcessors
  53. invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
  54. // Clear cached merged bean definitions since the post-processors might have
  55. // modified the original metadata, e.g. replacing placeholders in values...
  56. beanFactory.clearMetadataCache();
  57. }
  58. private static void invokeBeanFactoryPostProcessors(
  59. Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
  60. for (BeanFactoryPostProcessor postProcessor : postProcessors) {
  61. postProcessor.postProcessBeanFactory(beanFactory);
  62. }
  63. }

invokeBeanFactoryPostProcessors()方法的逻辑很简单,就是去遍历容器中的BeanFactoryPostProcessor,然后调用postProcessBeanFactory()方法,这个方法就是我们自定义BeanFactoryPostProcessor时需要去实现的方法,至此整个流程就已经很清晰了

总结

  • BeanFactoryPostProcessor是用来处理BeanFacoty中Bean属性的后置处理器
  • BeanFactoryPostProcessor接口只定义了一个简单的方法postProcessBeanFactory()
  • BeanFactoryPostProcessor接口允许修改上下文中Bean的定义(definitions),可以调整Bean的属性
  • 上下文可以自动检测BeanFactoryPostProcessor,并且在Bean实例化之前调用
  • 注意事项:BeanFactoryPostProcessor可以在Bean实例化之前修改Bean的属性,但不适合在BeanFactoryPostProcessor中做Bean的实例化,这样会导致一些意想不到的副作用,就是不要把Spring玩坏了_ ,若需要做Bean的实例化可以使用BeanPostProcessor

如果感觉对你有些帮忙,请收藏好,你的关注和点赞是对我最大的鼓励!
如果想跟我一起学习,坚信技术改变世界,请关注【Java天堂】公众号,我会定期分享自己的学习成果,第一时间推送给您

在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,237人围观)

还没有评论,来说两句吧...

相关阅读