返回介绍

6.6.1 激活注册的 BeanFactoryPostProcessor

发布于 2025-04-22 22:09:13 字数 12734 浏览 0 评论 0 收藏

正式开始介绍之前我们先了解下 BeanFactoryPostProcessor 的用法。

BeanFactoryPostProcessor 接口跟 BeanPostProcessor 类似,可以对 bean 的定义(配置元数据)进行处理。也就是说,Spring IoC 容器允许 BeanFactoryPostProcessor 在容器实际实例化任何其他的 bean 之前读取配置元数据,并有可能修改它。如果你愿意,你可以配置多个 BeanFactoryPostProcessor。你还能通过设置“order”属性来控制 BeanFactoryPostProcessor 的执行次序(仅当 BeanFactoryPostProcessor 实现了 Ordered 接口时你才可以设置此属性,因此在实现 BeanFactoryPostProcessor 时,就应当考虑实现 Ordered 接口)。请参考 BeanFactoryPostProcessor 和 Ordered 接口的 JavaDoc 以获取更详细的信息。

如果你想改变实际的 bean 实例(例如从配置元数据创建的对象),那么你最好使用 BeanPostProcessor。同样地,BeanFactoryPostProcessor 的作用域范围是容器级的。它只和你所使用的容器有关。如果你在容器中定义一个 BeanFactoryPostProcessor,它仅仅对此容器中的 bean 进行后置处理。BeanFactoryPostProcessor 不会对定义在另一个容器中的 bean 进行后置处理,即使这两个容器都是在同一层次上。在 Spring 中存在对于 BeanFactoryPostProcessor 的典型应用,比如 PropertyPlaceholderConfigurer。

1.BeanFactoryPostProcessor 的典型应用:PropertyPlaceholderConfigurer

有时候,阅读 Spring 的 Bean 描述文件时,你也许会遇到类似如下的一些配置:

<bean id="message" class="distConfig.HelloMessage">

  <property name="mes">

  <value>${bean.message}</value>

 </property>

</bean>

其中竟然出现了变量引用:${bean.message}。这就是 Spring 的分散配置,可以在另外的配置文件中为 bean.message 指定值。如在 bean.property 配置如下定义:

bean.message=Hi,can you find me?

当访问名为 message 的 bean 时,mes 属性就会被置为字符串“ Hi,can you find me?”,但 Spring 框架是怎么知道存在这样的配置文件呢?这就要靠 PropertyPlaceholderConfigurer 这个类的 bean:

<bean id="mesHandler" class="org.Springframework.beans.factory.config. Property Placeholder

Configurer">

  <property name="locations">

  <list>

   <value>config/bean.properties</value>

  </list>

 </property>

</bean>

在这个 bean 中指定了配置文件为 config/bean.properties。到这里似乎找到问题的答案了,但是其实还有个问题。这个“mesHandler”只不过是 Spring 框架管理的一个 bean,并没有被别的 bean 或者对象引用,Spring 的 beanFactory 是怎么知道要从这个 bean 中获取配置信息的呢?

查看层级结构可以看出 PropertyPlaceholderConfigurer 这个类间接继承了 BeanFactory PostProcessor 接口。这是一个很特别的接口,当 Spring 加载任何实现了这个接口的 bean 的配置时,都会在 bean 工厂载入所有 bean 的配置之后执行 postProcessBeanFactory 方法。在 PropertyResourceConfigurer 类中实现了 postProcessBeanFactory 方法,在方法中先后调用了 mergeProperties、convertProperties、processProperties 这 3 个方法,分别得到配置,将得到的配置转换为合适的类型,最后将配置内容告知 BeanFactory。

正是通过实现 BeanFactoryPostProcessor 接口,BeanFactory 会在实例化任何 bean 之前获得配置信息,从而能够正确解析 bean 描述文件中的变量引用。

2.使用自定义 BeanFactoryPostProcessor

我们以实现一个 BeanFactoryPostProcessor,去除潜在的“流氓”属性值的功能来展示自定义 BeanFactoryPostProcessor 的创建及使用,例如 bean 定义中留下 bollocks 这样的字眼。

配置文件 BeanFactory.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.Springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.Springframework.org/schema/beans

 http://www.Springframework.org/schema/beans/Spring-beans.xsd

">

<bean id="bfpp" class="com.Spring.ch04.ObscenityRemovingBeanFactoryPostProcessor">

  <property name="obscenties">

  <set>

   <value>bollocks</value>

   <value>winky</value>

   <value>bum</value>

   <value>Microsoft</value>

  </set>

 </property>

</bean>

<bean id="simpleBean" class="com.Spring.ch04.SimplePostProcessor">

  <property name="connectionString" value="bollocks"/>

  <property name="password" value="imaginecup"/>

  <property name="username" value="Microsoft"/>

