【MyBatis源码分析】Spring与MyBatis整合深入解析

news2025/1/4 19:03:18

🎮 作者主页:点击
🎁 完整专栏和代码:点击
🏡 博客主页:点击

文章目录

  • 概述
  • SqlSessionFactoryBean详解
      • 配置
      • 原理
  • MapperScannerConfigurer 源码分析
      • 介绍
      • postProcessBeanDefinitionRegistry 方法

概述

MyBatis-Spring 的原理通过整合 Spring 的事务管理和 MyBatis 的数据操作功能,简化了数据库操作的流程。核心在于 SqlSessionFactoryBean 和 SqlSessionTemplate,前者负责初始化 SqlSessionFactory,后者提供线程安全的 SqlSession 代理,自动处理数据库操作;同时,Spring 的 @Transactional 注解与 DataSourceTransactionManager 实现了事务的自动管理,使得 MyBatis 的数据库操作和 Spring 事务管理无缝连接,避免了手动管理事务和 SQL 会话。通过 MapperScannerConfigurer 自动扫描 Mapper 接口,实现了与 Spring 容器的深度集成。

SqlSessionFactoryBean详解

SqlSessionFactoryBean 是 MyBatis-Spring 整合中的核心组件之一,主要作用是创建和配置 SqlSessionFactory。它通过配置 DataSource、mybatis-config.xml、Mapper 文件等信息,将 MyBatis 环境初始化为一个 Spring 管理的 Bean,方便与 Spring 容器的其他组件(如事务管理、Mapper 扫描等)进行集成。通过使用 SqlSessionFactoryBean,Spring 能够自动管理 MyBatis 配置,简化开发流程。

配置

spring-config.xml

 <bean id="sqlSessionFactory" class="cn.xxxx.mybatis.spring.SqlSessionFactoryBean">
        <property name="resource" value="mybatis-config-datasource.xml"/>
    </bean>

