Mybatis-Spring重要组件介绍
一、四个核心组件
1、SqlSessionTemplate
对应Mybatis的SqlSession,通过SqlSessionFactory类得到。
2、MapperFactoryBean
将Mapper代理对象作为Spring Bean管理,通过getObject()可以得到Mapper代理对象。
3、SqlSessionFactoryBean
通过IOC来创建SqlSessionFactory对
4、MapperScannerConfigurer
自动化注册Mapper接口
二、SqlSessionTemplate
角色:SqlSession在Spring框架下的替代品
核心作用:
替代原生 SqlSession,实现与 Spring 事务管理的无缝集成
线程安全:可在多个 DAO 间共享(原生 SqlSession非线程安全)
自动参与Spring事务(通过 TransactionTemplate)
关键特性:
public class SqlSessionTemplate implements SqlSession {private final SqlSessionFactory sqlSessionFactory;private final ExecutorType executorType;private final SqlSessionInterceptor interceptor; // 关键:拦截器处理事务
}
执行流程:
当调用 selectOne()等方法时,通过拦截器检查当前是否存在 Spring 事务
若存在事务,则复用事务内的 SqlSession(通过 TransactionSynchronizationManager绑定)
若无事务,则创建新会话并在操作后关闭(避免资源泄漏)
三、MapperFactoryBean
角色:Mapper接口的Spring Bean工厂,通过MapperFactoryBean的getObject得到的不是MapperFactory,而是MapperProxy,也就是Mapper的代理对象,因为getSqlSession().getMapper(mapperInterface)这个方法,底层就是通过Mybatis的getMapper()方法来得到代理对象,所以返回的内容和原生的是一样的类型MapperProxy。
核心作用:
为每个 Mapper 接口生成 Spring Bean
将MyBatis的Mapper代理对象纳入Spring 容器管理
public class MapperFactoryBean<T> extends SqlSessionDaoSupport {private Class<T> mapperInterface;@Overrideprotected void checkDaoConfig() {// 注册 Mapper 接口到Configuration,为什么要添加到Configuration?getSqlSession().getConfiguration().addMapper(mapperInterface);}@Overridepublic T getObject() {// 获取Mapper的代理对象,通过SqlSessionTemplate获取Mapper代理对象。return getSqlSession().getMapper(mapperInterface);}
}
四、MapperScannerConfigurer
角色:自动扫描并注册Mapper接口
核心作用:
1、自动检测指定包下的Mapper接口
2、为每个接口创建MapperFactoryBean的BeanDefinition
其实说白了:MapperScannerConfigurer是MyBatis-Spring整合包中,为了简化Spring环境下,Mapper接口的批量注册而设计的,是为了批量注册。
配置示例:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.example.mapper"/>
</bean>
效果等价于:
<!-- 自动生成类似配置 -->
<bean id="userMapper" class="MapperFactoryBean"><property name="mapperInterface" value="com.example.mapper.UserMapper"/>
</bean>
问题:原生 MyBatis中如何注册Mapper接口?
在原生的MyBatis 中,注册 Mapper 接口主要有两种方式:
1、编程式逐个注册:通过 Configuration对象的 addMapper()方法。
2、包扫描注册:通过 Configuration对象的 addMappers()方法,指定一个包名,MyBatis 会扫描该包下的所有接口并注册。
- 编程式逐个注册示例:
SqlSessionFactory sqlSessionFactory = ...; // 获取 SqlSessionFactory
Configuration configuration = sqlSessionFactory.getConfiguration();
configuration.addMapper(UserMapper.class);
configuration.addMapper(OrderMapper.class);
// ... 其他 Mapper 接口
- 包扫描注册示例:
//这行代码会扫描 com.example.mapper包下的所有接口,
//并为它们创建动态代理工厂(MapperProxyFactory)并注册到 Configuration中。
configuration.addMappers("com.example.mapper");
对比MapperScannerConfigurer 在MyBatis-Spring 中,MapperScannerConfigurer的作用是自动扫描指定的包路径,并为每个Mapper接口创建对应的MapperFactoryBean(Spring Bean),从而将Mapper接口注册为Spring容器中的Bean。
同时,在背后也会调用MyBatis的addMapper或类似机制将接口注册到MyBatis的Configuration中。
什么意思:
就是原生的Mapper是通过configuration.addMapper(UserMapper.class)添加进去的。
Mybatis-Spring呢 ?
是通过MapperScannerConfigurer对configuration.addMapper(UserMapper.class)做了一层包装,底层就是使用configuration.addMapper(UserMapper.class)。
问题:为什么要把Mapper接口注册到Configuration中?
1、MyBatis的核心思想是通过接口方法直接映射到 SQL 语句
2、注册过程(addMapper)会解析接口方法上的注解(如 @Select)或对应的 XML 映射文件,将方法签名与 SQL 语句绑定。
五、SqlSessionFactoryBean
角色:Spring 环境下的 SqlSessionFactory工厂
核心作用:
替代原生 SqlSessionFactoryBuilder,通过 Spring IOC 创建 SqlSessionFactory
可以这么理解SqlSessionFactoryBuilder是Mybatis定义的东西,在原生Mybatis中SqlSessionFactoryBuilder是为了得到SqlSessionFactory。
而在Spring中,SqlSessionFactoryBean就是为了得到SqlSessionFactory
支持 Spring 配置方式加载 MyBatis 配置(如 DataSource注入)
六、流程总结
(1) 数据源配置(Spring Boot自动配置)
spring:datasource:url: jdbc:mysql://localhost:3306/testusername: rootpassword: 123456
(2) MyBatis配置
@Configuration
public class MyBatisConfig {@Beanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(dataSource);// 设置其他配置,如mapperLocations等return factoryBean.getObject();}@Beanpublic SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {return new SqlSessionTemplate(sqlSessionFactory);}
}
(3) Mapper扫描
@Configuration
@MapperScan("com.example.mapper")
public class MapperScannerConfig {// 使用@MapperScan注解自动扫描
}
步骤1: 创建SqlSessionFactory
触发时机: Spring容器初始化SqlSessionFactoryBean时
关键步骤:
1、SqlSessionFactoryBean实现InitializingBean接口,在afterPropertiesSet()方法中构建SqlSessionFactory
2、解析配置(如mybatis-config.xml,如果指定)
3、注册类型处理器、插件等
4、解析mapperLocations指定的XML文件(如果有)
5、最终返回DefaultSqlSessionFactory实例
步骤2: 扫描Mapper接口
触发时机: @MapperScan注解由MapperScannerRegistrar处理
关键步骤:
1、创建ClassPathMapperScanner扫描指定包
2、过滤出接口(Mapper必须是接口)
3、为每个Mapper接口创建BeanDefinition,并设置BeanClass为MapperFactoryBean
4、设置构造参数为Mapper接口类型
5、设置依赖的SqlSessionFactory或SqlSessionTemplate
步骤3: 初始化MapperFactoryBean
触发时机: Spring容器首次访问Mapper Bean时(懒加载或立即初始化)
关键步骤:
MapperFactoryBean继承SqlSessionDaoSupport,需要设置SqlSessionFactory或SqlSessionTemplate
在checkDaoConfig()方法中注册Mapper接口到Configuration
在getObject()方法中调用SqlSession.getMapper()
步骤4: 创建Mapper代理对象
触发时机: MapperFactoryBean.getObject()被调用时
关键步骤:
1、通过SqlSessionTemplate.getMapper()获取代理
2、SqlSessionTemplate内部通过Configuration.getMapper()获取
3、Configuration.getMapper()从MapperRegistry获取MapperProxyFactory
4、MapperProxyFactory创建MapperProxy动态代理
调用流程示例
当调用UserMapper方法时:
@Service
public class UserService {@Autowiredprivate UserMapper userMapper; // 实际是MapperProxy代理对象public User getUserById(int id) {return userMapper.selectById(id); // 触发代理逻辑}
}
代理执行链:
1、MapperProxy.invoke()
2、创建或获取MapperMethod(封装SqlCommand和MethodSignature)
3、根据SQL类型调用SqlSessionTemplate的方法
例如:sqlSession.selectOne(command.getName(), param)
4、SqlSessionTemplate检查当前线程是否存在事务上下文
5、如果存在,复用已有的SqlSession
6、否则创建新的SqlSession(执行后自动关闭)
7、最终由Executor执行SQL并返回结果