</bean>

 </beans>

ObscenityRemovingBeanFactoryPostProcessor.java

public class ObscenityRemovingBeanFactoryPostProcessor implements

  BeanFactoryPostProcessor {

  private Set<String> obscenties;

  public ObscenityRemovingBeanFactoryPostProcessor(){

   this.obscenties=new HashSet<String>();

 }

  public void postProcessBeanFactory(

   ConfigurableListableBeanFactory beanFactory) throws BeansException {

   String[] beanNames=beanFactory.getBeanDefinitionNames();

   for(String beanName:beanNames){

    BeanDefinition bd=beanFactory.getBeanDefinition(beanName);

    StringValueResolver valueResover=new StringValueResolver() {

     public String resolveStringValue(String strVal) {

      if(isObscene(strVal)) return "*****";

      return strVal;

    }

   };

    BeanDefinitionVisitor visitor=new BeanDefinitionVisitor(valueResover);

   visitor.visitBeanDefinition(bd);

  }

 }

  public boolean isObscene(Object value){

   String potentialObscenity=value.toString().toUpperCase();

   return this.obscenties.contains(potentialObscenity);

 }

  public void setObscenties(Set<String> obscenties) {

  this.obscenties.clear();

   for(String obscenity:obscenties){

   this.obscenties.add(obscenity.toUpperCase());

  }

 }

}

执行类:

public class PropertyConfigurerDemo {

  public static void main(String[] args) {

   ConfigurableListableBeanFactory bf=new XmlBeanFactory(new ClassPathResource

  ("/META-INF/BeanFactory.xml"));

   BeanFactoryPostProcessor bfpp=(BeanFactoryPostProcessor)bf.getBean("bfpp");

  bfpp.postProcessBeanFactory(bf);

  System.out.println(bf.getBean("simpleBean"));

 }

}

输出结果:

SimplePostProcessor{connectionString=*****,username=*****,password=imaginecup

通过 ObscenityRemovingBeanFactoryPostProcessor Spring 很好地实现了屏蔽掉 obscenties 定义的不应该展示的属性。

3.激活 BeanFactoryPostProcessor

了解了 BeanFactoryPostProcessor 的用法后便可以深入研究 BeanFactoryPostProcessor 的调用过程了。

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {

  // Invoke BeanDefinitionRegistryPostProcessors first, if any.

  Set<String> processedBeans = new HashSet<String>();

 //对 BeanDefinitionRegistry 类型的处理

  if (beanFactory instanceof BeanDefinitionRegistry) {

   BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;

   List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();

  /**

   * BeanDefinitionRegistryPostProcessor

   */

   List<BeanDefinitionRegistryPostProcessor> registryPostProcessors = new&nbsp;LinkedList<BeanDefinitionRegistryPostProcessor>();

  /*

   * 硬编码注册的后处理器

   */

   for (BeanFactoryPostProcessor postProcessor : getBeanFactoryPostProcessors()) {

    if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {

     BeanDefinitionRegistryPostProcessor registryPostProcessor =(Bean DefinitionRegistryPostProcessor) postProcessor;

    //对于 BeanDefinitionRegistryPostProcessor 类型,在 BeanFactoryPostProcessor 的基础上还有自己定义的方法,需要先调用

    registryPostProcessor.postProcessBeanDefinitionRegistry(registry);

    registryPostProcessors.add(registryPostProcessor);

    }else {

    //记录常规 BeanFactoryPostProcessor

    regularPostProcessors.add(postProcessor);

   }

  }

  /*

   * 配置注册的后处理器

   */

   Map<String, BeanDefinitionRegistryPostProcessor> beanMap = beanFactory.

   getBeansOfType(BeanDefinitionRegistryPostProcessor.class, true, false);

   List<BeanDefinitionRegistryPostProcessor> registryPostProcessorBeans =

    new ArrayList<BeanDefinitionRegistryPostProcessor>(beanMap.values());

  OrderComparator.sort(registryPostProcessorBeans);

   for (BeanDefinitionRegistryPostProcessor postProcessor : registryPostProcessorBeans) {

   //BeanDefinitionRegistryPostProcessor 的特殊处理

   postProcessor.postProcessBeanDefinitionRegistry(registry);

  }

  //激活 postProcessBeanFactory 方法,之前激活的是 postProcessBeanDefinitionRegistry

  //硬编码设置的 BeanDefinitionRegistryPostProcessor

   invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);

  //配置的 BeanDefinitionRegistryPostProcessor

   invokeBeanFactoryPostProcessors(registryPostProcessorBeans, beanFactory);

  //常规 BeanFactoryPostProcessor

   invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);

  processedBeans.addAll(beanMap.keySet());

 }

  else {

   // Invoke factory processors registered with the context instance.

   invokeBeanFactoryPostProcessors(getBeanFactoryPostProcessors(), beanFactory);

 }

 //对于配置中读取的 BeanFactoryPostProcessor 的处理

  String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPost

  Processor.class, true, false);

  List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList

 <BeanFactoryPostProcessor>();

  List<String> orderedPostProcessorNames = new ArrayList<String>();

  List<String> nonOrderedPostProcessorNames = new ArrayList<String>();

 //对后处理器进行分类

  for (String ppName : postProcessorNames) {

   if (processedBeans.contains(ppName)) {

   //已经处理过

   }else if (isTypeMatch(ppName, PriorityOrdered.class)) {

   priorityOrderedPostProcessors.add(beanFactory.getBean(ppName,

   BeanFactoryPostProcessor.class));

   }else if (isTypeMatch(ppName, Ordered.class)) {

   orderedPostProcessorNames.add(ppName);

   }else {

   nonOrderedPostProcessorNames.add(ppName);

  }

 }

 //按照优先级进行排序

 OrderComparator.sort(priorityOrderedPostProcessors);

  invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

  // Next, invoke the BeanFactoryPostProcessors that implement Ordered.

  List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactory

 PostProcessor>();

  for (String postProcessorName : orderedPostProcessorNames) {

   orderedPostProcessors.add(getBean(postProcessorName, BeanFactoryPostProcessor.

  class));

 }

 //按照 order 排序

 OrderComparator.sort(orderedPostProcessors);

  invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

 //无序,直接调用

  List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactory

 PostProcessor>();

  for (String postProcessorName : nonOrderedPostProcessorNames) {

  nonOrderedPostProcessors.add(getBean(postProcessorName,

  BeanFactoryPostProcessor.class));

 }

  invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

}

