在 Spring Boot 中整合 MyBatis 是一个常见的场景,它通过自动配置和约定优于配置的方式简化了 MyBatis 的集成。


一、整体流程

  1. 引入依赖(如 mybatis-spring-boot-starter
  2. Spring Boot 自动加载 MyBatisAutoConfiguration
  3. 创建数据源 DataSource
  4. 构建 SqlSessionFactory
  5. 注册 MapperScannerConfigurer 扫描 Mapper 接口
  6. 注入 SqlSessionTemplateMapper 到业务层使用

二、依赖

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>

三、核心类与方法

1. MyBatisAutoConfiguration

这是 MyBatis 在 Spring Boot 中的自动配置类,负责初始化关键组件。

类路径:
org.mybatis.spring.boot.autoconfigure.MyBatisAutoConfiguration
核心方法:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MyBatisProperties.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MyBatisAutoConfiguration {

    private final MyBatisProperties properties;

    public MyBatisAutoConfiguration(MyBatisProperties properties) {
        this.properties = properties;
    }

    // 创建 SqlSessionFactoryBean
    @Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setVfs(SpringBootVFS.class); // 使用 Spring Boot 的 VFS 加载资源
        factory.setConfigLocation(this.properties.resolveConfigLocation()); // mybatis.config-location
        factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage()); // type-handlers-package
        factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage()); // type-aliases-package
        return factory.getObject(); // 构建 SqlSessionFactory
    }

    // 创建事务管理器
    @Bean
    @ConditionalOnMissingBean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    // 注册 Mapper 扫描器
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer configurer = new MapperScannerConfigurer();
        configurer.setBasePackage(this.properties.getMapperLocations()); // 配置 Mapper 接口包路径
        return configurer;
    }
}

2. SqlSessionFactoryBean

用于创建 SqlSessionFactory,是 MyBatis 和 Spring 集成的关键类。

类路径:
org.mybatis.spring.SqlSessionFactoryBean
核心方法:
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ResourcesLoadedEvent> {

    private Resource configLocation; // mybatis-config.xml 文件位置
    private String[] mapperLocations; // Mapper XML 文件路径
    private DataSource dataSource; // 数据源
    private Class<? extends VFS> vfs; // 虚拟文件系统
    private String typeHandlersPackage; // 类型处理器包
    private String typeAliasesPackage; // 别名包

    // 初始化方法,在 afterPropertiesSet 中完成配置
    @Override
    public void afterPropertiesSet() throws Exception {
        notNull(dataSource, "Property 'dataSource' is required");
        notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");

        org.apache.ibatis.session.Configuration configuration;

        if (this.configuration != null) {
            configuration = this.configuration;
        } else if (this.configLocation != null) {
            configuration = new ConfigurationBuilder().parse(this.configLocation); // 解析 mybatis-config.xml
        } else {
            configuration = new org.apache.ibatis.session.Configuration();
        }

        // 设置类型别名
        if (StringUtils.hasText(typeAliasesPackage)) {
            configuration.getTypeAliasRegistry().registerAliases(typeAliasesPackage);
        }

        // 设置类型处理器
        if (StringUtils.hasText(typeHandlersPackage)) {
            configuration.getTypeHandlerRegistry().register(typeHandlersPackage);
        }

        // 加载 Mapper XML 文件
        if (mapperLocations != null) {
            for (Resource mapperLocation : mapperLocations) {
                if (mapperLocation.exists()) {
                    configuration.addMappers(mapperLocation); // 添加 Mapper 映射
                }
            }
        }

        // 创建 SqlSessionFactory
        this.sqlSessionFactory = buildSqlSessionFactory(configuration);
    }

    // 构建 SqlSessionFactory
    protected SqlSessionFactory buildSqlSessionFactory(org.apache.ibatis.session.Configuration configuration) {
        return sqlSessionFactoryBuilder.build(configuration);
    }

    // 返回工厂创建的对象
    @Override
    public SqlSessionFactory getObject() throws Exception {
        return getSqlSessionFactory();
    }
}

3. MapperScannerConfigurer

扫描 Mapper 接口并注册为 Spring Bean。

