资讯详情

资讯详情

Spring与MyBatis整合核心:SqlSessionFactoryBean配置、原理与排坑实战

做后端开发的但凡搞过SSM整合基本都在Spring配置文件里见过SqlSessionFactoryBean这个类。但大部分人对它的理解停留在配一下就能用的层面——XML里贴一段Bean定义注入数据源和Mapper文件路径项目跑通了就再也没管过。可真要出了问题比如Mapper扫描不到、循环依赖、多数据源起冲突、SQL执行时报奇怪的连接错误就抓瞎了。这个类的底层逻辑其实并不复杂但它站在Spring和MyBatis两个框架的接缝上两边的东西都得懂一点才能玩得转。这篇文章我把SqlSessionFactoryBean从头到尾拆开讲它解决了什么问题、每个配置项背后是什么原理、底层构建流程怎么走的、以及真正踩坑时怎么排查。既有源码层面的解释也有实际项目里的经验适合正在学SSM整合的初学者也适合写了很久CRUD但没深究过原理的开发者。1. 先搞清楚SqlSessionFactoryBean到底在解决什么问题1.1 原生MyBatis是怎么构建SqlSessionFactory的在没有Spring的时候我们用MyBatis的方式很直接。先读配置文件再用SqlSessionFactoryBuilder去构建一个SqlSessionFactoryString resource mybatis-config.xml; InputStream inputStream Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory new SqlSessionFactoryBuilder().build(inputStream);这样确实能拿到一个可用的SqlSessionFactory。麻烦在于这个对象的生命周期谁来管连接池要不要跟着应用一起优雅关闭如果多个模块都需要用到同一个SqlSessionFactory是每次new一个还是做成单例这些在纯MyBatis环境里都得自己操心。SqlSessionFactory本身太重要它是所有Mapper代理对象、SqlSession会话、事务管理的源头一旦被随意创建和丢弃代价很高。所以在Spring项目里我们几乎不会再用原生方式手动构建而是把这件事交给Spring容器去管理。1.2 Spring容器里的代工厂机制Spring容器管理Bean的思路是你告诉我需要什么类型的对象、怎么创建它容器来负责实例化、注入依赖、控制作用域和销毁时机。SqlSessionFactoryBean就是Spring和MyBatis之间的那座桥。它实现了Spring的FactoryBeanT接口容器在启动时会调用它的getObject()方法拿到一个SqlSessionFactory类型的对象然后把这个对象作为Bean放进容器里。之后你在任何地方注入SqlSessionFactory拿到的都是同一个实例。这里容易误解的地方在于我们需要的是SqlSessionFactory的实例却配置了一个SqlSessionFactoryBean。这正是FactoryBean的巧妙之处——它本身也是一个Bean但Spring在获取Bean的时候会特殊处理如果Bean实现了FactoryBean接口默认返回的是getObject()的产物而不是FactoryBean自身。打个比方FactoryBean就像代工厂。你找代工厂下单要一台冰箱签合同的对象是代工厂但最终送到你手上的货物是冰箱本身。SqlSessionFactoryBean在Spring容器里承担的就是这个角色Spring管的是工厂这个Bean而业务代码拿到的却是产品——SqlSessionFactory。1.3 它还解决了哪些基础问题除了创建对象SqlSessionFactoryBean至少还在两个层面帮我们兜了底。第一单例保证。它内部有缓存逻辑只有在sqlSessionFactory为空时才执行构建构建一次之后复用。这意味着Spring容器生命周期内只有一个SqlSessionFactory也保证了后续所有Mapper代理、SqlSession都共享同一个配置体系不会出现A事务用一套配置、B事务用另一套配置的割裂情况。第二和Spring的生命周期无缝对齐。SqlSessionFactoryBean实现了InitializingBean接口在Spring完成属性填充后会调用afterPropertiesSet()方法在这个时机完成SqlSessionFactory的构建。应用关闭时容器又会调用DisposableBean的destroy()方法确保数据连接等资源被正确释放。不管应用是正常关闭还是异常终止资源都会被回收不会白白占着连接不放手。2. 核心配置项逐一拆解2.1 每个配置项的用途和潜在坑位先看一段最典型的XML配置这也是我在早期项目里经常见到的写法bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBean property namedataSource refdataSource/ property nameconfigLocation valueclasspath:mybatis/mybatis-config.xml/ property namemapperLocations valueclasspath*:mybatis/mapper/*.xml/ property nametypeAliasesPackage valuecom.example.entity/ /bean这段配置里出现的几个属性网上随便搜都能找到说明但每个属性背后的原理和容易踩的坑我建议还是逐一说清楚。dataSource数据源数据源是所有SQL执行的底层依赖没有它整个SqlSessionFactory就是空中楼阁。SqlSessionFactoryBean拿到dataSource后会把它包装成MyBatis的Environment对象再结合事务工厂一起构成MyBatis自己的运行环境。这里有个关键点dataSource必须是Spring容器里已经初始化好的Bean而且在SqlSessionFactoryBean构建过程中只做引用绑定不会主动去建立物理连接。所以如果数据库地址配错、账号密码不对启动阶段不一定会报错而是等到第一次真正执行SQL时才暴露问题。这是我反复提醒过的事情排查连接问题时别老盯着启动日志先把第一次SQL执行的报错时间点对齐。configLocationMyBatis全局配置文件位置这个属性指向的是MyBatis自己的配置文件里面可以定义settings、typeAliases、typeHandlers、plugins等。SqlSessionFactoryBean在构建时会用XMLConfigBuilder去解析这个文件把里面的配置项逐一应用到Configuration对象上。需要注意如果指定了configLocation文件就必须真实存在并且能被正确解析。我曾经在项目里见过有人把mybatis-config.xml放在了源码目录的某个角落而不是resources目录下执行打包后配置文件压根没进classpath结果启动时报Invalid XML或者资源找不到排查起来非常痛苦。mapperLocationsMapper映射文件路径这个属性用来指定所有*Mapper.xml文件的位置。最常用的写法是classpath*:mybatis/mapper/*.xml注意classpath*:和classpath:的区别。classpath:只会在当前类路径下查找第一个匹配的资源classpath*:则会扫描所有依赖JAR包把所有匹配路径的资源都加载进来。如果你的Mapper XML文件在某个公共模块的JAR里用classpath:很可能扫不到启动时Mapper接口能注入成功但一执行方法就报Invalid bound statement (not found)。typeAliasesPackage别名扫描包这个属性指定一个基础包路径构建时会扫描该包下所有类为它们注册MyBatis别名。默认别名规则很简单不带包名的类名首字母小写。比如com.example.entity.User对应的别名就是user。这样做的意义在于XML里的resultType和parameterType可以写user代替com.example.entity.User写得快也更好读。但也别把包扫得太宽如果有两个类名相同但包路径不同的实体扫描时会发生冲突启动阶段就会报TypeAlias already exists这类错误。把扫描包限定在真正的实体类包内更稳妥。typeHandlersPackage类型处理器扫描包这个属性负责扫描自定义的TypeHandler实现类并注册到MyBatis。实际项目中像枚举与数据库字段之间的转换、JSON字符串与对象的互转经常需要自定义TypeHandler。配置好这个属性后MyBatis会自动发现这些处理器省去在XML配置文件里一条条手写注册的麻烦。plugins拦截器插件MyBatis插件机制可以在执行Executor、StatementHandler、ParameterHandler和ResultSetHandler时做拦截。最典型的分页插件就是通过拦截Executor实现的。在SqlSessionFactoryBean中配置plugins属性时需要注意插件在MyBatis内部的执行顺序和拦截范围同一个插件配置重复或者多个分页插件叠加会让问题变得很隐蔽。我用表格把上面这些配置项整理成速查配置项作用常见坑位dataSource构建MyBatis运行环境的数据源启动期不报错执行SQL时才暴露连接问题configLocation加载MyBatis全局配置XML文件没进classpath、XML格式错误mapperLocations加载Mapper XML映射文件classpath和classpath*选择错误导致扫不到typeAliasesPackage为实体类注册别名扫描包过宽类名冲突typeHandlersPackage扫描并注册TypeHandler自定义处理器没有被扫描到plugins注册MyBatis拦截器插件插件重复、顺序影响拦截结果2.2 那些容易被忽略的隐藏属性除了上面这些主流配置SqlSessionFactoryBean还有几个属性在实际排查问题时会遇到但文档里很少被强调。configurationProperties这是一个Properties对象在解析mybatis-config.xml时会被传递下去。它的作用是给XML配置文件里的${}占位符提供变量值。比如在mybatis-config.xml里写了${driverClass}这种占位符可以通过configurationProperties传入真实值。在Spring环境里我们通常会优先用Spring的属性文件机制去管理这类配置所以这个属性用得不多但你在手动构建场景里碰到占位符解析失败时应该能想到它。configuration如果不想用XML配置文件而是完全通过Java代码构建一个Configuration对象也可以直接把这个对象塞给SqlSessionFactoryBean。设置了configuration之后configLocation会被忽略两者不能同时使用。这种写法在现代Spring Boot项目中越来越常见因为大家更倾向于用JavaConfig而不是XML。transactionFactory这个属性指定使用哪个TransactionFactory。默认情况下SqlSessionFactoryBean会根据dataSource的类型做推断如果项目用的是Spring的DataSourceTransactionManager通常会配一个SpringManagedTransactionFactory让MyBatis的SqlSession会话和Spring事务保持同步。我们项目里曾经遇到过手动设置JdbcTransactionFactory后MyBatis事务和Spring事务互不兼容的问题SqlSession里的操作总是脱离外层事务管理回滚也不生效。这个坑相当隐蔽排查了很久才定位到。environment可以指定构建Environment时使用的环境ID默认值是SqlSessionFactoryBean类中写好的常量。绝大多数场景不需要改但如果你见过生成的Configuration里环境名称和自己预期不一致的情况可以检查一下这个属性有没有被意外修改。3. 底层工作机制SqlSessionFactory是怎么造出来的3.1 getObject与afterPropertiesSet的调用链要理解SqlSessionFactoryBean的完整工作流程直接看源码最直观。它的核心方法有两个getObject()和afterPropertiesSet()。Override public SqlSessionFactory getObject() throws Exception { if (this.sqlSessionFactory null) { afterPropertiesSet(); } return this.sqlSessionFactory; }这里有个很典型的懒加载思路sqlSessionFactory属性能保持null状态只有第一次被外界获取时才会真正触发构建。但注意在Spring容器里SqlSessionFactoryBean作为FactoryBean注册后通常会在应用启动阶段就被触发一次getObject()因为很多地方需要注入SqlSessionFactory或SqlSessionTemplate所以懒也只是相对而言。afterPropertiesSet()是InitializingBean接口定义的Spring在设置完所有属性后会调用它。它的逻辑很简单先检查关键属性是否存在再调用buildSqlSessionFactory()来做真正的构建最后把结果缓存到内部字段上。Override public void afterPropertiesSet() throws Exception { // 数据源和配置对象必须至少有一个 if (this.dataSource null this.configuration null) { throw new IllegalArgumentException(Property dataSource is required); } this.sqlSessionFactory buildSqlSessionFactory(); }从这段代码能看到一个非常重要的约定如果我们提供了完整的Configuration对象可以不配dataSource因为数据源已经被放进Configuration的Environment里了。但如果两个都没给就会直接抛出异常。3.2 buildSqlSessionFactory的完整流程buildSqlSessionFactory()是SqlSessionFactoryBean里最核心也最长的方法。它的工作可以拆分成下面几个阶段我按顺序梳理一下。第一步初始化XMLConfigBuilder。如果设置了configLocation就会读取对应的InputStream创建一个XMLConfigBuilder用于后续解析XMLConfigBuilder xmlConfigBuilder null; if (this.configuration ! null) { // 已有Configuration对象不再解析XML } else if (this.configLocation ! null) { xmlConfigBuilder new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties); }第二步解析全局配置。如果xmlConfigBuilder不为空就调用parse()方法把XML文件里的settings、typeAliases、typeHandlers等配置全部解析进Configuration对象。这一步才是mybatis-config.xml真正发挥作用的时刻。第三步处理dataSource和transactionFactory。如果当前Configuration里没有Environment就会用配置好的数据源和事务工厂新建一个if (this.environment null this.dataSource ! null) { Environment environment new Environment(this.environment null ? SqlSessionFactoryBean : this.environment, this.transactionFactory null ? new SpringManagedTransactionFactory() : this.transactionFactory, this.dataSource); configuration.setEnvironment(environment); }这里有一个值得注意的细节默认的transactionFactory是SpringManagedTransactionFactory。这个选择很关键它保证了MyBatis的SqlSession能够感知到Spring当前是否有活动事务从而正确地把数据库连接纳入Spring事务管理。如果这里换成了别的实现事务行为就可能变得不可控。第四步处理mapperLocations。这是最容易出问题的一步。SqlSessionFactoryBean会用PathMatchingResourcePatternResolver去解析mapperLocations表达式的资源路径循环每一个XML文件用XMLMapperBuilder解析并注册到Configuration。某个XML解析失败比如namespace写错、resultMap引用了不存在的类型都会在这里抛出异常。这里有一个容易忽略的细节mapperLocations里的XML文件可以被多个SqlSessionFactory重复引用。在多数据源场景下如果两个SqlSessionFactoryBean配置了同一个Mapper XML后注册的那个会报already contains value for...的错误。多数据源时必须把不同数据源的Mapper XML按包或目录严格分开。第五步处理typeAliasesPackage、typeHandlersPackage和plugins。这些操作都是围绕Configuration对象做扩展注册。别名扫描使用的是Spring的ClassPathMapperScanner资源扫描能力插件则是直接调用configuration.addInterceptor()逐个添加。第六步构建最终的SqlSessionFactory。这里有个很多人不熟悉的历史包袱。老版本MyBatis里构建方式是这样的this.sqlSessionFactory new SqlSessionFactoryBuilder().build(configuration);但到了较新的版本构造器内部已经能直接基于Configuration对象返回SqlSessionFactory整体逻辑没有大变化只是封装细节更收敛了。不管调用哪种方式核心目的都一样把Configuration对象包装成可以对外提供SqlSession的工厂对象。从整个流程能看出来SqlSessionFactoryBean本质上就是在Spring的Bean生命周期框架里按顺序组织MyBatis的各类初始化步骤。它做的事跟我们手写一大段初始化代码完全等价只是封装成了标准和可复用的形式。3.3 单例缓存与生命周期细节SqlSessionFactoryBean内部用了一个简单的缓存字段保存构建结果private SqlSessionFactory sqlSessionFactory;getObject()每次被调用时都会先检查这个字段非空就直接返回。这保证了SqlSessionFactory在容器中只有一个实例。而且SqlSessionFactoryBean默认实现isSingleton()返回true所以Spring容器会把它当作单例管理。要注意的是SqlSessionFactory一旦构建完成Configuration对象也就固定了。后续想再往里面添加新Mapper或修改配置不会生效除非重新构建一个SqlSessionFactory。所以如果你用SqlSessionFactoryBean之后还想通过Configuration.addMapper()动态补充Mapper通常会遇到这个Mapper已存在或者找不到对应语句的困惑。正确的做法是提前把Mapper XML都配置到mapperLocations里或者在构建前动态生成Configuration。4. 常见问题与排查技巧实录4.1 循环依赖Spring Boot 2.6之后的高频报错换了新版本框架之后项目启动时可能突然抛出如下异常Relying upon circular references is discouraged and they are prohibited by default.这背后的链路大致是SqlSessionFactoryBean依赖DataSource而DataSource的初始化又依赖某些MyBatis相关的Bean比如一个Mapper接口被注入到了数据源的配置类里于是形成了Bean之间的循环引用。Spring Boot 2.6之前默认允许循环引用之后默认禁止所以很多老项目一升级就踩到这个坑。排查时先画出依赖链谁依赖了谁循环是在哪一环形成的。如果确实是无害的循环可以在配置里打开允许开关spring: main: allow-circular-references: true但更推荐的做法是重构依赖关系把循环引用本身破除。比如数据源初始化阶段的逻辑就不应该反向去依赖MyBatis的Mapper将这些逻辑拆到单独的监听器或配置类中让依赖方向变成单向的。4.2 Mapper XML扫描不到classpath与classpath*的区别症状非常经典应用能正常启动Mapper接口也注入了但每次调用方法都报Invalid bound statement (not found): com.example.mapper.UserMapper.selectByPrimaryKey大多数人第一时间怀疑Mapper接口没被扫描到但实际上接口扫描如果有问题注入阶段就会失败。真正的原因往往是Mapper XML没有加载进Configuration。排查步骤也很简单第一步看SqlSessionFactoryBean的mapperLocations配置写的什么。是classpath:mapper/*.xml还是classpath*:mapper/*.xml。如果Mapper XML在另一个依赖模块的JAR里必须用classpath*:。第二步检查打包产物里是否真的有XML文件。有时候IDE里看得到文件但构建工具打包时过滤掉了src/main/resources下的某些后缀导致最终产物里没有。第三步看XML文件的namespace是否和Mapper接口全限定名完全一致id是否和接口方法名一致。顺便说一句从排查无数项目的经验来看Invalid bound statement这个报错里真正因为XML路径扫描不到的比例和因为namespace或id写错的比例差不多各占一半。4.3 启动不报错跑SQL才报错的连接问题之前提过SqlSessionFactoryBean构建时不会主动建立物理数据库连接。所以你数据库IP变了、密码错了、端口没开应用启动照样成功直到第一个请求触发SQL查询才开始抛连接异常。这个特性本身不是Bug但对排查问题的人来说非常容易造成误导。我曾经处理过一个线上服务一切正常但查询偶尔超时的问题最初怀疑是SQL性能问题后来才发现根本不是SQL慢而是数据源连接池初始化方式有问题某些情况下连接获取超时。这种问题单看启动日志真的很难定位因为一切看起来都很正常。建议在所有项目里都养成这样的习惯启动后主动做一次轻量的DB探活比如调用一个最简单的SELECT 1查询能提前暴露数据源配置问题。很多框架自带健康检查功能启动后访问健康检查端点就能验证数据源连接是否正常。4.4 多数据源配置的典型冲突有些项目因为业务隔离需要配置多个数据库于是配了多个SqlSessionFactoryBean。最常见的问题有两个。第一个Mapper XML被重复注册。两个SqlSessionFactoryBean都用了classpath*:mybatis/mapper/*.xml这个路径把两个模块的Mapper XML都扫描进来了后初始化的那个工厂就会报Mapper已存在的错误。解决办法是把不同数据源的Mapper XML放到不同目录下每个SqlSessionFactoryBean只扫描自己的目录。第二个事务管理器和数据源不对应。多个数据源时每个数据源需要配自己的DataSourceTransactionManager然后通过Transactional注解的transactionManager属性指定使用哪个管理器。如果事务管理器配错事务会静默失效操作出现部分成功部分失败还不好排查。用SqlSessionFactoryBean时尤其要注意一个SqlSessionFactory只能绑定一个数据源一个事务管理器也只能管理一个数据源的事务跨数据源事务需要额外引入分布式事务方案不能指望简单的配置覆盖。4.5 自定义TypeHandler注册不生效配置了typeHandlersPackage也实现了TypeHandler接口但字段转换就是不执行。这类问题多半是自定义的TypeHandler类没有加MappedJdbcTypes和MappedTypes注解MyBatis在做类型匹配时不知道这个处理器对应哪个Java类型和JDBC类型扫描到了也匹配不上。解决方法很简单在实现类上明确标注MappedTypes(MyEnum.class) MappedJdbcTypes(JdbcType.VARCHAR) public class MyEnumTypeHandler extends BaseTypeHandlerMyEnum { // 实现方法 }如果个别字段用了特殊类型也可以在Mapper XML里通过typeHandler属性显式指定。4.6 问题速查表现象可能原因排查方向启动报循环引用Bean依赖链成环检查DataSource与Mapper的依赖方向必要时打开循环引用开关执行SQL报Invalid bound statementMapper XML没加载、namespace写错、id不匹配核对mapperLocations路径、namespace、方法名启动成功但第一次查询报连接失败数据源参数错误或网络不通启动后主动探活检查数据源配置多个数据源时Mapper重复注册mapperLocations扫描范围重叠不同数据源使用不同XML目录枚举转换不生效TypeHandler没有注解声明补上MappedTypes和MappedJdbcTypes事务回滚不生效transactionFactory配置成了JdbcTransactionFactory使用SpringManagedTransactionFactory新加XML文件后启动不解析打包未包含resources下的XML检查构建产物调整资源过滤配置5. 版本差异与最佳实践5.1 MyBatis-Spring 2.x带来的变化SqlSessionFactoryBean的完整类名是org.mybatis.spring.SqlSessionFactoryBean它在MyBatis-Spring这个桥接包里。2.x版本相比早期版本有不少行为调整。其中一个值得注意的点是Configuration对象的处理方式更规范了很多原本需要手动设置的项会在构建过程中自动完成比如mapperLocations里的XML会被逐个解析并和Mapper接口关联。另外2.x版本对Spring Boot自动配置的适配也更好。如果你用的是Spring Boot以前需要手写的SqlSessionFactoryBean配置现在大部分都被MybatisAutoConfiguration接管了。Spring Boot自己会创建一个SqlSessionFactoryBean自动注入数据源、自动扫描Mapper接口、自动加载类路径下的mybatis-config.xml。这也是为什么现在很多新项目里看不到任何SqlSessionFactoryBean相关XML但MyBatis照常工作的原因。不过这并不意味着可以完全不懂SqlSessionFactoryBean。恰好相反理解了它的工作原理之后Spring Boot里那些约定俗成的自动配置行为就都能对上号了——为什么typeAliasesPackage可以在配置文件中指定为什么mapperLocations支持通配符为什么自定义插件配置会生效这些都是SqlSessionFactoryBean各个属性在起作用。5.2 推荐的配置策略从长期维护的角度出发我给几个在项目中反复验证过比较稳的配置建议。优先使用JavaConfig而不是XML去配置SqlSessionFactoryBean。XML配置在年代久远的项目里很常见但JavaConfig的好处是类型安全IDE里跳转方便编译期就能暴露拼写错误。一个典型的写法如下Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean factoryBean new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); factoryBean.setConfigLocation(new ClassPathResource(mybatis/mybatis-config.xml)); factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources(classpath*:mybatis/mapper/*.xml)); factoryBean.setTypeAliasesPackage(com.example.entity); return factoryBean.getObject(); }这里有一个小坑要注意直接调用factoryBean.getObject()的写法是可行的因为SqlSessionFactoryBean的getObject()内部会走完整的构建流程。但在Spring容器中更合适的做法是标注Bean方法返回SqlSessionFactory类型Spring会自动识别FactoryBean的语义。如果你手动调用getObject()务必确认afterPropertiesSet()已经被触发过不然可能拿到尚未构建完毕的结果。第二个建议是mybatis-config.xml里的配置项尽量精简把能交给Spring处理的部分都交给Spring。比如dataSource已经在Spring容器里管理了就没必要在MyBatis配置里再配一遍环境mapperLocations已经在SqlSessionFactoryBean上设置了也不需要写在XML里。保持单一配置来源可以避免两处配置相互覆盖的混乱。第三个建议是对分页插件这类全局插件配置前要确认它和其他拦截器之间的顺序。MyBatis的插件是通过责任链模式组织的多个插件同时存在时执行顺序会影响最终结果。分页插件通常会拦截Executor的query方法如果其他插件也拦截了query且放在了分页插件之前可能会导致分页逻辑错乱。5.3 SqlSessionFactoryBean和MyBatis-Plus等扩展框架的兼容问题现在很多项目用MyBatis-Plus替代原生MyBatis注意MyBatis-Plus也有自己的MybatisSqlSessionFactoryBean它继承了SqlSessionFactoryBean并增强了部分功能主要用来支持MyBatis-Plus的一些特性比如自带的分页插件、逻辑删除、乐观锁等。这里很容易犯的错误是在MyBatis-Plus项目里手动配置了一个原生SqlSessionFactoryBean结果MyBatis-Plus的增强功能完全不生效因为原生Bean构建出来的Configuration没有注册MyBatis-Plus的内部组件。遇到这种情况优先排查是不是默认的自动配置被覆盖了。如果确有必要自定义建议继承MyBatis-Plus提供的MybatisSqlSessionFactoryBean而不是直接使用原生类。从这些扩展框架的兼容性也能反向看出SqlSessionFactoryBean这个类在整个Java生态里的位置有多重要。它本身是一个标准的SpringFactoryBean所有需要构建SqlSessionFactory的场景都以它为核心扩展框架也都是基于它做继承和增强。弄懂了它后面再接触各类基于MyBatis的框架都会很顺。6. 最后再分享一点排查经验我自己的体会是SqlSessionFactoryBean这种类属于典型的看起来简单、用起来复杂的桥接组件。它的API设计很直观属性名也都可读但真正遇到问题的时候光看配置是看不出因果的必须把Spring容器的Bean生命周期、MyBatis的Configuration初始化顺序、以及连接池的运作时机放在一起考虑。如果你不知道怎么快速上手排查我给你一个具体的建议在调试模式下直接跟踪SqlSessionFactoryBean.buildSqlSessionFactory()方法的执行过程断点打到configuration.parse()和mapperLocations解析那段。你会看到MyBatis从XML到Configuration对象的完整映射过程也就能直观理解为什么某个配置会导致特定的报错信息这种实体化的感知比读十篇博客都有效。另一个亲身验证过的小技巧是在应用启动完成后打印一条日志把SqlSessionFactory的Configuration对象里已注册的Mapper总数输出出来。这样每次启动都能快速确认有没有Mapper遗漏加载能省掉很多上线后接口突然报错的突发排查时间。关于SqlSessionFactoryBean的内容到这里就聊完了。你可能发现它的核心思路其实很简单通过Spring的FactoryBean机制把MyBatis的初始化工作收纳到Spring容器的生命周期里让两者在统一的管理框架下协作。理解了这一层配置、报错、排查都有了抓手不再是被动地靠搜索引擎逐条匹配症状-解法了。希望这篇文章能帮你把这个关键类彻底吃透。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →