美文网首页FAQ
Spring BeanPostProsser最佳实践

Spring BeanPostProsser最佳实践

作者: liaijuyyer | 来源:发表于2021-11-10 23:09 被阅读0次

BeanPostProcessor接口的作用是在Spring bean 实例化完成后(执行完initializeBean)之后,初始化之前(执行bean的初始化方法)对Bean添加一些自定义的处理逻辑。也就是说执行beanProcessor方法是在bean实例化之后 此时bean的属性值都已经被赋值好了。另外需要注意的是 beanProcessor的实现类一定要被Spring托管才能生效。

一、BeanPostProcessor示例

  • 实体类

      @Component
      @ConfigurationProperties(prefix = "spring.datasource")
      public class DataSourceProperty {
      
      
          private String userName;
      
          private String password;
      
          /**
           * 通过@PostConstruct来标记这个init方法为bean的初始化方法
           **/
          @PostConstruct
          private void init() {
              //这条语句会在 beanprocessor的postProcessBeforeInitialization方法执行之后执行 2
              System.out.println("执行初始化方法");
          }
      
          public String getUserName() {
              return userName;
          }
      
          public void setUserName(String userName) {
              this.userName = userName;
          }
      
          public String getPassword() {
              return password;
          }
      
          public void setPassword(String password) {
              this.password = password;
          }
      }
    
  • 配置

    spring.datasource.username=test
    spring.datasource.password=12345678
    
  • 自定义的BeanPostProcessor实现类

      //这个类一定要被spring容器托管(也就是要能够被spring识别为一个bean) postProcessBeforeInitialization 和 
      //postProcessAfterInitialization才会生效
      @Component
      public class MyBeanPostProcessor implements BeanPostProcessor {
      
          /**
           * bean实例化前处理
           * @param bean
           * @param beanName
           * @return
           * @throws BeansException
           */
          @Override
          public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
              if (bean instanceof DataSourceProperty) {
                          //这条语句是最先打印的 1  DataSourceProperty 此时它的两个属性是已经被赋值了的
                  System.out.println("dataSourceProperty 初始化前执行 dataSourceProperty" );
              }
              return bean;
          }
      
          /**
           * bean实例化后处理
           * @param bean
           * @param beanName
           * @return
           * @throws BeansException
           */
          @Override
          public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
              if (bean instanceof DataSourceProperty) {
                  //这条语句是最后打印的
                  System.out.println("dataSourceProperty 初始后执行" );
              }
              return bean;
          }
      }
    
  • 结果

二、为什么BeanPostProcessor必须被Spring托管才能生效
关于这一点可以查看源码

  • 第一步
    当Spring容器启动时 会先执行AbstractApplicationContext类的refresh方法 通过该方法去初始化我们的Spring容器 源码如下
      public abstract class AbstractApplicationContext extends DefaultResourceLoader
              implements ConfigurableApplicationContext {
          @Override
          public void refresh() throws BeansException, IllegalStateException {
              synchronized (this.startupShutdownMonitor) {
                  //省略前面若干方法
                  prepareBeanFactory(beanFactory);
      
                  try {
              //此处省略若干方法
                      // 向Spring容器注册beanProstProcessor
                      registerBeanPostProcessors(beanFactory);
                      beanPostProcess.end();
                      //此处省略若干方法 完成Spring容器刷新工作
                      finishRefresh();
                  }catch (BeansException ex) {
                      //此处省略
                  }finally {
                      //此处生路
                  }
              }
          }
      }
    
  • 第二步
    从第一步 我们知道了当Spring容器在执行refresh方法的时候 会向容器中注册beanProcessor 下面接着看registerBeanPostProcessors(beanFactory)方法的逻辑 该方法的真正实现是在PostProcessorRegistrationDelegate类中
      final class PostProcessorRegistrationDelegate {
        public static void registerBeanPostProcessors(
                  ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
              //核心方法 从beanFactory中获取容器中所有实现了BeanPostProcessor接口的bean的名称
              String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
          //此后省略若干方法
          }
      }
    
  • 第三步
    beanFactory.getBeanNamesForType() 这个方法真正的实现是在DefaultListableBeanFactory中
      public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
              implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
          
        @Override
          public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
              if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
                  //真正获取beanPostProcessor的名称的方法
            return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
              }
              //此处省略若干方法
              return resolvedBeanNames;
          }
      }
    
  • 第四步
      public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
              implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
        
        private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
              List<String> result = new ArrayList<>();
      
              // 它会遍历Spring容器的beanDefinitionNames 
              for (String beanName : this.beanDefinitionNames) {
                    //此处省略若干方法
              //如果类型是指定的类型 则将这个bean的名称加入到list中
              //对于BeanPostProcessor来说 此时type就是BeanPostProcessor
                      boolean matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
                      //此处省略若干方法      
                      if (matchFound) {
                          result.add(beanName);
                      }
              //此处省略若干方法
              }
              return StringUtils.toStringArray(result);
          }
      }   
    

可以发现它最终还是需要通过遍历Spring容器中所有的beanName才能够将这个bean注册为BeanProcessor 如果这个BeanPostProcessor的实现类都没有被Spring托管 也就不可能被注册为beanProcessor 这也就是为什么beanProcessor的实现类必须被spring托管才能生效。

三、BeanPostProcessor执行的流程

//第一步 容器刷新
1、AbstractApplicationContext.refresh()
//第二步 完成beanFactory初始化
2、AbstractApplicationContext.finishBeanFactoryInitialization(beanFactory);  
//第三步 默认的beanFactory开始预实例化单例bean
3、DefaultListableBeanFactory.preInstantiateSingletons();
//第四步 开始根据bean的名称获取bean
4、AbstractBeanFactory.getBean(String name);
//第五步 执行doCreateBean方法 开始创建bean
5、AbstractAutowireCapableBeanFactory.doCreateBean()
//第六步 对bean进行初始化
AbstractAutowireCapableBeanFactory.initializeBean()  
//第七步 开始遍历beanProcessor 执行beanProcessor的postProcessBeforeInitialization方法
AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization();
//第八步 执行beanPostProcessor的后置方法
AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization();

initializeBean源码

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
        //此处省略若干方法
        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
      //执行beanPostProcessor的前置方法
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
      //执行bean的初始化方法
            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的后置方法
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }

applyBeanPostProcessorsBeforeInitialization源码

@Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
            throws BeansException {

        Object result = existingBean;
    //遍历beanPostProcessor 执行前置方法
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessBeforeInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }

applyBeanPostProcessorsAfterInitialization源码

@Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
            throws BeansException {

        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }

相关文章

网友评论

    本文标题:Spring BeanPostProsser最佳实践

    本文链接:https://www.haomeiwen.com/subject/voxwzltx.html