核心概念

  • 作用@MapperScan 是 MyBatis-Plus(继承自 MyBatis-Spring)提供的一个注解,用于自动扫描指定包下的 Mapper 接口,并将它们注册为 Spring 容器中的 Bean。
  • 目的:避免在每一个 Mapper 接口上都添加 @Mapper 注解,实现批量、集中式的接口扫描和注册,简化配置。
  • 替代方案:可以在每个 Mapper 接口上单独使用 @Mapper 注解。@MapperScan 是更优雅、更推荐的批量管理方式。
  • 扫描目标:被 @MapperScan 扫描到的包及其子包中,所有继承了 BaseMapper<T> 或实现了其他 MyBatis Mapper 接口的接口,都会被 Spring 容器识别并创建代理实例。

操作步骤 (非常详细)

前提:已完成 MyBatis-Plus 的依赖引入、数据源配置、核心配置(application.yml)以及 Mapper 接口的创建。

步骤 1: 定位 Spring Boot 启动类 找到你的项目主启动类,通常命名为 Application.java 或类似名称,位于主包(如 com.yourcompany.yourproject)下。

步骤 2: 添加 @MapperScan 注解 在启动类的类定义上方,添加 @MapperScan 注解。

package com.yourcompany.yourproject; // 假设这是主包

import org.mybatis.spring.annotation.MapperScan; // 1. 导入注解
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

// 2. 在 @SpringBootApplication 下方或同级添加 @MapperScan
@SpringBootApplication
@MapperScan("com.yourcompany.yourproject.mapper") // 3. 指定要扫描的 Mapper 接口包路径
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

步骤 3: 确认 Mapper 接口位置 确保你的所有 Mapper 接口(如 UserMapper.java)都位于 @MapperScan 指定的包(com.yourcompany.yourproject.mapper)或其子包内。

步骤 4: (可选) 移除 Mapper 接口上的 @Mapper 注解 如果之前为了测试在 UserMapper 等接口上添加了 @Mapper 注解,现在可以安全地移除了。@MapperScan 已经承担了注册职责。

步骤 5: 运行应用 启动 Spring Boot 应用。如果配置正确,Spring 容器会成功创建所有被扫描到的 Mapper Bean。

常见错误

  1. NoSuchBeanDefinitionException: No qualifying bean of type 'xxxMapper' available:
    • 原因:这是最常见的错误,表示 Spring 容器找不到指定的 Mapper Bean。
    • 排查
      • 路径错误:检查 @MapperScan("...") 中的包路径是否完全正确,与 Mapper 接口的实际包路径一致。注意大小写和拼写。
      • 包层级:确认 Mapper 接口确实在指定包或其子包下。@MapperScan 会递归扫描子包。
      • 注解遗漏:确认启动类上确实添加了 @MapperScan 注解。
      • 组件扫描范围:虽然 @SpringBootApplication 默认扫描启动类所在包及子包,但 @MapperScan 是独立的。确保路径正确即可。
      • 接口未继承 BaseMapper:虽然不是绝对必要(自定义 SQL 也可),但通常 Mapper 接口会继承 BaseMapper<T>。如果只是一个普通接口,MyBatis 可能无法识别为 Mapper。
  2. 扫描到不需要的接口
    • 原因:指定的包路径过宽,包含了非 Mapper 接口。
    • 解决:尽量将所有 Mapper 接口放在一个专门的、清晰的包(如 mapper)下,并精确指定该包路径。避免使用过于宽泛的路径如 com.yourcompany.*
  3. IDE 提示找不到 Bean
    • 原因:有时 IDE 的代码分析可能滞后或配置问题。
    • 解决:清理并重新构建项目 (mvn clean compilegradle clean build),刷新 Maven/Gradle 项目。重启 IDE 通常也能解决。

注意事项

  1. 路径格式:包路径使用点号 . 分隔,如 com.yourcompany.yourproject.mapper。不要使用斜杠 /
  2. 多个包扫描:如果 Mapper 接口分散在多个不同的包中,可以传入一个字符串数组:
    @MapperScan({"com.yourcompany.yourproject.mapper", "com.yourcompany.yourproject.another.mapper"})
    
  3. @Mapper 共存@MapperScan@Mapper 注解可以同时使用。@MapperScan 扫描的包中的接口无需 @Mapper,但其他包的单个接口仍可使用 @Mapper。通常选择一种方式保持一致性。
  4. @MapperScanbasePackages 属性@MapperScan("...")@MapperScan(basePackages = "...") 的简写。basePackages 是其主要属性。
  5. basePackageClasses 属性:另一种指定扫描包的方式,通过指定一个位于目标包下的类来确定包路径,避免硬编码字符串,提高重构安全性。
    @MapperScan(basePackageClasses = {UserMapper.class, OrderMapper.class})
    // 这会扫描 UserMapper 和 OrderMapper 所在的包
    
  6. sqlSessionFactoryRef / sqlSessionTemplateRef:在多数据源配置中,用于指定该扫描的 Mapper 应该绑定到哪个 SqlSessionFactorySqlSessionTemplate Bean 上。单数据源通常不需要。
  7. annotationClass 属性:可以指定只扫描带有特定注解的接口。默认扫描所有接口。一般不需要。
  8. markerInterface 属性:可以指定一个标记接口,只扫描继承了该接口的类。BaseMapper<T> 本身就可以看作一个标记接口,但此属性较少使用。

使用技巧

  1. 使用 basePackageClasses:推荐使用 basePackageClasses 结合一个空的 Marker 接口或某个核心 Mapper 接口,提高代码的可维护性。
    // 定义一个空接口作为标记
    public interface MapperMarker {}
    // 在 UserMapper 上实现它
    public interface UserMapper extends BaseMapper<User>, MapperMarker {}
    // 启动类
    @MapperScan(basePackageClasses = MapperMarker.class)
    
  2. 结合 @ComponentScan 理解@MapperScan 专注于 MyBatis Mapper 接口的扫描注册,而 @ComponentScan (被 @SpringBootApplication 包含) 负责扫描 @Component, @Service, @Repository, @Controller 等注解的类。两者职责不同。
  3. 包结构设计:良好的包结构(如 controller, service, service/impl, mapper, entity)能让 @MapperScan 的配置更加清晰和简洁。

最佳实践与性能优化

  1. 统一使用 @MapperScan:在项目中统一采用 @MapperScan 方式管理所有 Mapper 接口,避免混用 @Mapper 注解,保持代码风格一致。
  2. 明确的包命名:将所有 Mapper 接口放置在专门的、语义清晰的包中,例如 mapperdao。避免将 Mapper 接口分散在业务逻辑包中。
  3. 精确的扫描路径:尽量精确地指定扫描路径,避免扫描不必要的包,减少 Spring 容器的初始化负担(虽然影响通常很小)。
  4. 避免过度扫描:不要使用 com.yourcompany.* 这种过于宽泛的路径,除非有特殊需求。
  5. 与代码生成器配合:如果使用 MyBatis-Plus 代码生成器,可以配置生成的 Mapper 接口放在指定的包下(如 mapper),然后在启动类上用 @MapperScan 扫描这个包,实现自动化集成。
  6. 性能影响@MapperScan 本身发生在应用启动时,其性能开销主要在于类路径扫描和 Bean 定义的注册。对于绝大多数项目,这个开销是微不足道的,可以忽略。优化重点应放在 SQL 查询、索引、缓存等层面。