# BeanFactoryPostProcessor

BeanFactoryPostProcessor类是spring提供的可以对application context中的bean definition进行自定义修改的的后处理接口。 BeanFactoryPostProcessor只能修改BeanDefinition即Bean的定义,如果要修改bean实例,需要使用BeanPostProcessor。 相当于自定义一些Bean的定义,比如@Configuration、MyBatis的Mapper Bean都是使用BeanFactoryPostProcessor以及子接口BeanDefinitionRegistryPostProcessor实现的。

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

BeanDefinitionRegistryPostProcessor提供的postProcessBeanDefinitionRegistry方法可以在BeanFactoryPostProcessor的postProcessBeanFactory执行之前 注册bean definition。

BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor的调用时机,是在AbstractApplicationContext的refresh方法中, 在DispatcherServlet init的时候,就会创建ApplicationContext并调用refresh方法。 refresh方法中invokeBeanFactoryPostProcessors(beanFactory)是调用application context中注册的BeanFactoryPostProcessor。(前面的postProcessBeanFactory 是给AbstractApplicationContext子类留下的扩展方法,比如ServletWebServerApplicationContext会增加一些BeanPostProcessor。)

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        prepareRefresh();

        // Tell the subclass to refresh the internal bean factory.
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);

        try {
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);

    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

invokeBeanFactoryPostProcessors中,会先调用BeanFactoryPostProcessor的postProcessBeanDefinitionRegistry再调用postProcessBeanFactory。

# 常见实现

# ConfigurationClassPostProcessor

ConfigurationClassPostProcessor用来实现@Configuration注解的功能。 通过@Configuration注解,可以通过代码声明bean定义。

@Configuration
public class AppConfig {

   @Bean
   public MyBean myBean() {
       // instantiate, configure and return bean ...
   }
}
1
2
3
4
5
6
7
8

ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口, 通过ConfigurationClassParser类解析@Configuration注解标识的类中的@ComponentScan、@Bean方法定义、@Import(ImportBeanDefinitionRegistrar)等注解,向 通过ConfigurationClassParser解析完成后,ConfigurationClassPostProcessor就会在postProcessBeanDefinitionRegistry的时候将 解析出来的BeanDefinition注册到BeanFactory中。

# MapperScannerConfigurer

MapperScannerConfigurer是spring-mybatis中将Mapper接口注册为spring中的bean的BeanDefinitionRegistryPostProcessor 使用方式是定义一个MapperScannerConfigurer的bean。

 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
     <property name="basePackage" value="org.mybatis.spring.sample.mapper" />
     <!-- optional unless there are multiple session factories defined -->
     <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>
1
2
3
4
5

MapperScannerConfigurer会在postProcessBeanDefinitionRegistry的时候创建一个ClassPathMapperScanner(继承自spring内部的ClassPathBeanDefinitionScanner) 这个Scanner可以设置bean的配置比如有什么注解或继承什么接口的是MyBatis的Mapper类,通过Scanner扫描出来BeanDefinition后, 会设置一些FactoryBean、sqlSessionTemplateBeanName等 帮助创建MapperFactoryBean的属性,然后通过BeanFactory注册BeanDefinition。

另外注意spring mybatis也提供了通过在Configuration类上增加@MapperScan或@MapperScans来扫描bean的功能,功能上和MapperScannerConfigurer一致但是使用更简单。 @MapperScan是通过MapperScannerRegistrar也就是通过上面提到的ConfigurationClassPostProcessor机制来实现的。

# PropertyPlaceholderConfigurer&PropertyOverrideConfigurer

PropertyPlaceholderConfigurer、PropertyOverrideConfigurer能够替换bean定义中的${}占位符,替换为环境变量、properties文件中的值,比如替换数据库的配置等等