MyBatis @Mapper注解注册为Spring Bean的核心原理

ps:如果这篇帖子对于还在找工作和找实习的你有所帮助,可以关注我,给本贴点赞、评论、收藏并订阅专栏;同时不要吝啬您的花花

首先明确核心结论:@Mapper并非Spring原生Bean注解,无法被Spring默认扫描机制识别,它能注册为Bean的核心,是MyBatis-Spring整合包扩展了Spring的Bean注册体系,通过自定义扫描、Bean定义重构、动态代理生成,将Mapper接口转化为可被Spring IOC容器管理的单例Bean。

一、前置依赖:注册生效的基础

@Mapper注解的Bean注册能力,完全依赖mybatis-spring整合依赖(SpringBoot场景下为mybatis-spring-boot-starter),脱离该依赖,Spring无法识别@Mapper注解,Mapper接口也不会被加载为Bean。

该整合包封装了全套Mapper注册逻辑,弥补了Spring原生注解无法适配MyBatis接口式编程的缺陷,是整个注册流程的载体。

二、核心组件:支撑注册的关键类

整个注册流程围绕三大核心组件运转,各司其职完成从注解识别到Bean注册的全链路:

  • MapperScannerConfigurer:实现Spring的BeanDefinitionRegistryPostProcessor扩展接口,是Mapper扫描的入口,负责启动自定义扫描逻辑。
  • ClassPathMapperScanner:自定义类路径扫描器,重写Spring默认扫描规则,专门识别标记@Mapper注解的接口,过滤普通类、实现类等非目标对象。
  • MapperFactoryBean:实现Spring FactoryBean接口,是Mapper代理对象的生产工厂,也是Bean注册的核心载体。
  • MapperScannerRegistrar:实现ImportBeanDefinitionRegistrar接口,配合@MapperScan注解,完成扫描器的注册与初始化(SpringBoot自动配置会间接触发该逻辑)。

三、全流程拆解:@Mapper如何变成Spring Bean

1. 扫描触发:定位@Mapper注解接口

Spring容器启动时,通过两种方式触发Mapper扫描:一是启动类添加@MapperScan注解指定扫描包;二是SpringBoot自动配置(mybatis-spring-boot-starter)自动扫描项目包下的@Mapper接口。

扫描器ClassPathMapperScanner会遍历指定包路径,筛选出仅包含@Mapper注解的接口,排除普通类、抽象类、实现类,确保只处理MyBatis Mapper接口。

2. Bean定义重构:替换为MapperFactoryBean

这是@Mapper能注册为Bean的核心环节:Spring默认只会将类注册为Bean,无法直接注册接口,因此整合包会对扫描到的Mapper接口做Bean定义重构。

扫描器会为每个@Mapper接口创建BeanDefinition(Spring Bean的元数据),并将BeanDefinition的beanClass属性从Mapper接口替换为MapperFactoryBean,同时把原Mapper接口的全类名作为构造参数传入MapperFactoryBean。

此时Spring容器感知到的不再是普通接口,而是一个可生产Bean的FactoryBean,满足Spring Bean注册的基础条件。

3. 动态代理生成:创建Mapper接口实现类

Spring容器实例化Bean时,会调用MapperFactoryBean的getObject()方法,该方法是FactoryBean的核心方法,负责生成真正的Mapper代理对象:

  • 依托MyBatis的SqlSessionTemplate(Spring托管的SqlSession),获取Mapper代理工厂MapperProxyFactory;
  • 通过JDK动态代理,为Mapper接口生成匿名实现类,绑定接口方法与XML/注解中的SQL语句;
  • 代理对象会拦截接口方法调用,自动完成SQL解析、参数绑定、结果映射等MyBatis核心逻辑。

4. 容器注册:纳入Spring IOC管理

生成的动态代理对象会以单例模式注册到Spring容器,Bean名称默认是Mapper接口名首字母小写(如UserMapper→userMapper),与普通Spring Bean完全一致。

后续业务层可通过@Autowired、@Resource等注解直接注入Mapper Bean,正常调用接口方法,无需关心代理和注册细节。

四、Spring扩展点:突破原生限制的关键

@Mapper能绕过Spring原生扫描规则,核心是利用了Spring提供的两大扩展接口,实现自定义Bean注册:

  • BeanDefinitionRegistryPostProcessor:允许在Spring Bean定义加载完成后,动态新增、修改BeanDefinition,MapperScannerConfigurer通过该接口插入自定义扫描逻辑;
  • ImportBeanDefinitionRegistrar:允许通过注解导入第三方Bean注册逻辑,@MapperScan通过该接口注册Mapper扫描器,实现灵活的包扫描配置。

五、补充说明:@Mapper与@MapperScan的关系

@Mapper是标记注解,用于标识某个接口是MyBatis Mapper;@MapperScan是扫描注解,用于指定Mapper接口的扫描路径。SpringBoot场景下,若引入starter且Mapper接口在启动类同级/子包,可省略@MapperScan,自动配置会直接扫描@Mapper接口;非Boot场景必须搭配@MapperScan使用,否则扫描逻辑无法触发。

六、核心总结

@Mapper注解本身无注册Bean能力,真正实现注册的是MyBatis-Spring整合包的自定义机制:扫描@Mapper接口→重构Bean定义为MapperFactoryBean→生成JDK动态代理→注册为Spring单例Bean。整个流程既适配了MyBatis接口式编程的特性,又完全遵循Spring IOC容器的管理规范。

ps:如果这篇帖子对于还在找工作和找实习的你有所帮助,可以关注我,给本贴点赞、评论、收藏并订阅专栏;同时不要吝啬您的花花

Spring 文章被收录于专栏

本专栏聚焦Spring全生态体系,从IoC/AOP核心原理入手,覆盖Spring Boot自动配置、事务管理、Web开发等实战内容。拆解循环依赖、动态代理等高频面试难点,助力开发者从入门到精通,打通单体到微服务的技术链路,解决企业级开发痛点,提升架构设计与问题排查能力,成为Java后端进阶的必备技术专栏。

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务