【README】

  1. 本文总结了spring集成mybatis的底层原理及源码分析;
  2. 本文借助 mybatis的MapperScannerConfigurer是 BeanDefinitionRegistryPostProcessor,扩展分析了 BeanDefinitionRegistryPostProcessor与BeanFactoryPostProcessor的源码及使用场景;

【1】SqlSessionFactory

【1.1】spring集成mybatis操作数据库开发事例

spring-mybatis-beans-mapperscan.xml 】spring集成mybatis的bean定义xml

  1. SqlSessionFactory的bean创建依赖于 SqlSessionFactoryBean,所以定义SqlSessionFactory的class为SqlSessionFactoryBean
  2. userMapper的bean创建依赖于 MapperFactoryBean, 所以定义了userMapper的class为MapperFactoryBean
<?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="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/myspring" />
        <property name="username" value="root" />
        <property name="password" value="rootroot" />
        <property name="initialSize" value="2" />
        <property name="maxIdle" value="2" />
        <property name="minIdle" value="1" />
    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:a_src_deep_analysis/chapter9/mybatis-config.xml"/>
        <property name="dataSource" ref="dataSource"/>
    </bean>
<!--    <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">-->
<!--        <property name="mapperInterface" value="com.tom.srccode.deep.analysis.chapter9.UserMapper" />-->
<!--        <property name="sqlSessionFactory" ref="sqlSessionFactory" />-->
<!--    </bean>-->

    <!-- 使用MapperScannerConfigurer,扫描特定包,自动成批创建映射器Mapper -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.tom.srccode.deep.analysis.chapter9" />
        <property name="processPropertyPlaceHolders" value="true" />
    </bean>
</beans>

mybatis-config.xml 】 mybaits配置xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <setting name="cacheEnabled" value="true"/>
        <setting name="defaultExecutorType" value="SIMPLE"/>
    </settings>
    <typeAliases>
        <typeAlias alias="UserPO" type="com.tom.srccode.deep.analysis.chapter9.UserPO" />
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="jdbc" />
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/myspring"/>
                <property name="username" value="root"/>
                <property name="password" value="rootroot"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="a_src_deep_analysis/chapter9/UserMapper.xml" />
    </mappers>

</configuration>

【使用UserMapper的单元测试案例】

@Slf4j
public class SpringMybatisIntegrateUnitTest {
    @Test
    public void test() {
//        ApplicationContext context = new ClassPathXmlApplicationContext("a_src_deep_analysis/chapter9/spring-mybatis-beans.xml");
        ApplicationContext context = new ClassPathXmlApplicationContext("a_src_deep_analysis/chapter9/spring-mybatis-beans-mapperscan.xml");
        UserMapper userMapper = context.getBean(UserMapper.class);
        log.info("user = {}", userMapper.getUser("3"));
    }

【使用SqlSession操作db的单元测试案例】

@Test
public void test3() {
    ApplicationContext context = new ClassPathXmlApplicationContext("a_src_deep_analysis/chapter9/spring-mybatis-beans-mapperscan.xml");
  // 获取 SqlSessionFactory bean
    SqlSessionFactory sqlSessionFactory = context.getBean("sqlSessionFactory", SqlSessionFactory.class);
    Map<String, Object> paramMap = new HashMap<>(2);
    paramMap.put("id", "3");
    // 使用SqlSessionFactory获取 SqlSession , 并通过 SqlSession操作数据库 
    try(SqlSession sqlSession = sqlSessionFactory.openSession(true)) {
        List<UserPO> userPOList = sqlSession.selectList("com.tom.srccode.deep.analysis.chapter9.UserMapper.getUser", paramMap);
        log.info("userPOList = {}", userPOList);
    }
}

【使用SqlSession.getMapper()操作db的单元测试案例】

/**
 * @description 使用SqlSession获取UserMapper,操作数据库
 *
 * @author tomx
 * @datetime 2026/7/4 20:15
 */
@Test
public void test4() {
    ApplicationContext context = new ClassPathXmlApplicationContext("a_src_deep_analysis/chapter9/spring-mybatis-beans-mapperscan.xml");
    SqlSessionFactory sqlSessionFactory = context.getBean("sqlSessionFactory", SqlSessionFactory.class);
    Map<String, Object> paramMap = new HashMap<>(2);
    paramMap.put("id", "3");
    try(SqlSession sqlSession = sqlSessionFactory.openSession(true)) {
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        log.info("userPOList = {}", userMapper.getUser("3"));
    }
}

【1.2】SqlSessionFactory-bean的创建依赖SqlSessionFactoryBean

