第九章 : mybatis-spring-boot-starter 机制原理

前言

本章节知识重点:通过分析 mybatis-spring-boot-starter组件构成以及 @Mapper 或 @MapperScan 注解的作用,深入理解mybatis的集成原理,理解Springboot是如何加载mybatis的接口、mapper.xml以及mybatis.conf配置文件参数.

mybatis-spring-boot-starter 机制原理

设计原理主要基于 MyBatis 和 Spring Boot 的自动配置特性。其核心组件包括 SqlSessionFactory、SqlSessionTemplate 和 MapperScanner。

  1. SqlSessionFactory:这是 MyBatis 的核心接口,用于创建 SqlSession。在 mybatis-spring-boot-starter 中,SqlSessionFactory 通常会通过 XML 配置文件或 Java 配置类自动配置。
  2. SqlSessionTemplate:这是 Spring 提供的一个模板类,封装了对 SqlSession 的操作,使得开发者可以更方便地执行 SQL 语句。在 mybatis-spring-boot-starter 中,SqlSessionTemplate 会通过自动配置的方式引入到 Spring 容器中。
  3. MapperScanner:这是 MyBatis 提供的一个组件,用于扫描指定包下的所有 Mapper 接口,并将其注册到 Spring 容器中。在 mybatis-spring-boot-starter 中,MapperScanner 会通过自动配置的方式引入到 Spring 容器中。
  4. 在 Spring Boot 项目中使用 MyBatis 时,如果没有显式地配置 SqlSessionFactory 和 MapperScanner,Spring Boot 会自动扫描相关的类和配置文件,并自动创建和配置这两个组件。
  5. 利用 MyBatis 和 Spring Boot 的自动配置特性,简化我们在 Spring Boot 项目中使用 MyBatis 的配置和操作。

如果没有显式地配置 SqlSessionFactory 和 MapperScanner,Spring Boot 会默认自动扫描相关的类和配置文件,并自动创建和配置这两个组件。

具体来说,Spring Boot 会执行以下步骤:

  1. 扫描启动类所在的包及其子包下的所有类,寻找标注了 @Mapper 或 @MapperScan 注解的类。

  2. 对于找到的 @Mapper 注解的类,将其注册到 Spring 容器中,并自动创建 SqlSessionFactory 和 MapperScanner。

  3. 对于找到的 @MapperScan 注解的类,将其作为配置类,并自动创建 SqlSessionFactory 和 MapperScanner。

  4. 对于没有 @Mapper 或 @MapperScan 注解的类,如果它们实现了接口,且接口中标注了 @Mapper 或 @MapperScan 注解,那么也会将它们注册到 Spring 容器中,并自动创建 SqlSessionFactory 和 MapperScanner。

  5. 在创建 SqlSessionFactory 和 MapperScanner 时,Spring Boot 会根据默认的配置规则,自动配置相关的参数和属性。例如,它会使用默认的数据库连接信息、事务管理器、类型别名等。

mybatis-spring-boot-starter pom.xml

<dependency>
     	<!--定义springboot启动-->
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
          <!--定义springboot jdbc-->
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
          <!--定义mybatis自动配置-->
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-autoconfigure</artifactId>
    </dependency>
    <dependency>
          <!--定义mybatis包-->
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
    </dependency>
    <dependency>
          <!--定义mybatis与spring集成-->
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
    </dependency>

以上pom.xml定义了 spring-boot-starter 、spring-boot-starter-jdbc、mybatis、mybatis-spring、mybatis-spring-boot-autoconfigure

通过以上分析,第三方jar与Spring Boot集成都会包含三个必须的 jar:spring-boot-starter 、自身定义的包、以及与Spring集成的定义

@Mapper
package org.apache.ibatis.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Marker interface for MyBatis mappers.
 *
 * <p>
 * <b>How to use:</b>
 *
 * <pre>
 * &#064;Mapper
 * public interface UserMapper {
 *   // ...
 * }
 * </pre>
 *
 * @author Frank David Martínez
 */
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
public @interface Mapper {
  // Interface Mapper
}

