1. Spring Boot 自动配置 Mybatis

1. Spring Boot 自动配置 Mybatis

自动配置

约定大于配置,缺省的配置看这个注解 @EnableConfigurationProperties({MybatisProperties.class})。这个注解中引入了MybatisProperties类,包含了一些默认的配置。

java 复制代码
@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties({MybatisProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
public class MybatisAutoConfiguration implements InitializingBean {

}

MybatisAutoConfiguration的主要属性有:

  1. MybatisProperties:yaml文件中的属性配置
  2. Interceptor[] :拦截器数组
  3. TypeHandler[] :类型解析器等

构造方法:

  1. 从 yaml 文件中获取 mybatis 前缀的属性封装成对象MybatisProperties,赋值给 properties 。
  2. 获取拦截器
  3. 获取typeHandlers
  4. 其他。。。
创建 sqlSessionFactory

前提:

  1. 依赖DataSource 数据源 @ConditionalOnSingleCandidate(DataSource.class)。要求 BeanFactory 中存在指定类并且可以确定单个候选项才会匹配成功
  2. 在数据源完成自动配置之后配置 sqlSessionFactory = new SqlSessionFactoryBean().getObject();

正文:

  1. 创建一个工厂bean:​MybatisSqlSessionFactoryBean​​

  2. 工厂 bean 设置数据源dataSource。依赖注入,此时容器中已经有了dataSource,直接拿来用。

  3. 初始化配置属性

    1. 如果有配置 mybatis-config.xml 则设置configLocation 属性。
    2. 应用yaml 文件中嵌套配置 configuration到 factoryBean。
    3. TypeHandler
    4. 拦截器
  4. 通过工厂Bean的getObject方法获取sqlSessionFactory。

    1. 如果配置项 mapperLocation不为空,循环解析每一个 mapper.xml文件

    2. XMLMapperBuilder.parse() 解析xml 文件

      1. configurationElement​解析mapper 节点

        java 复制代码
         <mapper namespace="com.pansnow.changcheng.mapper.UserMapper">
             <select id="queryUserList" resultType="com.pansnow.changcheng.pojo.User">
                 select *
                 from user
             </select>
        
             <insert id="addUser" parameterType="com.pansnow.changcheng.pojo.User">
                 insert into user(id, name, pwd)
                 values (#{id}, #{name}, #{pwd});
        
             </insert>
        
             <update id="updateUser" parameterType="com.pansnow.changcheng.pojo.User">
                 update user
                 set name=#{name},
                     pwd=#{pwd}
                 where id = #{id};
             </update>
        
             <delete id="deleteUser" parameterType="int">
                 delete
                 from user
                 where id = #{id};
             </delete>
         </mapper>
        1. namespace判空。namespace 为 mapper 接口类的 String 字符串
        2. 解析 parameterMap 和 resultMap节点
        3. 解析 sql节点
        4. 解析 select|insert|update|delete
        5. 将该文件添加到已解析集合中。protected final Set<String> loadedResources;
        6. 将 mapper 类添加到 mapper注册表中,解析 mapper 类上的注解@Select、@SelectProvider、@ResultSet 等。
        7. 解析方法上的 SQL语句parseStatement。
创建sqlSessionTemplate
  1. 使用 jdk 动态代理,创建SqlSessionProxy,增强逻辑为SqlSessionInterceptor​。代理了SqlSession的创建和获取、事务、关闭。即在调用SqlSession接口中的每一个方法时,都会调用SqlSessionInteceptor的invoke逻辑。

  2. SqlSessionInterceptor​的逻辑为:

    1. 创建SqlSession。使用 selSessionFactory

      代理对象是如何获取defaultSqlSession ,在代理方法中通过SqlSessionUtils 的方法获取SqlSession

      • 它会首先获取SqlSessionHolder,SqlSessionHolder用于在TransactionSynchronizationManager中保持当前的SqlSession。
      • 如果holder不为空,并且holder被事务锁定,则可以通过holder.getSqlSession()方法,从当前事务中获取sqlSession,即 Fetched SqlSession from current transaction。
      • 如果不存在holder或没有被事务锁定,则会创建新的sqlSession,即 Creating a new SqlSession,通过sessionFactory.openSession()方法。
      • 如果当前线程的事务是活跃的,将会为SqlSession注册事务同步,即 Registering transaction synchronization for SqlSession。
      java 复制代码
      SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, 
      	SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
      1. 如果 session 为 null,

        1. 利用事务工厂创建一个事务,
        2. 新建一个 Executor:这个是干嘛的,不太清楚哇。
        3. 新建一个 DefaultSqlSession。
        4. 创建sqlSessionHolder 将 sqlSession 包起来。
        5. 将sqlSessionHolder存放到TransactionSynchronizationManagersynchronizations中。synchronizations是一个 set 集合。
    2. 调用业务方法

    3. 如果有事务,提交事务

    4. 关闭 session。关闭前会释放 holder。​holder.released();

      java 复制代码
      SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
创建MapperScannerRegistrarNotFoundConfiguration

主要在于根据配置创建MapperScannerConfigurer​,

@Import({AutoConfiguredMapperScannerRegistrar.class}) 这个AutoConfiguredMapperScannerRegistrar类非常关键,因为他在扫描@Mapper 注解

  1. BeanDefinitionBuilder:创建MapperScannerConfigurer的 BeanDefinitionBuilder
  2. 设置扫描注解类:Mapper.class
  3. 设置扫描包路径
  4. 设置sqlSessionFactoryBeaName
  5. 设置 sqlSessionTemplateBeanName
  6. 注册MapperScannerConfigurer到注册表中
MapperScannerConfigurer

实现了 BeanDefinitionRegistryPostProcessor ,工作在bean 定义的注册阶段。

扫描@Mapper 注解,为什么需要单独处理呢?因为 Mapper 注解是 mybatis 自定义注解,和 Component 注解没有关系。这个类会将@Mapper 注解下的类也实例化后放入到 Spring 容器中。

相关推荐
OLDERHARD1 小时前
Java - MyBatis(上)
java·oracle·mybatis
计算机学姐13 小时前
基于SpringBoot+Vue的高校运动会管理系统
java·vue.js·spring boot·后端·mysql·intellij-idea·mybatis
我是浮夸15 小时前
MyBatisPlus——学习笔记
java·spring boot·mybatis
编程、小哥哥21 小时前
手写mybatis之Mapper XML的解析和注册使用
xml·java·mybatis
小桑要读研1 天前
Redis实现点赞
java·mysql·mybatis
真的想不出名儿2 天前
04-SpringBootWeb案例(下)
mybatis·spingbootweb
舞者H2 天前
如何实现Mybatis自定义插件
java·mybatis
程序员大金2 天前
基于SpringBoot+Vue+MySQL的考勤管理系统
java·javascript·vue.js·spring boot·后端·mysql·mybatis
beiback2 天前
Springboot + netty + rabbitmq + myBatis
spring boot·mysql·rabbitmq·mybatis·netty·java-rabbitmq
wclass-zhengge2 天前
Redis篇(缓存机制 - 基本介绍)(持续更新迭代)
redis·缓存·mybatis