  1. SqlSessionFactory的bean创建依赖于 SqlSessionFactoryBean,其类层次结构如下。
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ContextRefreshedEvent> {
 
  public void afterPropertiesSet() throws Exception {
        Assert.notNull(this.dataSource, "Property 'dataSource' is required");
        Assert.notNull(this.sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
        Assert.state(this.configuration == null && this.configLocation == null || this.configuration == null || this.configLocation == null, "Property 'configuration' and 'configLocation' can not specified with together");
        this.sqlSessionFactory = this.buildSqlSessionFactory();
    }

    protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
        XMLConfigBuilder xmlConfigBuilder = null;
        Configuration targetConfiguration;
        if (this.configuration != null) {
          // ...
        }
    }
  
  public SqlSessionFactory getObject() throws Exception {
        if (this.sqlSessionFactory == null) {
            this.afterPropertiesSet();
        }

        return this.sqlSessionFactory;
    }
}

【代码解说】

  1. InitializingBean的实现类,在bean初始化为bean属性赋值时会调用其afterPropertiesSet(), 该方法旨在创建 SqlSessionFactory;
  2. FactoryBean的实现类,当applicationContext.get(‘beanName’)时,若bean的class为FactoryBean,则会调用其getObject()方法获取bean实例;


【1.3】UserMapper或业务Mapper的创建过程依赖 MapperFactoryBean

  1. 单元测试中, UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 因UserMapper的class定义为org.mybatis.spring.mapper.MapperFactoryBean,所以调用MapperFactoryBean#getObject()方法;
  2. org.mybatis.spring.mapper.MapperFactoryBean定义如下(继承SqlSessionDaoSupport):
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
    
    private Class<T> mapperInterface;
    private boolean addToConfig = true;
  
    public MapperFactoryBean() {
    }

    public MapperFactoryBean(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    protected void checkDaoConfig() {
        super.checkDaoConfig();
        Assert.notNull(this.mapperInterface, "Property 'mapperInterface' is required");
        Configuration configuration = this.getSqlSession().getConfiguration();
        if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
            try {
                configuration.addMapper(this.mapperInterface);
            } catch (Exception e) {
                this.logger.error("Error while adding the mapper '" + String.valueOf(this.mapperInterface) + "' to configuration.", e);
                throw new IllegalArgumentException(e);
            } finally {
                ErrorContext.instance().reset();
            }
        }
    }
  // spring容器ApplicationContext.getBean(..)方法,会调用 MapperFactoryBean的getObject()方法获取bean实例 
  // 其中 mapperInterface 就是 MapperFactoryBean对应Mapper接口class 
    public T getObject() throws Exception {
        return (T)this.getSqlSession().getMapper(this.mapperInterface);
    }
  //...
}

// SqlSessionDaoSupport 定义:
public abstract class SqlSessionDaoSupport extends DaoSupport {
    private SqlSessionTemplate sqlSessionTemplate;
		
  //  装配SqlSessionFactory时,创建SqlSessionTemplate并赋值
    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {
            this.sqlSessionTemplate = this.createSqlSessionTemplate(sqlSessionFactory);
        }
    }

    protected SqlSessionTemplate createSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    public final SqlSessionFactory getSqlSessionFactory() {
        return this.sqlSessionTemplate != null ? this.sqlSessionTemplate.getSqlSessionFactory() : null;
    }

    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSessionTemplate = sqlSessionTemplate;
    }

    public SqlSession getSqlSession() {
        return this.sqlSessionTemplate;
    }

    public SqlSessionTemplate getSqlSessionTemplate() {
        return this.sqlSessionTemplate;
    }

    protected void checkDaoConfig() {
        Assert.notNull(this.sqlSessionTemplate, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");
    }
}

【代码解说】

  1. SqlSessionDaoSupport装配SqlSessionFactory时,会创建SqlSessionTemplate并赋值;也就是MapperFactoryBean初始化时会调用setSqlSessionFactory(…)方法注入SqlSessionFactory; 注入前,会调用createSqlSessionTemplate()创建 SqlSessionTemplate并注入


【2】MapperScannerConfigurer-映射器扫描配置器

  1. MapperScannerConfigurer作用:使用MapperScannerConfigurer,扫描特定包,自动成批创建映射器Mapper,而无需单个单个创建业务Mapper,如UserMapper,就可以删除单个配置业务Mapper的bean定义xml代码 ;

【2.1】MapperScannerConfigurer的bean定义配置