定义所属包,表示@Mapper注解类是mybatis框架定义的

package org.apache.ibatis.annotations

代码示例:

@Mapper 注解是由 Mybatis 框架中定义的一个描述数据层接口的注解,用于告诉 Spring 框架此接口的实现类由 Mybatis 负责创建,并将其实现类对象存储到 Spring 容器中。通常情况下,我们会在接口方法上添加 @Mapper 注解,以实现 Mybatis 对该接口方法的映射。

示例代码如下:

@Mapper  
public interface UserMapper {  
    List<User> findAll();  
}

在上面的代码中,我们使用 @Mapper 注解声明了一个 UserMapper 接口,该接口用于操作数据库中的用户数据。通过在接口方法上添加 @Mapper 注解,我们告诉 Mybatis 在编译后生成相应的接口实现类,并将其实例存储到 Spring 容器中。这样,我们就可以通过 Spring 容器中的 UserMapper 接口来访问数据库中的用户数据。

@MapperScan
package org.mybatis.spring.annotation;

import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.Import;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({MapperScannerRegistrar.class})
@Repeatable(MapperScans.class)
public @interface MapperScan {
    String[] value() default {};

    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    Class<? extends Annotation> annotationClass() default Annotation.class;

    Class<?> markerInterface() default Class.class;

    String sqlSessionTemplateRef() default "";

    String sqlSessionFactoryRef() default "";

    Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;

    String lazyInitialization() default "";
}

定义所属包,表示 @MapperScan注解类是mybatis.spring框架定义的

package org.mybatis.spring.annotation;

代码示例:

@MapperScan 注解是 MyBatis-Spring 项目中的一个注解,用于指示 Spring 扫描并注册 MyBatis 的 Mapper 接口,使得这些接口可以被自动实例化并注入到 Spring 容器中。在使用 MyBatis 时,通常会定义 Mapper 接口来描述 SQL 操作,而实际的 SQL 语句和参数映射是通过 XML 文件完成的。@MapperScan 注解的作用是告诉 Spring 扫描指定的包路径,查找这些包下的 Mapper 接口,并将它们注册到 Spring 容器中。

以下是一个简单的示例,展示了如何在 Spring Boot 项目中使用 @MapperScan 注解:

在 Spring Boot 项目的入口类上使用 @MapperScan 注解,指定需要扫描的 Mapper 接口所在的包路径:

import org.springframework.boot.SpringApplication;  
import org.springframework.boot.autoconfigure.SpringBootApplication;  
import org.mybatis.spring.annotation.MapperScan;  
  
@SpringBootApplication  
@MapperScan("com.example.mapper") // 指定 Mapper 接口所在的包路径  
public class MyApplication {  
    public static void main(String[] args) {  
        SpringApplication.run(MyApplication.class, args);  
    }  
}

在上述代码中,@MapperScan(“com.example.mapper”) 注解告诉 Spring Boot 扫描 com.example.mapper 包路径下的所有类,查找其中的 Mapper 接口,并将它们注册到 Spring 容器中。这样,在应用启动时,Spring Boot 就会自动扫描该包下的所有 Mapper 接口,并将其实例化后交给 Spring 容器管理。使用 @MapperScan 注解可以避免手动在配置文件中配置 Mapper 的 Bean,从而简化配置过程,提高开发效率。同时,使用注解也可以提高代码的可读性和维护性,使得代码更加易于理解和修改。

