Mapper 接口注入
Mapper 接口注入是 Spring-MyBatis 集成的核心机制,通过动态代理将接口转换为可执行的 SQL 操作。
@MapperScan 注解
@MapperScan 用于自动扫描并注册 Mapper 接口为 Spring Bean。
Java
@Configuration
@MapperScan("com.example.mapper")
public class MyBatisConfig {
}
多包扫描
Java
@MapperScan({"com.example.mapper.user", "com.example.mapper.order"})
指定 SqlSessionFactory
Java
// 多数据源时必须指定
@MapperScan(basePackages = "com.example.mapper",
sqlSessionFactoryRef = "sqlSessionFactory")
| 属性 | 说明 |
|---|---|
| basePackages | 扫描包路径,支持多个 |
| basePackageClasses | 类型安全的包路径(以某个类所在包为准) |
| sqlSessionFactoryRef | 指定 SqlSessionFactory Bean 名称 |
| sqlSessionTemplateRef | 指定 SqlSessionTemplate Bean 名称 |
| annotationClass | 只注册带有该注解的接口 |
| markerInterface | 只注册实现该接口的接口 |
注入 Mapper
Java
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User findById(Long id) {
return userMapper.selectById(id);
}
}
也可使用构造器注入(推荐):
Java
@Service
@RequiredArgsConstructor
public class UserService {
private final UserMapper userMapper;
public User findById(Long id) {
return userMapper.selectById(id);
}
}
接口代理创建原理
Mapper 接口本身没有实现类,通过 JDK 动态代理创建代理对象:
Java
@MapperScan 扫描
|
v
MapperScannerConfigurer
|
v
MapperFactoryBean (每个 Mapper 对应一个)
|
v
getObject() 返回代理对象
|
v
MapperProxyFactory 创建 MapperProxy
|
v
JDK 动态代理 (InvocationHandler)
|
v
方法调用时解析 @Select/@Insert 或 XML 中的 SQL
|
v
通过 SqlSession 执行
Mapper 代理底层使用 JDK 动态代理,因此 Mapper 接口必须是 interface,不能是 class。
MapperFactoryBean
每个 Mapper 接口对应一个 MapperFactoryBean:
Java
// 内部逻辑简化
public class MapperFactoryBean<T> implements FactoryBean<T> {
public T getObject() {
return getSqlSession().getMapper(mapperInterface);
}
public Class<T> getObjectType() {
return mapperInterface;
}
}
注意事项
Java
// 错误:Mapper 不是 Spring Bean,无法注入
public class UserService {
private UserMapper userMapper = new UserMapper(); // 错误
}
// 错误:包路径不匹配,@MapperScan 未扫描到
@MapperScan("com.example.dao") // 实际 Mapper 在 com.example.mapper
public class Config { }
// 正确:确保扫描路径正确
@MapperScan("com.example.mapper")
public class Config { }
Mapper 注入失败通常是 @MapperScan 路径配置错误或未添加该注解。
与 @Mapper 注解的区别
| 方式 | 说明 | 适用场景 |
|---|---|---|
| @MapperScan | 批量扫描注册 | 项目级配置,推荐 |
| @Mapper | 单个接口标记 | 少量 Mapper 或分布式模块 |
text
// 不使用 @MapperScan 时,在每个接口上标记 @Mapper
@Mapper
public interface UserMapper {
User selectById(Long id);
}
要点总结
- @MapperScan 批量扫描 Mapper 接口并注册为 Spring Bean
- 通过 @Autowired 或构造器注入 Mapper 代理对象
- Mapper 代理通过 JDK 动态代理实现,接口必须有 interface
- 多数据源时需通过 sqlSessionFactoryRef 指定对应工厂
- MapperFactoryBean 为每个接口创建代理,getObject() 返回代理实例
- @MapperScan 推荐项目级使用,@Mapper 适合单个接口标记
📝 发现内容有误?点击此处直接编辑