文件 spring-mybatis-beans-mapperscan.xml 中有关于MapperScannerConfigurer的配置,如下。

<!-- 使用MapperScannerConfigurer,扫描特定包,自动成批创建映射器Mapper -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.tom.srccode.deep.analysis.chapter9" />
    <property name="processPropertyPlaceHolders" value="true" /> 
</bean>

注意:processPropertyPlaceHolders=true表示开启占位符替换;

配置了 MapperScannerConfigurrer后, 就可以删除UseMapper的配置了。

<!-- userMapper的bean定义代码,可以删除;因为MapperScannerConfigurer可以自动扫描basePackage下的Mapper接口并自动注册 -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <property name="mapperInterface" value="com.tom.srccode.deep.analysis.chapter9.UserMapper" />
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

【2.2】MapperScannerConfigurer的类层次结构

  1. MapperScannerConfigurer类继承结构:
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
 // ...  
  public void afterPropertiesSet() throws Exception {
        Assert.notNull(this.basePackage, "Property 'basePackage' is required");
    }
}

【代码解说】InitializingBean的实现类的afterPropertiesSet方法,没有做任何事情,忽略;

下面,本文主要关注 BeanDefinitionRegistryPostProcessor 对MapperScannerConfigurer的作用;


【2.2.1】BeanDefinitionRegistryPostProcessor-bean定义注册器后置处理器

【BeanDefinitionRegistryPostProcessor】继承结构

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

    default void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
      // do nothing.
    }
}

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

【代码解说】综上, 本文主要关注postProcessBeanDefinitionRegistry,也就是重点关注 MapperScannerConfigurer 的postProcessBeanDefinitionRegistry方法;


【2.2.2】MapperScannerConfigurer 的postProcessBeanDefinitionRegistry方法

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    if (this.processPropertyPlaceHolders) {
        // 占位符的属性处理 
        this.processPropertyPlaceHolders();
    }
    
    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry, this.getEnvironment());
    scanner.setAddToConfig(this.addToConfig);
    scanner.setAnnotationClass(this.annotationClass);
    scanner.setMarkerInterface(this.markerInterface);
    scanner.setExcludeFilters(this.excludeFilters = this.mergeExcludeFilters());
    scanner.setSqlSessionFactory(this.sqlSessionFactory);
    scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
    scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
    scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
    scanner.setResourceLoader(this.applicationContext);
    scanner.setBeanNameGenerator(this.nameGenerator);
    scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
    if (StringUtils.hasText(this.lazyInitialization)) {
        scanner.setLazyInitialization(Boolean.parseBoolean(this.lazyInitialization));
    }

    if (StringUtils.hasText(this.defaultScope)) {
        scanner.setDefaultScope(this.defaultScope);
    }
	  
    // 注册过滤器,定义规则,用于扫描时找出满足规则的bean; 因为scanner是扫描所有bean,需要根据一定规则筛选出Mapper接口的bean
    scanner.registerFilters();
    // 扫描basePackage指定包名下的mapper接口
    scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
}

// 处理属性占位符 
private void processPropertyPlaceHolders() {
       // 获取所有实现了 PropertyResourceConfigurer 的接口的bean的map,其中key为beanName,value为PropertyResourceConfigurer实现类bean
        Map<String, PropertyResourceConfigurer> prcs = this.applicationContext.getBeansOfType(PropertyResourceConfigurer.class, false, false);
        if (!prcs.isEmpty() && this.applicationContext instanceof ConfigurableApplicationContext) {
            BeanDefinition mapperScannerBean = ((ConfigurableApplicationContext)this.applicationContext).getBeanFactory().getBeanDefinition(this.beanName);
            DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
            factory.registerBeanDefinition(this.beanName, mapperScannerBean);

            for(PropertyResourceConfigurer prc : prcs.values()) {
                prc.postProcessBeanFactory(factory);
            }

            PropertyValues values = mapperScannerBean.getPropertyValues();
            this.basePackage = this.getPropertyValue("basePackage", values);
            this.sqlSessionFactoryBeanName = this.getPropertyValue("sqlSessionFactoryBeanName", values);
            this.sqlSessionTemplateBeanName = this.getPropertyValue("sqlSessionTemplateBeanName", values);
            this.lazyInitialization = this.getPropertyValue("lazyInitialization", values);
            this.defaultScope = this.getPropertyValue("defaultScope", values);
            this.rawExcludeFilters = this.getPropertyValueForTypeFilter("rawExcludeFilters", values);
        }

        Optional var10001 = Optional.ofNullable(this.basePackage);
        Environment var10002 = this.getEnvironment();
        Objects.requireNonNull(var10002);
        this.basePackage = (String)var10001.map(var10002::resolvePlaceholders).orElse((Object)null);
        var10001 = Optional.ofNullable(this.sqlSessionFactoryBeanName);
        var10002 = this.getEnvironment();
        Objects.requireNonNull(var10002);
        this.sqlSessionFactoryBeanName = (String)var10001.map(var10002::resolvePlaceholders).orElse((Object)null);
        var10001 = Optional.ofNullable(this.sqlSessionTemplateBeanName);
        var10002 = this.getEnvironment();
        Objects.requireNonNull(var10002);
        this.sqlSessionTemplateBeanName = (String)var10001.map(var10002::resolvePlaceholders).orElse((Object)null);
        var10001 = Optional.ofNullable(this.lazyInitialization);
        var10002 = this.getEnvironment();
        Objects.requireNonNull(var10002);
        this.lazyInitialization = (String)var10001.map(var10002::resolvePlaceholders).orElse((Object)null);
        var10001 = Optional.ofNullable(this.defaultScope);
        var10002 = this.getEnvironment();
        Objects.requireNonNull(var10002);
        this.defaultScope = (String)var10001.map(var10002::resolvePlaceholders).orElse((Object)null);
    }