类路径:
org.mybatis.spring.mapper.MapperScannerConfigurer
核心方法:
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, ResourceLoaderAware {

    private String basePackage; // Mapper 接口所在的包

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        scanner.setAnnotationClass(Mapper.class); // 指定 @Mapper 注解
        scanner.setMarkerInterface(Mapper.class); // 指定标记接口
        scanner.registerFilters(); // 注册过滤器
        scanner.doScan(basePackage); // 执行扫描
    }

    // 设置基础包路径
    public void setBasePackage(String basePackage) {
        this.basePackage = basePackage;
    }
}

4. ClassPathMapperScanner

继承自 ClassPathBeanDefinitionScanner,用于扫描 Mapper 接口。

类路径:
org.mybatis.spring.mapper.ClassPathMapperScanner
核心方法:
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {

    public ClassPathMapperScanner(BeanDefinitionRegistry registry) {
        super(registry, false); // 不使用默认的 Component 注解过滤器
    }

    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);

        for (BeanDefinitionHolder holder : beanDefinitions) {
            GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();

            // 设置 MapperFactoryBean 作为 Bean 的工厂类
            definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
            definition.setBeanClassName(MapperFactoryBean.class.getName());

            // 设置是否需要懒加载
            definition.setLazyInit(lazyInitialization);
        }

        return beanDefinitions;
    }
}

5. MapperFactoryBean

将每个 Mapper 接口包装为 Spring 管理的 Bean。

类路径:
org.mybatis.spring.mapper.MapperFactoryBean
核心方法:
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {

    private Class<T> mapperInterface; // Mapper 接口类型

    @Override
    public T getObject() throws Exception {
        return getSqlSession().getMapper(this.mapperInterface); // 获取 Mapper 实例
    }

    @Override
    public Class<T> getObjectType() {
        return this.mapperInterface;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

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

6. SqlSessionTemplate

线程安全的 SqlSession,用于执行 SQL 操作。

类路径:
org.mybatis.spring.SqlSessionTemplate
核心方法:
public class SqlSessionTemplate implements SqlSession, DisposableBean {

    private final SqlSessionFactory sqlSessionFactory; // 工厂
    private final ExecutorType executorType; // 执行器类型
    private final SqlSession sqlSessionProxy; // 代理对象

    public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) {
        this.sqlSessionFactory = sqlSessionFactory;
        this.executorType = executorType;
        this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
            SqlSession.class.getClassLoader(),
            new Class[]{SqlSession.class},
            new SqlSessionInterceptor()); // 动态代理
    }

    // 获取 Mapper 接口的实例
    @Override
    public <T> T getMapper(Class<T> type) {
        return getConfiguration().getMapper(type, this);
    }

    // 内部拦截器处理事务等逻辑
    private class SqlSessionInterceptor implements InvocationHandler {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            final SqlSession sqlSession = getSqlSession(sqlSessionFactory, executorType);
            try {
                Object result = method.invoke(sqlSession, args); // 执行真实方法
                if (!isSqlSessionTransactional(sqlSession, sqlSessionFactory)) {
                    sqlSession.commit(true); // 提交事务
                }
                return result;
            } finally {
                closeSqlSession(sqlSession, sqlSessionFactory);
            }
        }
    }
}

四、总结

类名 作用
MyBatisAutoConfiguration 自动配置类,整合 MyBatis
SqlSessionFactoryBean 创建 MyBatis 的 SqlSessionFactory
MapperScannerConfigurer 注册 Mapper 接口扫描器
ClassPathMapperScanner 实际执行 Mapper 接口扫描
MapperFactoryBean 将 Mapper 接口封装为 Spring Bean
SqlSessionTemplate 线程安全的 SqlSession,用于执行 SQL

五、流程图

启动应用
│
├─ 引入 mybatis-spring-boot-starter
│
├─ Spring Boot 加载自动配置
│   └─ 加载 MyBatisAutoConfiguration
│       ├─ 创建 SqlSessionFactory
│       │   └─ 使用 SqlSessionFactoryBean 构建
│       ├─ 创建事务管理器
│       └─ 注册 MapperScannerConfigurer
│           └─ 扫描 Mapper 接口 -> MapperFactoryBean -> 注册为 Bean
│
└─ 使用时注入 Mapper 接口
    └─ Spring 从容器中获取 MapperFactoryBean.getObject()
        └─ 获取 SqlSessionTemplate.getMapper()
            └─ MyBatis 创建动态代理对象执行 SQL

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