Spring拓展點:BeanFactoryPostProcessor及其子接口

BeanFactoryPostProcessor

BeanFactoryPostProcessor是一個函數式接口,裏面只有一個方法:java

@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.app

機器翻譯:容許自定義修改應用程序上下文的bean定義,調整上下文的基礎bean工廠的bean屬性值。應用程序上下文能夠在其bean定義中自動檢測BeanFactoryPostProcessor bean,並在建立任何其餘bean以前先建立BeanFactoryPostProcessor。BeanFactoryPostProcessor能夠與bean定義交互並修改bean定義,但毫不能與bean實例交互。這樣作可能會致使bean過早實例化,違反容器並致使意外的反作用。若是須要bean實例交互,請考慮實現BeanPostProcessor。實現該接口,能夠容許咱們的程序獲取到 BeanFactory,從而修改 BeanFactory,能夠實現編程式的往Spring容器中添加Bean。

總結,也就是說,咱們能夠經過實現BeanFactoryPostProcessor接口,獲取BeanFactory,操做BeanFactory對象,修改BeanDefinition,但不要去實例化bean。ide

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.post

機器翻譯:對標準BeanFactoryPostProcessor SPI的擴展,容許在進行常規BeanFactoryPostProcessor檢測以前註冊其餘Bean定義。特別是,BeanDefinitionRegistryPostProcessor能夠註冊其餘Bean定義,這些定義又定義了BeanFactoryPostProcessor實例。

執行時機

那麼BeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor接口是在何時被回調的呢?ui

看過我以前文章的小夥伴不知道還記不得的,這兩個接口是在AbstractApplicationContext#refresh方法中執行到invokeBeanFactoryPostProcessors(beanFactory);方法時被執行的。Spring的編碼取名真的很藝術,方法名雖然很長,可是一看就知道在作什麼。this

舉個例子

@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接口和其父類接口中的方法。spa

  • ConfigurationClassPostProcessor#postProcessBeanFactory:主要負責對Full Configuration 配置進行加強,攔截@Bean方法來確保加強執行@Bean方法的語義。
  • ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry:負責掃描咱們的程序,根據程序的中Bean建立BeanDefinition,並註冊到容器中。

歡迎各位關注公衆號:

Coder小黑

相關文章
相關標籤/搜索