【代码解说】

  1. this.applicationContext.getBeansOfType(PropertyResourceConfigurer.class, false, false): 获取spring容器中class=PropertyResourceConfigurer.class的所有bean,其中key为beanName, value为bean实例;

  2. postProcessBeanDefinitionRegistry()方法内部最后会调用scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, “,; \t\n”));

    1. 有代码可知,scanner的类型为 ClassPathMapperScanner

【ClassPathMapperScanner#scan()方法】 扫描给定路径的Mapper接口

public int scan(String... basePackages) {
    int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
  // 调用doScan()方法执行实际扫描  
  this.doScan(basePackages);
    if (this.includeAnnotationConfig) {
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }

    return this.registry.getBeanDefinitionCount() - beanCountAtScanStart;
}

调用ClassPathMapperScanner.doScan(basePackages);

注意: ClassPathMapperScanner的父类super是 ClassPathBeanDefinitionScanner

public Set<BeanDefinitionHolder> doScan(String... basePackages) {
  // 调用super父类的doScan方法, 父类是 ClassPathBeanDefinitionScanner
    Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
    if (beanDefinitions.isEmpty()) {
        if (this.printWarnLogIfNotFoundMappers) {
            LOGGER.warn(() -> "No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
        }
    } else {
       // 处理Mapper的bean定义 
        this.processBeanDefinitions(beanDefinitions);
    }

    return beanDefinitions;
}

调用 ClassPathBeanDefinitionScanner#doScan()方法, 接着调用ClassPathMapperScanner#processBeanDefinitions() 方法处理bean定义;

第1步:先分析 doScan()方法,如下:

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet();

    for(String basePackage : basePackages) {
        for(BeanDefinition candidate : this.findCandidateComponents(basePackage)) {
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            if (candidate instanceof AbstractBeanDefinition abstractBeanDefinition) {
                this.postProcessBeanDefinition(abstractBeanDefinition, beanName);
            }

            if (candidate instanceof AnnotatedBeanDefinition annotatedBeanDefinition) {
                AnnotationConfigUtils.processCommonDefinitionAnnotations(annotatedBeanDefinition);
            }

            if (this.checkCandidate(beanName, candidate)) {
               // 创建bean定义持有器
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                beanDefinitions.add(definitionHolder);
                this.registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }

    return beanDefinitions;
}

【代码解说】 doScan()方法的作用: 根据给定pacakge路径扫描到满足规则的Mapper,并创建该Mapper的BeanDefinition;

第2步:调用ClassPathMapperScanner#processBeanDefinitions() 方法处理bean定义;

private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
    BeanDefinitionRegistry registry = this.getRegistry();

    for(BeanDefinitionHolder holder : beanDefinitions) {
        AbstractBeanDefinition definition = (AbstractBeanDefinition)holder.getBeanDefinition();
        boolean scopedProxy = false;
        if (ScopedProxyFactoryBean.class.getName().equals(definition.getBeanClassName())) {
            definition = (AbstractBeanDefinition)Optional.ofNullable(((RootBeanDefinition)definition).getDecoratedDefinition()).map(BeanDefinitionHolder::getBeanDefinition).orElseThrow(() -> new IllegalStateException("The target bean definition of scoped proxy bean not found. Root bean definition[" + String.valueOf(holder) + "]"));
            scopedProxy = true;
        }

        String beanClassName = definition.getBeanClassName();
        LOGGER.debug(() -> {
            String var10000 = holder.getBeanName();
            return "Creating MapperFactoryBean with name '" + var10000 + "' and '" + beanClassName + "' mapperInterface";
        });
        definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);

        try {
            // 为bean定义新增属性,如 factoryBeanObjectType=beanClass,beanClass就是Mapper接口class;
          // 新增属性mapperInterface, 值同样也是 mapperInterface 
            Class<?> beanClass = Resources.classForName(beanClassName);
            definition.setAttribute("factoryBeanObjectType", beanClass);
            definition.getPropertyValues().add("mapperInterface", beanClass);
        } catch (ClassNotFoundException var10) {
        }
        
      // ********** 这行代码非常重要,设置BeanClass为 mapperFactoryBeanClass,其值为MapperFactoryBean的clazz 
        definition.setBeanClass(this.mapperFactoryBeanClass);
      
        definition.getPropertyValues().add("addToConfig", this.addToConfig);
        boolean explicitFactoryUsed = false;
        if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
            definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
            explicitFactoryUsed = true;
        } else if (this.sqlSessionFactory != null) {
            definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
            explicitFactoryUsed = true;
        }

        if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
            if (explicitFactoryUsed) {
                LOGGER.warn(() -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
            }

            definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
            explicitFactoryUsed = true;
        } else if (this.sqlSessionTemplate != null) {
            if (explicitFactoryUsed) {
                LOGGER.warn(() -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
            }
				   新增属性 sqlSessionTemplate 
            definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
            explicitFactoryUsed = true;
        }

        if (!explicitFactoryUsed) {
            LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
            definition.setAutowireMode(2);
        }

        definition.setLazyInit(this.lazyInitialization);
        if (!scopedProxy) {
            if ("singleton".equals(definition.getScope()) && this.defaultScope != null) {
                definition.setScope(this.defaultScope);
            }

            if (!definition.isSingleton()) {
                BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(holder, registry, true);
                if (registry.containsBeanDefinition(proxyHolder.getBeanName())) {
                    registry.removeBeanDefinition(proxyHolder.getBeanName());
                }

                registry.registerBeanDefinition(proxyHolder.getBeanName(), proxyHolder.getBeanDefinition());
            }
        }
    }

}

