Spring拓展点BeanFactoryPostProcessor及其子接口

44次阅读

共计 4382 个字符,预计需要花费 11 分钟才能阅读完成。

BeanFactoryPostProcessor

BeanFactoryPostProcessor是一个函数式接口,里面只有一个方法:

@FunctionalInterface
public interface BeanFactoryPostProcessor {void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

再看一下 doc 文档上的相关描述:

Allows for custom modification of an application context’s bean definitions, adapting the bean property values of the context’s underlying bean factory. Application contexts can auto-detect BeanFactoryPostProcessor beans in their bean definitions and apply them before any other beans get created. 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 BeanPostProcessor instead.

机器翻译:允许自定义修改应用程序上下文的 bean 定义,调整上下文的基础 bean 工厂的 bean 属性值。应用程序上下文可以在其 bean 定义中自动检测 BeanFactoryPostProcessor bean,并在创建任何其他 bean 之前先创建 BeanFactoryPostProcessor。BeanFactoryPostProcessor 可以与 bean 定义交互并修改 bean 定义,但绝不能与 bean 实例交互。这样做可能会导致 bean 过早实例化,违反容器并导致意外的副作用。如果需要 bean 实例交互,请考虑实现 BeanPostProcessor。实现该接口,可以允许我们的程序获取到BeanFactory,从而修改BeanFactory,可以实现编程式的往 Spring 容器中添加 Bean。

总结,也就是说,我们可以通过实现 BeanFactoryPostProcessor 接口,获取 BeanFactory,操作BeanFactory 对象,修改BeanDefinition,但不要去实例化 bean。

BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor 的子类,在父类的基础上,增加了新的方法,允许我们获取到 BeanDefinitionRegistry,从而编码动态修改BeanDefinition。例如往BeanDefinition 中添加一个新的BeanDefinition

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}

Extension to the standard BeanFactoryPostProcessor SPI, allowing for the registration of further bean definitions before regular BeanFactoryPostProcessor detection kicks in. In particular, BeanDefinitionRegistryPostProcessor may register further bean definitions which in turn define BeanFactoryPostProcessor instances.

机器翻译:对标准 BeanFactoryPostProcessor SPI 的扩展,允许在进行常规 BeanFactoryPostProcessor 检测之前注册其他 Bean 定义。特别是,BeanDefinitionRegistryPostProcessor 可以注册其他 Bean 定义,这些定义又定义了 BeanFactoryPostProcessor 实例。

执行时机

那么 BeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor接口是在什么时候被回调的呢?

看过我之前文章的小伙伴不知道还记不得的,这两个接口是在 AbstractApplicationContext#refresh 方法中执行到 invokeBeanFactoryPostProcessors(beanFactory); 方法时被执行的。Spring 的编码取名真的很艺术,方法名虽然很长,但是一看就知道在做什么。

举个例子

@Repository
public class OrderDao {public void query() {System.out.println("OrderDao query...");
    }
}
public class OrderService {

    private OrderDao orderDao;

    public void setDao(OrderDao orderDao) {this.orderDao = orderDao;}

    public void init() {System.out.println("OrderService init...");
    }

    public void query() {orderDao.query();
    }
}
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        // 向 Spring 容器中注册 OrderService
        BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(OrderService.class)
                // 这里的属性名是根据 setter 方法
                .addPropertyReference("dao", "orderDao")
                .setInitMethodName("init")
                .setScope(BeanDefinition.SCOPE_SINGLETON)
                .getBeanDefinition();

        registry.registerBeanDefinition("orderService", beanDefinition);

    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 在这里修改 orderService bean 的 scope 为 PROTOTYPE
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("orderService");
        beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
    }
}

OrderService通过 MyBeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 注册到了容器中,又通过 MyBeanDefinitionRegistryPostProcessor#postProcessBeanFactory 方法修改了其 Scope。最后运行主方法:

@Configuration
@ComponentScan
public class Main {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class);
        // 能成功从容器中获取 orderService, 并成功调用 orderService.query(); 方法
        OrderService orderService = context.getBean(OrderService.class);
        orderService.query();
        OrderService orderService2 = context.getBean(OrderService.class);
        //false,orderService 已经不是单例
        System.out.println(orderService == orderService2);
        context.close();}
}

典型应用:ConfigurationClassPostProcessor

在 Spring 中 ConfigurationClassPostProcessor 同时实现了 BeanDefinitionRegistryPostProcessor 接口和其父类接口中的方法。

  • ConfigurationClassPostProcessor#postProcessBeanFactory:主要负责对 Full Configuration 配置进行增强,拦截 @Bean 方法来确保增强执行 @Bean 方法的语义。
  • ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry:负责扫描我们的程序,根据程序的中 Bean 创建BeanDefinition,并注册到容器中。

欢迎各位关注公众号:

正文完
 0