Mapper 源码分析

mybatis通常的用法如下:

定义接口

public interface UserMapper {
    User selectUser(int id);
}

定义xml文件

<mapper namespace="com.example.UserMapper">
    <select id="selectUser" parameterType="int" resultType="User">
        SELECT * FROM users WHERE id = #{id}
    </select>
</mapper>

执行

class Test {
    public static void main(String[] args) {
        try (SqlSession session = sqlSessionFactory.openSession()) {
            UserMapper mapper = session.getMapper(UserMapper.class);
            User user = mapper.selectUser(1);
            System.out.println(user);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

mapper使用JDK动态代理生成的代理对象,集成Spring就是通过MapperScan注解扫描指定目录的mapper文件集合,生成代理对象,并且注册为Bean

这里的UserMapper实现是代理MapperProxy。

集成到Spring的时候,需要将项目中定义的所有Mapper转换为Proxy,并且注册为Bean。

mybatis通过MapperScan注解扫描mapper接口,注册为bean的时候的是FactoryBean模式将实现类转换为MapperProxy代理,

对于mybatis-plus来说,通过注册SqlSessionTemplate这个bean,将MapperProxy代理替换成自己的MybatisMapperProxy代理

mybatis-plus集成mybatis的时候,使用MybatisMapperProxy

主要的调用链路

@MapperScan("com.soyokra.sprival.dao.*.mapper")
=> MapperScan @Import({MapperScannerRegistrar.class}):注册MapperScannerRegistrar
=> MapperScannerRegistrar.registerBeanDefinitions:设置MapperScannerConfigurer属性的basePackage为com.soyokra.sprival.dao.*.mapper
=> MapperScannerConfigurer.postProcessBeanDefinitionRegistry
=> ClassPathMapperScanner.processBeanDefinitions:扫描basePackage生成BeanDefinition,并且设置BeanClass为MapperFactoryBean
=> Mapper注册为Bean的时候,通过MapperFactoryBean的getObject()转到了SqlSessionTemplate.getMapper()
=> SqlSessionTemplate调用的是 getConfiguration().getMapper(type, this)。这个SqlSessionTemplate是mybatis-plus注册的Bean,Configuration是mybatis-plus的
=> 最终通过mybatis-plus的MybatisMapperRegistry执行到MybatisMapperProxyFactory,生成了MybatisMapperProxy代理类作为Mapper接口的实现

MapperScan

@MapperScan("com.soyokra.sprival.dao..mapper")设置了需要扫描的包basePackages为"com.soyokra.sprival.dao..mapper"

@MapperScan("com.soyokra.sprival.dao.*.mapper")
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {
    String[] value() default {};
}

MapperScannerRegistrar

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
    void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs,
                                 BeanDefinitionRegistry registry, String beanName) {

        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);

        builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));

        registry.registerBeanDefinition(beanName, builder.getBeanDefinition());

    }
}

MapperScannerConfigurer

public class MapperScannerConfigurer 
        implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
        scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
    }
}

ClassPathMapperScanner

对basePackages下的文件进行扫描注册成BeanDefinition,并且设置了BeanDefinition的属性beanClass为MapperFactoryBean

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
    @Override
    public Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
        processBeanDefinitions(beanDefinitions);
        return beanDefinitions;
    }

    private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
        AbstractBeanDefinition definition;
        BeanDefinitionRegistry registry = getRegistry();
        for (BeanDefinitionHolder holder : beanDefinitions) {
            definition = (AbstractBeanDefinition) holder.getBeanDefinition();
            definition.setBeanClass(this.mapperFactoryBeanClass); // this.mapperFactoryBeanClass => MapperFactoryBean
        }
    }
}

MapperFactoryBean

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
    @Override
    public T getObject() throws Exception {
        return getSqlSession().getMapper(this.mapperInterface);
    }

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

public abstract class SqlSessionDaoSupport extends DaoSupport {
    public SqlSession getSqlSession() {
        return this.sqlSessionTemplate;
    }
}

SqlSessionTemplate

SqlSessionTemplate调用的是 getConfiguration().getMapper(type, this)。由于这个SqlSessionTemplate是mybatis-plus注册的Bean,Configuration实际上是mybatis-plus
实现的,最终最终通过mybatis-plus的MybatisMapperRegistry执行到MybatisMapperProxyFactory,生成了MybatisMapperProxy代理类作为Mapper接口的实现

public class SqlSessionTemplate implements SqlSession, DisposableBean {
    @Override
    public <T> T getMapper(Class<T> type) {
        return getConfiguration().getMapper(type, this);
    }

    @Override
    public Configuration getConfiguration() {
        return this.sqlSessionFactory.getConfiguration();
    }
}

MybatisPlusAutoConfiguration

mybatis-plus注册SqlSessionFactory 和 SqlSessionTemplate bean

public class MybatisPlusAutoConfiguration implements InitializingBean {

    @Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        return factory.getObject();
    }

    @Bean
    @ConditionalOnMissingBean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        ExecutorType executorType = this.properties.getExecutorType();
        return executorType != null ? new SqlSessionTemplate(sqlSessionFactory, executorType) : new SqlSessionTemplate(sqlSessionFactory);
    }
}