【代码解说】 definition.setBeanClass(this.mapperFactoryBeanClass): 这行代码非常重要,this.mapperFactoryBeanClass值为 MapperFactoryBean


【3】AbstractApplicationContext-invokeBeanFactoryPostProcessors()作用及源码分析

  1. AbstractApplicationContext-invokeBeanFactoryPostProcessors()方法作用: spring启动时,解析BeanDefinition,并将其注册到BeanFactory; 然后执行AbstractApplicationContext-invokeBeanFactoryPostProcessors(),该方法会执行所有 BeanDefinitionRegistryPostProcessor实现类bean的postProcessBeanDefinitionRegistry方法,然后再执行所有BeanFactoryPostProcessor实现类bean的postProcessBeanFactory()方法;
    1. 调用 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry方法;
      1. 作用: 在 BeanDefinition 加载完成后、BeanFactoryPostProcessor 执行之前,可以动态注册、删除或修改 BeanDefinition;如 MapperScannerConfigurer根据basePackage解析Mapper并注册Mapper定义到spring容器; 【可以注册,删除,修改BeanDefinition】
      2. BeanDefinitionRegistryPostProcessor-BeanDefinition注册后置处理器的实现类举例
        1. MapperScannerConfigurer: 负责扫描Mapper并注册Mapper bean,key为Mapper接口clazz,value为MapperFactoryBean;
        2. ConfigurationClassPostProcessor:解析@Configuration注解,扫描 @Bean, @Import, @ComponentScan,@PropertySource注释;
    2. 调用 BeanFactoryPostProcessor#postProcessBeanFactory() 方法;
      1. BeanFactoryPostProcessor-Bean工厂后置处理器的作用: 在 Spring 实例化任何 Bean 之前,修改 Bean 的定义(BeanDefinition),而不是修改 Bean 对象本身;【仅可以删除BeanDefinition】
        1. 执行BeanFactoryPostProcessor#postProcessBeanFactory() 方法修改BeanDefinition属性;属性包括:beanName,beanClass,scope,lazyInit,constructor,propertyValues,initMethod,destroyMethod;
      2. BeanFactoryPostProcessor-bean工厂后置处理器的实现类举例
        1. PropertySourcesPlaceholderConfigurer: 属性源占位符配置器;