SpringBoot中使用MyBatis时参数
  1. mybatis-spring-boot-starter:这是MyBatis与Spring Boot集成的自动配置类,可以通过在Maven或Gradle的构建配置文件中添加依赖来引入。它提供了对MyBatis的自动配置和简化配置的支持。
  2. @MapperScan:注解类,用于指示Spring扫描指定的包路径,查找其中的Mapper接口,并将它们注册到Spring容器中。可以指定多个包路径,用逗号分隔。
  3. @Mapper:注解类,用于标注Mapper接口,指示Spring将其注册到Spring容器中。可以在接口方法上添加@Mapper注解,以实现特定的SQL操作。
  4. sqlSessionFactoryBean():这是一个方法,用于创建SqlSessionFactory的Bean对象。可以在配置类中重写该方法,以提供自定义的SqlSessionFactory配置。
  5. sqlSessionTemplateBean():这是一个方法,用于创建SqlSessionTemplate的Bean对象。可以在配置类中重写该方法,以提供自定义的SqlSessionTemplate配置。
  6. mapperLocations():这是一个方法,用于指定Mapper接口所在的XML文件或Java配置类的位置。可以在配置类中重写该方法,以提供自定义的Mapper接口配置。
  7. typeAliasesPackage():这是一个方法,用于指定类型别名的包路径。可以在配置类中重写该方法,以提供自定义的类型别名配置。
  8. configLocation():这是一个方法,用于指定MyBatis的配置文件路径。可以在配置类中重写该方法,以提供自定义的MyBatis配置文件路径。
  9. environment():这是一个方法,用于指定MyBatis的环境配置。可以在配置类中重写该方法,以提供自定义的环境配置。
  10. properties():这是一个方法,用于指定MyBatis的属性配置。可以在配置类中重写该方法,以提供自定义的属性配置。
package org.mybatis.spring.boot.autoconfigure;

import java.io.IOException;
import java.util.Optional;
import java.util.Properties;
import java.util.stream.Stream;

import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

/**
 * Configuration properties for MyBatis.
 *
 * @author Eddú Meléndez
 * @author Kazuki Shimizu
 */
@ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX)
public class MybatisProperties {

  public static final String MYBATIS_PREFIX = "mybatis";

  private static final ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();

  /**
   * Location of MyBatis xml config file.
   */
  private String configLocation;

  /**
   * Locations of MyBatis mapper files.
   */
  private String[] mapperLocations;

  /**
   * Packages to search type aliases. (Package delimiters are ",; \t\n")
   */
  private String typeAliasesPackage;

  /**
   * The super class for filtering type alias. If this not specifies, the MyBatis deal as type alias all classes that
   * searched from typeAliasesPackage.
   */
  private Class<?> typeAliasesSuperType;

  /**
   * Packages to search for type handlers. (Package delimiters are ",; \t\n")
   */
  private String typeHandlersPackage;

  /**
   * Indicates whether perform presence check of the MyBatis xml config file.
   */
  private boolean checkConfigLocation = false;

  /**
   * Execution mode for {@link org.mybatis.spring.SqlSessionTemplate}.
   */
  private ExecutorType executorType;

  /**
   * The default scripting language driver class. (Available when use together with mybatis-spring 2.0.2+)
   */
  private Class<? extends LanguageDriver> defaultScriptingLanguageDriver;

  /**
   * Externalized properties for MyBatis configuration.
   */
  private Properties configurationProperties;

  /**
   * A Configuration object for customize default settings. If {@link #configLocation} is specified, this property is
   * not used.
   */
  @NestedConfigurationProperty
  private Configuration configuration;

application.properties

mybatis.mapper-locations=classpath:/mapper/*

作为一个开发人员,我们心中是否会一直疑惑,为什么在application.properties 要定义mybatis开头的参数?通过下面源码可以看出,环境变量进行了隔离,必须以mybatis开头,否则不能注入到mybatis Bean.

@ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX)
public class MybatisProperties {

  public static final String MYBATIS_PREFIX = "mybatis";
总结
  1. Springboot集成第三方框架的时候,会进行参数隔离,通过PREFIX
  2. @Mapper 与@MapperScan注解的功能是一样的,@MapperScan按照Springboot规范与风格进行了封装,底层原理不变
    在这里插入图片描述
Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