当前位置: 首页 > ops >正文

MyBatis 中 XML 与 DAO 接口的位置关系及扫描机制详解

MyBatis中XML与DAO接口的位置关系及扫描机制详解

在使用MyBatis进行开发时,很多开发者都会有这样的疑问:为什么XML映射文件和DAO接口(Mapper接口)通常要放在同一个包下?为什么需要进行包扫描?扫描的是DAO包还是XML文件的包?@Mapper和@MapperScan又有什么区别?本文将详细解答这些问题,帮助你理解MyBatis的底层工作逻辑。

一、为什么XML文件和DAO接口要放在同一个包下?

MyBatis中XML映射文件与DAO接口放在同一个包下,主要是基于"约定优于配置"的设计理念,这一约定可以大大简化配置并提高开发效率。

1. 核心匹配规则

MyBatis通过以下两个规则来关联DAO接口和XML映射文件:

  • DAO接口的全限定名(包名+接口名)必须与XML文件的namespace属性值完全一致
  • DAO接口中的方法名必须与XML文件中SQL标签的id属性完全一致

例如,有如下DAO接口:

package com.example.mapper;public interface UserMapper {User selectById(Long id);
}

对应的XML文件应该这样配置:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper"><select id="selectById" resultType="com.example.entity.User">SELECT * FROM user WHERE id = #{id}</select>
</mapper>

2. 路径约定

当XML文件与DAO接口位于同一个包下时,MyBatis会自动根据DAO接口的全限定名去查找对应的XML文件。在Maven项目中,通常的目录结构是:

  • DAO接口:src/main/java/com/example/mapper/UserMapper.java
  • XML文件:src/main/resources/com/example/mapper/UserMapper.xml

这种结构让MyBatis能够通过类路径快速定位到对应的映射文件,而无需额外的配置。

二、为什么需要扫包?扫包的作用是什么?

MyBatis中的"扫包"是连接接口与框架的关键步骤,其核心作用是让框架识别并管理Mapper接口,具体体现在以下三个方面:

  1. 识别Mapper接口
    扫包告诉MyBatis"哪些接口是需要处理的Mapper接口",避免框架误将普通接口当作Mapper处理。

  2. 生成代理对象
    MyBatis不会直接实例化接口(接口无法实例化),而是为扫包范围内的Mapper接口生成代理对象(MapperProxy)。当调用接口方法时,实际是代理对象在执行具体逻辑(解析XML、执行SQL、处理结果集)。

  3. 集成Spring容器
    在Spring环境中,扫包后生成的代理对象会被注册到Spring容器中,使得Service层可以通过@Autowired直接注入并使用Mapper接口,无需手动创建实例。

三、扫描的是DAO包还是XML包?

扫包操作仅扫描DAO接口所在的包,而非XML文件的包。XML文件的加载是通过"接口全限定名+路径约定"间接关联的,具体流程如下:

  1. 框架扫描指定包下的所有DAO接口(如com.example.mapper),识别出哪些是Mapper接口。
  2. 针对每个DAO接口,根据其全限定名(如com.example.mapper.UserMapper),到类路径中查找对应的XML文件。
  3. 查找规则是:在与接口相同的包路径下,寻找与接口同名的XML文件(如UserMapper.xml),并通过XML的namespace属性确认匹配关系。

如果XML文件与DAO接口不在同一包下,需要在MyBatis配置文件中手动指定XML路径(如<mapper resource="xmls/UserMapper.xml"/>),但这种方式会增加配置成本,违背"约定优于配置"的原则。

四、@MapperScan和@Mapper的区别及使用方法

@Mapper@MapperScan都是MyBatis与Spring整合时用于注册Mapper接口的注解,但它们的作用范围和使用场景有所不同。

1. @Mapper注解

  • 作用范围:作用于单个Mapper接口(类级别注解)
  • 功能:标记该接口是MyBatis的Mapper接口,让框架为其生成代理对象
  • 使用场景:接口数量较少时(如1-5个),无需配置包路径

使用示例:

import org.apache.ibatis.annotations.Mapper;@Mapper // 标记当前接口为MyBatis Mapper
public interface UserMapper {User selectById(Long id);
}

启动类无需额外配置:

@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