【3.1】背景

  1. 由 MapperScannerConfigurer 的postProcessBeanDefinitionRegistry()方法的调用入口, 扩展出 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry方法调用入口,如下:
  2. AbstractApplicationContext#refresh() -> this.invokeBeanFactoryPostProcessors(beanFactory) -> PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(…) 方法, 如下:
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());
    if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

}

接着,本文分析PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors())源码;

【3.2】调用Bean工厂后置处理器

  1. PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(): 调用Bean工厂后置处理器

【PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()】这段代码,看似复杂,但实际逻辑简单,本文下面进行分析;

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    Set<String> processedBeans = new HashSet();
  // beanFactory 实现类 BeanDefinitionRegistry,所以为true
    if (beanFactory instanceof BeanDefinitionRegistry registry) {
        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList();
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList();
				
      	// 传入的postProcessor为null,所以不进入
        for(BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor registryProcessor) {
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                registryProcessors.add(registryProcessor);
            } else {
                regularPostProcessors.add(postProcessor);
            }
        }

        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList();
      	// 获取 BeanDefinitionRegistryPostProcessor 类型的bean名称 
        String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

        for(String ppName : postProcessorNames) {
            // 【步骤1】筛选出 实现 PriorityOrdered 接口的BeanDefinitionRegistryPostProcessor类型的bean
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                currentRegistryProcessors.add((BeanDefinitionRegistryPostProcessor)beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(ppName);
            }
        }
				
        // 对实现了 PriorityOrdered接口的 BeanDefinitionRegistryPostProcessor进行优先调用
        // 因为 PriorityOrdered ,顾名思义就是 优先级排序接口,它比Ordered的实现类要优先调用
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
        // 调用【步骤1】筛选出的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
        currentRegistryProcessors.clear();
        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

        for(String ppName : postProcessorNames) {
          	// 【步骤2】筛选出 实现 Ordered 接口的 BeanDefinitionRegistryPostProcessor 类型的bean
            if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                currentRegistryProcessors.add((BeanDefinitionRegistryPostProcessor)beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(ppName);
            }
        }
				
      	// 对 Ordered接口的 BeanDefinitionRegistryPostProcessor进行排序并调用  
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
        // 调用【步骤2】筛选出的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
        currentRegistryProcessors.clear();
        boolean reiterate = true;

        while(reiterate) {
            reiterate = false;
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

            for(String ppName : postProcessorNames) {
              // 【步骤3】筛选出 没有实现 Ordered 接口且没有实现PriorityOrdered接口的 BeanDefinitionRegistryPostProcessor 类型的bean
                if (!processedBeans.contains(ppName)) {
                    currentRegistryProcessors.add((BeanDefinitionRegistryPostProcessor)beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                    reiterate = true;
                }
            }
            // 排序
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
             // 调用【步骤3】筛选出的 BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
            currentRegistryProcessors.clear();
        }

        invokeBeanFactoryPostProcessors((Collection)registryProcessors, beanFactory);
        invokeBeanFactoryPostProcessors((Collection)regularPostProcessors, beanFactory);
    } else {
        invokeBeanFactoryPostProcessors((Collection)beanFactoryPostProcessors, beanFactory);
    }
  
  //  我是分割线:至此,BeanDefinitionRegistryPostProcessor所有bean的postProcessBeanDefinitionRegistry方法调用完成
		
  
  // 找出 类型为 BeanFactoryPostProcessor 的 beanName数组 
    String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
    List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList();
    List<String> orderedPostProcessorNames = new ArrayList();
    List<String> nonOrderedPostProcessorNames = new ArrayList();

    for(String ppName : postProcessorNames) {
        if (!processedBeans.contains(ppName)) {
          // 【步骤4】筛选实现 PriorityOrdered接口的 BeanFactoryPostProcessor
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                priorityOrderedPostProcessors.add((BeanFactoryPostProcessor)beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
            } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
               // 【步骤5】筛选实现 Ordered接口的 BeanFactoryPostProcessor
                orderedPostProcessorNames.add(ppName);
            } else {
               // 【步骤6】筛选没有实现 PriorityOrdered且没有实现 Ordered接口的 BeanFactoryPostProcessor
                nonOrderedPostProcessorNames.add(ppName);
            }
        }
    }
    // 排序 
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
  	// 调用【步骤4】筛选出的 BeanFactoryPostProcessor 的 postProcessBeanFactory 方法
    invokeBeanFactoryPostProcessors((Collection)priorityOrderedPostProcessors, beanFactory);
    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList(orderedPostProcessorNames.size());

    for(String postProcessorName : orderedPostProcessorNames) {
        orderedPostProcessors.add((BeanFactoryPostProcessor)beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }

    sortPostProcessors(orderedPostProcessors, beanFactory);
  	// 调用【步骤5】筛选出的 BeanFactoryPostProcessor 的 postProcessBeanFactory 方法
    invokeBeanFactoryPostProcessors((Collection)orderedPostProcessors, beanFactory);
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList(nonOrderedPostProcessorNames.size());

    for(String postProcessorName : nonOrderedPostProcessorNames) {
        nonOrderedPostProcessors.add((BeanFactoryPostProcessor)beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
		
    // 调用【步骤6】筛选出的 BeanFactoryPostProcessor 的 postProcessBeanFactory 方法
    invokeBeanFactoryPostProcessors((Collection)nonOrderedPostProcessors, beanFactory);
    beanFactory.clearMetadataCache();
}

【补充】关于 PriorityOrdered接口, Ordered接口定义:

// 优先有序接口
public interface PriorityOrdered extends Ordered {
}

// 有序接口
public interface Ordered {
    int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
    int LOWEST_PRECEDENCE = Integer.MAX_VALUE;

    int getOrder();
}


【4】总结

【4.1】(非常重要)总结:调用BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry()方法与BeanFactoryPostProcessor 的 postProcessBeanFactory()方法总结

  1. 调用入口: PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()

    1. 该方法有两个作用:
      1. 调用 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry()方法;
      2. 调用 BeanFactoryPostProcessor 的 postProcessBeanFactory()方法;
  2. 调用 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry()方法的步骤:

    1. 【步骤1】筛选出 实现 PriorityOrdered 接口的BeanDefinitionRegistryPostProcessor类型的bean,并根据排序策略排序,按照顺序执行其postProcessBeanDefinitionRegistry方法;
    2. 【步骤2】筛选出 实现 Ordered 接口的 BeanDefinitionRegistryPostProcessor 类型的bean, 并根据排序策略排序,按照顺序执行其postProcessBeanDefinitionRegistry方法;
    3. 【步骤3】筛选出 没有实现 PriorityOrdered接口且没有实现 Ordered 接口 的 BeanDefinitionRegistryPostProcessor 类型的bean, 并根据排序策略排序,按照顺序执行其postProcessBeanDefinitionRegistry方法;
  3. 调用 BeanFactoryPostProcessor 的 postProcessBeanFactory()方法的步骤:

    1. 【步骤4】筛选 实现 PriorityOrdered接口 的 BeanFactoryPostProcessor类型的bean,并根据排序策略排序,按照顺序执行其 postProcessBeanFactory()方法;
    2. 【步骤5】筛选 实现 Ordered接口 的 BeanFactoryPostProcessor类型的bean,并根据排序策略排序,按照顺序执行其 postProcessBeanFactory()方法;
    3. 【步骤6】筛选 没有实现 PriorityOrdered接口且没有实现 Ordered接口 的 BeanFactoryPostProcessor类型的bean,并根据排序策略排序,按照顺序执行其 postProcessBeanFactory()方法;

【注意】上述过程的调用,都是在bean实例化前,因为

  1. BeanDefinitionRegistryPostProcessor的作用:在 BeanDefinition 加载完成后、BeanFactoryPostProcessor 执行之前,可以动态注册、删除或修改 BeanDefinition,是在bean实例化前;
  2. BeanFactoryPostProcessor的作用:在 Spring 实例化任何 Bean 之前,修改 Bean 的定义(BeanDefinition),而不是修改 Bean 对象本身

【4.2】BeanDefinitionRegistryPostProcessor与BeanFactoryPostProcessor使用总结

  1. 调用入口: spring启动时,解析BeanDefinition,并将其注册到BeanFactory; 然后执行AbstractApplicationContext-invokeBeanFactoryPostProcessors(),该方法会执行所有 BeanDefinitionRegistryPostProcessor实现类bean的postProcessBeanDefinitionRegistry方法,然后再执行所有BeanFactoryPostProcessor实现类bean的postProcessBeanFactory()方法;
    1. 也就是说:BeanDefinitionRegistryPostProcessor比BeanFactoryPostProcessor执行得早 ;
  2. 使用场景:
    1. BeanDefinitionRegistryPostProcessor使用场景:在 BeanDefinition 加载完成后、BeanFactoryPostProcessor 执行之前,可以动态注册、删除或修改 BeanDefinition。它是 Spring 向容器动态添加 Bean 的核心扩展点;它是 Spring 底层大量功能(如 @Configuration、@Value、占位符解析等)的基础;
    2. BeanFactoryPostProcessor使用场景: 在所有BeanDefinitionRegistryPostProcessor实现类bean#postProcessBeanDefinitionRegistry方法执行后,在 Spring 实例化任何 Bean 之前,修改 Bean 定义(BeanDefinition),而不是修改 Bean 对象本身
  3. 两者区别与联系:
    1. 区别:BeanDefinitionRegistryPostProcessor可以注册,修改,修改BeanDefinition; 而BeanFactoryPostProcessor只能修改BeanDefinition;
    2. 联系: BeanDefinitionRegistryPostProcessor 继承自 BeanFactoryPostProcessor,可以重写后者的postProcessBeanFactory方法;
      1. 所以BeanDefinitionRegistryPostProcessor会被执行两次:
      2. 第1次,执行其postProcessBeanDefinitionRegistry方法;【可以动态注册,删除,修改BeanDefinition】
      3. 第2次,执行其postProcessBeanFactory方法; 【仅可以动态修改BeanDefinition属性,属性包括:beanName,beanClass,scope,lazyInit,constructor,propertyValues,initMethod,destroyMethod】
  4. BeanDefinitionRegistryPostProcessor与BeanFactoryPostProcessor的执行顺序:

读取配置(XML、注解)


解析 BeanDefinition


注册 BeanDefinition 到 BeanDefinitionRegistry


★★★★★ BeanDefinitionRegistryPostProcessor #postProcessBeanDefinitionRegistry()方法★★★★★


★★★★★ BeanFactoryPostProcessor #postProcessBeanFactory()方法 ★★★★★


实例化 Bean


BeanPostProcessor


初始化 Bean


【4.2.1】BeanDefinitionRegistryPostProcessor使用场景(注册,删除,修改BeanDefinition)

public class TomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        // 注册bean定义,以便spring后续对该bean实例化与初始化
        BeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(DiyUserServiceManualRegistry.class).getBeanDefinition();
        registry.registerBeanDefinition("diyUserServiceManualRegistry", bd);

        // 删除BeanDefinition
        registry.removeBeanDefinition("diyUserServiceManualRegistry2");
        // 修改BeanDefinition属性,属性包括:beanName,beanClass,scope,lazyInit,constructor,propertyValues,initMethod,destroyMethod
        bd.setPrimary(true);
    }
}

