MyBatis的MapperFactoryBean详解
1. 基本概念
MapperFactoryBean 是MyBatis与Spring框架集成的核心组件,它实现了Spring的FactoryBean接口,负责将MyBatis的Mapper接口转换为可被Spring容器管理的Bean。当我们在Spring中直接注入Mapper接口时,实际上注入的是MapperFactoryBean创建的Mapper接口的动态代理实现。
2. 工作原理
MapperFactoryBean的核心工作原理可以概括为以下几点:
- 实现FactoryBean接口 :通过
getObject()
方法返回Mapper接口的代理实现 - 继承SqlSessionDaoSupport:获取SqlSession实例,用于执行SQL操作
- 动态代理机制:使用JDK动态代理为Mapper接口创建实现类
- SQL执行封装:将Mapper接口方法调用转换为对应的SQL执行
关键代码流程
MapperFactoryBean在初始化过程中,会:
- 设置SqlSessionFactory,构建SqlSessionTemplate
- 检查Mapper接口配置
- 通过SqlSession的getMapper方法创建接口的代理实现
java
// SqlSessionDaoSupport中的核心代码
bublic void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (!this.externalSqlSession) {
this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
}
}
// MapperFactoryBean继承自SqlSessionDaoSupport,重写getObject方法
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
3. 配置方式
XML配置方式
最传统的MapperFactoryBean配置如下:
xml
<!-- 配置单个Mapper接口 -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.example.mapper.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
批量注册方式
当Mapper接口较多时,可以使用MapperScannerConfigurer进行批量注册:
xml
<!-- 批量扫描Mapper接口 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.example.mapper" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
Spring Boot配置方式
在Spring Boot中,通常使用注解方式简化配置:
java
@Configuration
@MapperScan("com.example.mapper")
public class MyBatisConfig {
// 配置相关Bean...
}
4. MapperFactoryBean与SqlSessionTemplate的关系
MapperFactoryBean继承自SqlSessionDaoSupport,而SqlSessionDaoSupport中使用SqlSessionTemplate作为SqlSession的实现。SqlSessionTemplate是线程安全的,它内部使用SqlSessionInterceptor代理模式,保证每个方法调用都使用正确的SqlSession实例。
java
// SqlSessionTemplate内部的代理实现
private class SqlSessionInterceptor implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取或创建SqlSession
final SqlSession sqlSession = getSqlSession(...);
try {
// 调用目标方法
Object result = method.invoke(sqlSession, args);
// 处理事务...
return result;
} finally {
// 正确关闭SqlSession
}
}
}
5. 核心参数说明
MapperFactoryBean主要有两个核心参数:
- mapperInterface:指定要代理的Mapper接口
- sqlSessionFactory:指定使用的SqlSessionFactory实例
其他可选参数包括:
- addToConfig:是否将Mapper接口添加到MyBatis配置中(默认true)
- sqlSessionTemplate:可以直接设置SqlSessionTemplate而非SqlSessionFactory
6. 优势与应用场景
主要优势
- 简化开发:无需手动编写Mapper接口的实现类
- Spring集成:无缝集成Spring的依赖注入和事务管理
- 线程安全:通过SqlSessionTemplate确保线程安全
- 灵活配置:支持单接口配置和批量扫描
应用场景
- 所有使用MyBatis与Spring集成的项目
- 需要将MyBatis Mapper接口作为Spring Bean管理的场景
- 需要利用Spring的事务管理功能执行MyBatis操作的场景
7. 与MapperScannerConfigurer的对比
特性 | MapperFactoryBean | MapperScannerConfigurer |
---|---|---|
配置方式 | 单个接口配置 | 批量扫描配置 |
使用复杂度 | 配置较多(每个接口都需要单独配置) | 配置简单(一次性配置整个包) |
适用场景 | 少量Mapper接口 | 大量Mapper接口 |
灵活性 | 更高(可针对每个Mapper单独配置) | 较低(统一配置) |
8. 实际应用示例
完整的MyBatis与Spring集成配置
xml
<!-- 1. 配置数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<!-- 2. 配置SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath:mapper/*.xml" />
<property name="typeAliasesPackage" value="com.example.model" />
</bean>
<!-- 3. 方式一:单独配置MapperFactoryBean -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.example.mapper.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<!-- 或者方式二:批量扫描配置 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.example.mapper" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<!-- 4. 配置Service,注入Mapper -->
<bean id="userService" class="com.example.service.UserServiceImpl">
<property name="userMapper" ref="userMapper" />
</bean>
9. 总结
MapperFactoryBean是MyBatis与Spring集成的关键组件,它巧妙地利用了Spring的FactoryBean机制,使MyBatis的Mapper接口能够作为Spring Bean被管理和注入。在实际开发中,特别是使用XML配置的项目中,MapperFactoryBean是连接MyBatis和Spring的重要桥梁。而在Spring Boot项目中,虽然@MapperScan注解简化了配置,但底层仍然依赖于MapperFactoryBean的核心机制。