2. @MapperScan注解

  • 作用范围:作用于包路径,批量扫描多个Mapper接口(通常加在启动类上)
  • 功能:指定需要扫描的包路径,自动注册该路径下所有接口为Mapper接口
  • 使用场景:接口数量较多时(如10个以上),避免重复添加@Mapper注解

使用示例:

// 启动类(通过@MapperScan批量扫描)
@SpringBootApplication
@MapperScan("com.example.mapper") // 扫描com.example.mapper包下的所有接口
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

此时,Mapper接口上无需再加@Mapper注解:

// 无需@Mapper注解,会被@MapperScan扫描到
public interface UserMapper {User selectById(Long id);
}

3. @MapperScan的高级用法

  • 扫描多个包:

    @MapperScan({"com.example.mapper", "com.example.dao"})
    
  • 排除特定接口:

    @MapperScan(basePackages = "com.example.mapper",excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {TestMapper.class} // 排除TestMapper接口)
    )
    

五、如何选择合适的注解?

  • 小型项目(Mapper接口数量少):使用@Mapper更直观,无需关心包路径管理。
  • 中大型项目(Mapper接口多):使用@MapperScan更高效,统一管理扫描路径,减少重复代码。

注意:两者无需同时使用。如果用了@MapperScan,接口上无需再加@Mapper;反之亦然(同时使用不会报错,但属于冗余配置)。

六、总结

  1. XML与DAO接口同包放置,是为了让MyBatis通过"全限定名+路径约定"自动关联两者,减少手动配置。
  2. 扫包的核心作用是让框架识别Mapper接口、生成代理对象并集成到Spring容器,是MyBatis实现接口与SQL绑定的关键步骤。
  3. 扫包扫描的是DAO接口包,XML文件通过接口全限定名间接关联,无需单独扫描。
  4. @Mapper@MapperScan都是为了注册Mapper接口,前者适合少量接口,后者适合批量管理,根据项目规模选择即可。

理解这些机制,能帮助我们规避因路径或配置错误导致的常见问题,更高效地使用MyBatis进行开发。

http://www.xdnf.cn/news/17643.html

相关文章:

  • react与vue的对比,来实现标签内部类似v-for循环,v-if等功能
  • 万字详解C++11列表初始化与移动语义
  • 如何把ubuntu 22.04下安装的mysql 8 的 数据目录迁移到另一个磁盘目录
  • 基于深度学习的苹果品质智能检测算法研究
  • Kubernetes(K8S)中,kubectl describe node与kubectl top pod命令显示POD资源的核心区别
  • .net\c#web、小程序、安卓开发之基于asp.net家用汽车销售管理系统的设计与实现
  • Android Activity 的对话框(Dialog)样式
  • LaTeX(排版系统)Texlive(环境)Vscode(编辑器)环境配置与安装
  • PostgreSQL——索引
  • SpringBoot工程妙用:不启动容器也能享受Fat Jar的便利
  • Redis:是什么、能做什么?
  • 第十三节:后期处理:效果增强
  • MySQL优化常用的几个方法
  • 使用 Python Selenium 和 Requests 实现歌曲网站批量下载实战
  • 100、【OS】【Nuttx】【构建】cmake 配置保存
  • 文心4.5专家负载均衡机制深度解析
  • 【Virtual Globe 渲染技术笔记】4 椭球面上的曲线
  • 线上Linux服务器被植入各种病毒的详细分析、处理、加固流程
  • 机器学习之TF-IDF文本关键词提取
  • EP1S20F484C6 Altera Stratix FPGA
  • imx6ull-驱动开发篇19——linux信号量实验
  • 鸿蒙开发资源导航与学习建议
  • 如何解决Unexpected token ‘<’, “<!doctype “… is not valid JSON 报错问题
  • 微服务ETCD服务注册和发现
  • LeetCode 2787.将一个数字表示成幂的和的方案数:经典01背包
  • Airtable 入门指南:从创建项目到基础数据分析与可视化
  • 渗透测试现已成为 CISO 战略的核心
  • 开疆智能Ethernet转ModbusTCP网关连接PAC3200电能表配置案例
  • 企业高性能web服务器(4)
  • 【运维进阶】Ansible 自动化