bean.xml文件定义TomBeanDefinitionRegistryPostProcessor ;

<!-- 自定义BeanDefinition注册后置处理器 -->
<bean class="com.tom.srccode.deep.analysis.chapter9.beanfactorypostprocessor.TomBeanDefinitionRegistryPostProcessor" />

【测试案例】

@Test
public void test5() {
    ApplicationContext context = new ClassPathXmlApplicationContext("a_src_deep_analysis/chapter9/spring-mybatis-beans-mapperscan.xml");
    DiyUserServiceManualRegistry bean = context.getBean(DiyUserServiceManualRegistry.class);
    log.info(" DiyUserServiceManualRegistry = {}", bean);
}

【打印结果】

com.tom.srccode.deep.analysis.chapter9.beanfactorypostprocessor.DiyUserServiceManualRegistry - DiyUserServiceManualRegistry: 构造器被调用
com.tom.srccode.deep.analysis.chapter9.SpringMybatisIntegrateUnitTest -  DiyUserServiceManualRegistry = com.tom.srccode.deep.analysis.chapter9.beanfactorypostprocessor.DiyUserServiceManualRegistry@6865c751


【4.2.2】BeanFactoryPostProcessor使用场景(修改BeanDefinition)

参见: PropertySourcesPlaceholderConfigurer-属性源占位符配置器

public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerSupport implements EnvironmentAware {
  //...
}

public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfigurer implements BeanNameAware, BeanFactoryAware {
  //...
}

// 显然,由传递性可知,PropertySourcesPlaceholderConfigurer是BeanFactoryPostProcessor实现类 
public abstract class PropertyResourceConfigurer extends PropertiesLoaderSupport implements BeanFactoryPostProcessor, PriorityOrdered {
  //...
}
Logo

CANN开发者社区旨在汇聚广大开发者,围绕CANN架构重构、算子开发、部署应用优化等核心方向,展开深度交流与思想碰撞,携手共同促进CANN开放生态突破!

更多推荐