从上面的方法中我们看到,对于 BeanFactoryPostProcessor 的处理主要分两种情况进行,一个是对于 BeanDefinitionRegistry 类的特殊处理,另一种是对普通的 BeanFactoryPostProcessor 进行处理。而对于每种情况都需要考虑硬编码注入注册的后处理器以及通过配置注入的后处理器。

对于 BeanDefinitionRegistry 类型的处理类的处理主要包括以下内容。

(1)对于硬编码注册的后处理器的处理,主要是通过 AbstractApplicationContext 中的添加处理器方法 addBeanFactoryPostProcessor 进行添加。

public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor) {

 this.beanFactoryPostProcessors.add(beanFactoryPostProcessor);

}

添加后的后处理器会存放在 beanFactoryPostProcessors 中,而在处理 BeanFactoryPostProcessor 时候会首先检测 beanFactoryPostProcessors 是否有数据。当然,BeanDefinitionRegistryPostProcessor 继承自 BeanFactoryPostProcessor,不但有 BeanFactoryPostProcessor 的特性,同时还有自己定义的个性化方法,也需要在此调用。所以,这里需要从 beanFactoryPostProcessors 中挑出 BeanDefinitionRegistryPostProcessor 的后处理器,并进行其 postProcessBeanDefinitionRegistry 方法的激活。

(2)记录后处理器主要使用了三个 List 完成。

registryPostProcessors:记录通过硬编码方式注册的 BeanDefinitionRegistryPostProcessor 类型的处理器。

regularPostProcessors:记录通过硬编码方式注册的 BeanFactoryPostProcessor 类型的处理器。

registryPostProcessorBeans:记录通过配置方式注册的 BeanDefinitionRegistryPostProcessor 类型的处理器。

( 3 )对以上所记录的 List 中的后处理器进行统一调用 BeanFactoryPostProcessor 的 postProcessBeanFactory 方法。

(4)对 beanFactoryPostProcessors 中非 BeanDefinitionRegistryPostProcessor 类型的后处理器进行统一的 BeanFactoryPostProcessor 的 postProcessBeanFactory 方法调用。

(5)普通 beanFactory 处理。

BeanDefinitionRegistryPostProcessor 只对 BeanDefinitionRegistry 类型的 ConfigurableListable BeanFactory 有效,所以如果判断所示的 beanFactory 并不是 BeanDefinitionRegistry,那么便可以忽略 BeanDefinitionRegistryPostProcessor,而直接处理 BeanFactoryPostProcessor,当然获取的方式与上面的获取类似。

这里需要提到的是,对于硬编码方式手动添加的后处理器是不需要做任何排序的,但是在配置文件中读取的处理器,Sping 并不保证读取的顺序。所以,为了保证用户的调用顺序的要求,Spring 对于后处理器的调用支持按照 PriorityOrdered 或者 Ordered 的顺序调用。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。