原理

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean {

    private String resource;
    private SqlSessionFactory sqlSessionFactory;

    @Override
    public void afterPropertiesSet() throws Exception {
        try (Reader reader = Resources.getResourceAsReader(resource)) {
            this.sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public SqlSessionFactory getObject() throws Exception {
        return sqlSessionFactory;
    }

    @Override
    public Class<?> getObjectType() {
        return SqlSessionFactory.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    public void setResource(String resource) {
        this.resource = resource;
    }

}

FactoryBean 是 Spring 提供的一个接口,它的作用是用来生产某个类型的 Bean。SqlSessionFactoryBean 实现了这个接口,从而允许 Spring 容器通过 FactoryBean 机制创建 SqlSessionFactory 实例。
getObject():该方法返回 SqlSessionFactory 实例,Spring 容器会将该实例注入到依赖该 SqlSessionFactory的 Bean 中。
getObjectType():返回 SqlSessionFactory 的类型,Spring 用来确认返回的对象类型。
isSingleton():表明该 Bean 是否是单例的。由于 SqlSessionFactory 应当是整个应用共享的资源,isSingleton() 返回 true,表示每次请求返回同一个实例。

InitializingBean 是 Spring 提供的一个接口,其 afterPropertiesSet() 方法会在 Spring 完成依赖注入后调用。SqlSessionFactoryBean 实现了这个接口,确保在 Spring 容器初始化完成后,它会创建 SqlSessionFactory。它通过 Resources.getResourceAsReader(resource) 方法加载 MyBatis 的配置文件(如 mybatis-config.xml),并使用 SqlSessionFactoryBuilder 来构建 SqlSessionFactory 实例。

这里,Resources.getResourceAsReader(resource) 会加载指定路径的 MyBatis 配置文件,SqlSessionFactoryBuilder 用来构建 SqlSessionFactory。

在 Spring 容器中,SqlSessionFactoryBean 只会初始化一次 SqlSessionFactory,并且该实例会被 Spring 容器作为单例(Singleton)Bean 管理。SqlSessionFactory 是线程安全的,可以在多个线程之间共享,因此可以在整个应用程序中复用。所有的 SqlSession 都是通过 SqlSessionFactory 来生成的,但 SqlSession 不是单例的,它是按需创建的。每次需要执行数据库操作时,MyBatis 会通过 SqlSessionFactory 创建一个新的 SqlSession 实例。

MapperScannerConfigurer 源码分析

介绍

MapperScannerConfigurer 是 MyBatis-Spring 框架中的一个非常重要的组件,它帮助开发者自动扫描并注册 MyBatis 的 Mapper 接口。通过 MapperScannerConfigurer,我们不需要手动配置每一个 Mapper 接口的 Bean,而是通过配置扫描路径,自动为每个接口创建代理实例,并将其注册为 Spring 的 Bean。
【1】自动扫描指定包路径下的 MyBatis Mapper 接口。
【2】将扫描到的接口通过动态代理生成 Mapper 实例。
【3】将生成的 Mapper 实例注入到 Spring 容器中。

MapperScannerConfigurer 是一个实现了 BeanDefinitionRegistryPostProcessor、InitializingBean、ApplicationContextAware 和 BeanNameAware 接口的类。通过这些接口,MapperScannerConfigurer 可以在 Spring 容器启动时进行自定义的 Bean 注册和初始化操作。

postProcessBeanDefinitionRegistry 方法

这是 BeanDefinitionRegistryPostProcessor 接口中的核心方法,它会在 Spring 容器启动过程中被调用,用于注册新的 Bean 定义。
下面代码非mybatis源码,参考原理代码

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        try {
            // classpath*:com/**/dao/**/*.class
            String packageSearchPath = "classpath*:" + basePackage.replace('.', '/') + "/**/*.class";
            ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
            for (Resource resource : resources) {
                MetadataReader metadataReader = new SimpleMetadataReader(resource, ClassUtils.getDefaultClassLoader());

                ScannedGenericBeanDefinition beanDefinition = new ScannedGenericBeanDefinition(metadataReader);
                String beanName = Introspector.decapitalize(ClassUtils.getShortName(beanDefinition.getBeanClassName()));

                beanDefinition.setResource(resource);
                beanDefinition.setSource(resource);
                beanDefinition.setScope("singleton");
                beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition.getBeanClassName());
                beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(sqlSessionFactory);
                beanDefinition.setBeanClass(MapperFactoryBean.class);

                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(beanDefinition, beanName);
                registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

【1】扫描指定包(basePackage)下的所有 .class 文件。
【2】读取每个 .class 文件的元数据(MetadataReader)。MetadataReader 用于读取每个 Resource(即 .class 文件)的元数据,SimpleMetadataReader 是它的实现。它会从 Resource 中加载类的基本信息,如类名、接口、注解等。
【3】根据读取到的元数据创建一个 ScannedGenericBeanDefinition。ScannedGenericBeanDefinition 是一个特殊的 BeanDefinition 实现,它通过 MetadataReader 提供的元数据来构建一个新的 Bean 定义。此时,beanDefinition 包含了类的相关信息,如类名、构造方法、作用域等。
【4】配置该 BeanDefinition 的属性,包括 Bean 名称、构造器参数等。
【5】将 BeanDefinition 注册到 Spring 的 BeanDefinitionRegistry 中。通过 BeanDefinitionRegistry 注册 beanDefinition。BeanDefinitionHolder 用来包装 BeanDefinition 和 Bean 名称,registry.registerBeanDefinition(beanName, …) 则是将其实际注册到 Spring 容器中,确保 Spring 能识别并管理这个 Bean。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2269511.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

macos 支持外接高分辩率显示器开源控制软件

macos 支持外接高分辩率显示器开源控制软件 软件&#xff08;app应用&#xff09;名&#xff1a;BetterDisplay 官方地址&#xff1a; https://github.com/waydabber/BetterDisplay

JVM实战—7.如何模拟GC场景并阅读GC日志

大纲 1.动手模拟出频繁Young GC的场景 2.JVM的Young GC日志应该怎么看 3.代码模拟动态年龄判定规则进入老年代 4.代码模拟S区放不下部分进入老年代 5.JVM的Full GC日志应该怎么看 6.问题汇总 1.动手模拟出频繁Young GC的场景 (1)程序的JVM参数示范 (2)如何打印出JVM GC…

javaEE-文件操作和IO-文件

目录 一.什么是文件 1.文件就是硬盘(磁盘)上的文件。 2.计算机中存储数据的设备&#xff1a; 3.硬盘的物理特征 4.树型结构组织和⽬录 5.文件路径 文件路径有两种表示方式&#xff1a; 6.文件的分类 二、java中文件系统的操作 1.File类中的属性&#xff1a; 2.构造方…

使用 Docker 搭建 Hadoop 集群

1.1. 启用 WSL 与虚拟机平台 1.1.1. 启用功能 启用 WSL并使用 Moba 连接-CSDN博客 1.2 安装 Docker Desktop 最新版本链接&#xff1a;Docker Desktop: The #1 Containerization Tool for Developers | Docker 指定版本链接&#xff1a;Docker Desktop release notes | Do…

数据结构(系列)

在Python中&#xff0c;列表&#xff08;list&#xff09;是一种基本的数据结构&#xff0c;它可以存储一系列的元素。列表是可变的&#xff0c;即可以对其进行增删改查操作。 栈&#xff08;Stack&#xff09;是一种具有特定限制的线性数据结构&#xff0c;在栈中&#xff0c…

【Linux】HTTP cookie与session

在登录B站时&#xff0c;有登录和未登录两种状态&#xff0c; 问题&#xff1a;B站是如何认识我这个登录用户的&#xff1f;问题&#xff1a;HTTP是无状态、无连接的&#xff0c;怎么能够记住我&#xff1f; HTTP协议是无状态、无连接的。比如客户端&#xff08;浏览器&#…

Java - 日志体系_Simple Logging Facade for Java (SLF4J)日志门面_SLF4J集成logback 及 原理分析

文章目录 Pre官网集成步骤POM依赖使用第一步&#xff1a;编写 Logback 的配置文件第二步&#xff1a;在代码中使用 SLF4J 原理分析1. 获取对应的 ILoggerFactory2. 根据 ILoggerFactory 获取 Logger 实例3. 日志记录过程 小结 Pre Java - 日志体系_Apache Commons Logging&…

5.系统学习-PyTorch与多层感知机

PyTorch与多层感知机 前言PyTroch 简介张量&#xff08;Tensor&#xff09;张量创建张量的类型数据类型和 dtype 对应表张量的维度变换&#xff1a;张量的常用操作矩阵或张量计算 Dataset and DataLoaderPyTorch下逻辑回归与反向传播数据表格 DNN&#xff08;全连结网络&#x…

ubuntu 如何使用vrf

在Ubuntu或其他Linux系统中&#xff0c;您使用ip命令和sysctl命令配置的网络和内核参数通常是临时的&#xff0c;这意味着在系统重启后这些配置会丢失。为了将这些配置持久化&#xff0c;您需要采取一些额外的步骤。 对于ip命令配置的网络接口和路由&#xff0c;您可以将这些配…

Unity Shader TexelSize的意义

TexelSize在制作玻璃折射效果时会用到。 // Get the normal in tangent space fixed3 bump UnpackNormal(tex2D(_BumpMap, i.uv.zw)); // Compute the offset in tangent space float2 offset bump.xy * _Distortion * _RefractionTex_TexelSize.xy; i.scrPos.xy offset * i…

嵌入式硬件杂谈(七)IGBT MOS管 三极管应用场景与区别

引言&#xff1a;在现代嵌入式硬件设计中&#xff0c;开关元件作为电路中的重要组成部分&#xff0c;起着至关重要的作用。三种主要的开关元件——IGBT&#xff08;绝缘栅双极型晶体管&#xff09;、MOSFET&#xff08;金属氧化物半导体场效应晶体管&#xff09;和三极管&#…

【亲测有效】k8s分布式集群安装部署

1.实验环境准备 准备三台centos7虚拟机&#xff0c;用来部署k8s集群&#xff1a; master&#xff08;hadoop1&#xff0c;192.168.229.111&#xff09;配置&#xff1a; 操作系统&#xff1a;centos7.3以及更高版本都可以配置&#xff1a;4核cpu&#xff0c;4G内存&#xff…

【SQL server】教材数据库(5)

使用教材数据库&#xff08;1&#xff09;中的数据表完成以下题目&#xff1a; 1 根据上面基本表的信息定义视图显示每个学生姓名、应缴书费 2 观察基本表数据变化时&#xff0c;视图中数据的变化。 3利用视图&#xff0c;查询交费最高的学生。 1、create view 学生应缴费视…

去除el-tabs 下面的灰色横线,并修改每一项的左右间距,和字体颜色

HTML <el-tabs v-model"activeName" class"demo-tabs" tab-click"handleClick"><el-tab-pane label"全部" :name"null"></el-tab-pane><el-tab-pane label"问答陪练" name"general-t…

纯血鸿蒙ArkUI的网格布局详解

网格布局概要 网格布局是由行和列分割的单元格组成&#xff0c;通过指定项目所在的单元格做出各种各样的布局。网格布局具有较强的页面均分能力&#xff0c;子组件占比控制能力&#xff0c;是一种重要的自适应布局组件&#xff0c;其使用场景有九宫格图片展示、日历、计算器等…

LeRobot(1)

Train python lerobot/scripts/train.py \ policyact \ envaloha \ env.taskAlohaInsertion-v0 \ dataset_repo_idlerobot/aloha_sim_insertion_human \ load_data一直报错&#xff0c;忘记截图了&#xff0c;反正是ssh报错&#xff0c;下不下来&#xff0c;网…

【C++】B2085 第 n 小的质数

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目描述题目内容输入格式输出格式题目示例 &#x1f4af;原始做法分析解法源码解析1. 步骤分析2. 问题分析3. 性能问题 &#x1f4af;老师提供的优化解法优化代码每部分解…

Node.js详细安装教程

1.下载 [名称]&#xff1a;Node.js [大小]&#xff1a;26.4 MB [语言]&#xff1a;简体中文 [安装环境]&#xff1a;Win7/Win8/Win10 [Node.js15.11.0下载链接]&#xff1a; 通过网盘分享的文件&#xff1a;Node.js 链接: https://pan.baidu.com/s/12WlNlWlX-1ppdhz…

IDEA 搭建 SpringBoot 项目之配置 Maven

目录 1?配置 Maven 1.1?打开 settings.xml 文件1.2?配置本地仓库路径1.3?配置中央仓库路径1.4?配置 JDK 版本1.5?重新下载项目依赖 2?配置 idea 2.1?在启动页打开设置2.2?配置 Java Compiler2.3?配置 File Encodings2.4?配置 Maven2.5?配置 Auto Import2.6?配置 C…

SpringCloud 系列教程:微服务的未来(三)IService接口的业务实现

本文将介绍 IService 接口的基本业务操作、复杂业务操作、Lambda 方法的使用以及批量增加操作&#xff0c;帮助开发者深入了解如何高效地利用 MyBatis-Plus 提供的功能进行数据库操作。无论是简单的单表查询&#xff0c;还是复杂的多表联动&#xff0c;甚至是大数据量的批量操作…