MyBatis3源码深度解析(十二)MyBatis的核心组件(一)Configuration

文章目录

  • 第四章 MyBatis的核心组件
    • 4.1 使用MyBatis操作数据库
    • 4.2 MyBatis核心组件
    • 4.3 Configuration组件
      • 4.3.1 属性
      • 4.3.2 设置
      • 4.3.3 类型别名
      • 4.3.3 类型处理器
      • 4.3.5 对象工厂
      • 4.3.6 插件
      • 4.3.7 配置环境
      • 4.3.8 映射器

第四章 MyBatis的核心组件

4.1 使用MyBatis操作数据库

在研究MyBatis的核心组件之前,有必要了解一下如何使用MyBatis操作数据库。本文使用maven创建一个简单的示例项目来演示。

(1)准备数据库环境:使用MySQL数据库,创建一个新的database:mybatis_demo,新的表user,并插入数据。

CREATE DATABASE mybatis_demo;
USE mybatis_demo;
CREATE TABLE `user` (
  `id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `name` VARCHAR(20) DEFAULT NULL,
  `age` INT(11) DEFAULT NULL,
  `phone` VARCHAR(20) DEFAULT NULL,
  `birthday` DATETIME DEFAULT NULL
)
insert into user (name, age, phone, birthday) values('孙悟空', 1500, '18705464523', '0000-01-01');
insert into user (name, age, phone, birthday) values('猪八戒', 1000, '15235468789', '0500-03-10');

(2)创建maven项目,导入相关依赖。

<dependencies>
    <!--单元测试-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>compile</scope>
    </dependency>
    <!--mybatis-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.15</version>
    </dependency>
    <!--mysql-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
</dependencies>

(3)编写MyBatis主配置文件mybatis-config.xml。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC
        "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <settings>
        <!--支持返回自动生成主键-->
        <setting name="useGeneratedKeys" value="true"/>
        <!--支持实体名驼峰原则-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <!--别名处理-->
    <typeAliases>
        <package name="com.star.mybatis.entity"/>
    </typeAliases>
    <!--环境信息-->
    <environments default="dev">
        <environment id="dev">
            <!--事务管理器-->
            <transactionManager type="JDBC"/>
            <!--数据源:用户名和密码需要改成自己定义的-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis_demo"/>
                <property name="username" value="******"/>
                <property name="password" value="******"/>
            </dataSource>
        </environment>
    </environments>
    <!--Mapper映射文件-->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>

MyBatis主配置文件用于配置MyBatis框架的配置信息,这些参数会改变MyBatis的运行时行为。

(4)编写Java实体User。

public class User {

    private Integer id;
    private String name;
    private Integer age;
    private String phone;
    private Date birthday;
    
    // constructor getter setter ...
}

(5)编写UserMapper接口。

public interface UserMapper {

    List<User> selectAll();

    @Select("select * from user where id = #{id, jdbcType=INTEGER}")
    User selectById(@Param("id") Integer id);

}

为了演示方便,这里使用两种方式配置SQL语句,selectAll()方法用XML的方式,selectById()方法用注解的方式。

(6)编写映射文件UserMapper.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.star.mybatis.mapper.UserMapper">

    <select id="selectAll" resultType="User">
        select * from user
    </select>

</mapper>

(7)编写单元测试。

@Test
public void testMybatis() throws IOException {
    // 读取配置文件
    Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
    // 创建会话
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 获取Mapper接口
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    // 操作数据库
    List<User> userList = userMapper.selectAll();
    userList.forEach(System.out::println);
    System.out.println("---------");
    User user = userMapper.selectById(1);
    System.out.println(user.toString());
}

(8)执行单元测试,控制台打印结果。

User{id=1, name='孙悟空', age=1500, phone='18705464523', birthday=Thu Jan 01 00:00:00 CST 1}
User{id=2, name='猪八戒', age=1000, phone='15235468789', birthday=Fri Mar 10 00:00:00 CST 500}
---------
User{id=1, name='孙悟空', age=1500, phone='18705464523', birthday=Thu Jan 01 00:00:00 CST 1}

如示例代码所示,SqlSession是MyBatis提供的与数据库交互的接口,其实例通过工厂模式创建。

为了创建SqlSession对象,首先需要创建SqlSessionFactory对象,而SqlSessionFactory对象的创建又依赖于SqlSessionFactoryBuilder类,该类提供了一系列重载的build()方法,将主配置文件的输入流作为参数传入SqlSessionFactoryBuilder对象的build()方法,则可以返回一个SqlSessionFactory对象。

有了SqlSessionFactory对象后,调用其openSession()方法即可获得一个与数据库建立连接的SqlSession实例。

调用SqlSession对象的getMapper()方法创建一个Mapper接口的动态代理对象,然后调用代理实例的方法即可完成与数据库的交互。

需要注意的是,MyBatis来源于iBatis项目,依然保留了iBatis执行Mapper的方式,例如:

// 兼容iBatis执行Mapper的方式
List<User> userList = sqlSession.selectList("com.star.mybatis.mapper.UserMapper.selectAll");

另外,MyBatis还提供了一个SqlSessionManager类,同样可以用于与数据库的交互,例如可以把单元测试方法修改成如下:

@Test
public void testSqlSessionManager() throws IOException {
    Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
    // 创建SqlSessionManager对象
    SqlSessionManager sqlSessionManager = SqlSessionManager.newInstance(reader);
    sqlSessionManager.startManagedSession();
    // 通过SqlSessionManager获取Mapper接口
    UserMapper userMapper = sqlSessionManager.getMapper(UserMapper.class);
    List<User> userList = userMapper.selectAll();
    userList.forEach(System.out::println);
    System.out.println("---------");
    User user = userMapper.selectById(1);
    System.out.println(user.toString());
}

如示例代码所示,SqlSessionManager使用了单例模式,在整个应用程序中只存在一个实例。通过该类的静态方法newInstance()即可获取SqlSessionManager的实例。

SqlSessionManager实现了SqlSessionFactory和SqlSession接口,因此可以替代SqlSession完成与数据库的交互。

4.2 MyBatis核心组件

在上面的示例项目中,有一个比较核心的MyBatis组件——SqlSession,它是面向用户的操作数据库的API。除此之外,MyBatis还有一些其他的核心组件,其执行流程如下图所示:

这些核心组件的作用大致描述如下:

  • Configuration

用于描述MyBatis的主配置信息。其他组件需要获取配置信息时,可以直接通过Configuration对象获取。MyBatis在应用启动时,会读取主配置文件mybatis-config.xml中的配置,并将这些配置注册到Configuration组件中,其他组件需要这些配置时,可以直接通过Configuration对象获取。

  • MappedStatement

用于描述Mapper中的SQL配置信息,是对Mapper XML配置文件中的、、、等标签或者@Select、@Update、@Delete、@Insert等注解的封装。

  • SqlSession

是MyBatis提供的面向用户的API,表示和数据库交互时的会话对象,用于完成数据库的增删改查功能。SqlSession是Executor组件的外观,目的是对外提供易于理解和使用的数据库操作接口。

  • Executor

Executor是MyBatis的SQL执行器,MyBatis中对数据库的所有增删改查操作都是由Executor组件完成的。

  • StatementHandler

StatementHandler封装了对JDBC的Statement对象的操作,比如为Statement对象设置参数、调用Statement接口提供的方法与数据库交互等。

  • ParameterHandler

当MyBatis使用的Statement类型为PreparedStatement和CallableStatement时,ParameterHandler用于为Statement对象的参数占位符设置值。

  • ResultSetHandler

ResultSetHandler封装了对JDBC中的ResultSet对象的操作,当执行SQL类型为SELECT语句时,ResultSetHandler用于将查询结果转换为Java对象。

  • TypeHandler

TypeHandler是MyBatis的类型处理器,用于处理Java类型与JDBC类型之间的映射。它能够根据Java类型调用PreparedStatement或CallableStatement对象的setXXX()方法为Statement对象设置值,而且能够根据Java类型调用ResultSet对象的getXXX()方法获取SQL执行结果。

MyBatis操作数据库的过程大致如下:

  1. SqlSession是用户层面的API,它是Executor组件的外观,目的是为用户提供更友好的数据库操作接口。
  2. 真正执行SQL操作的是Executor组件,它是SQL执行器,会使用StatementHandler组件对JDBC的Statement对象进行操作。
  3. 当Statement类型为PreparedStatement和CallableStatement时,会通过ParameterHandler组件为参数占位符赋值。
  4. ParameterHandler组件会根据Java类型找到对应的TypeHandler对象,TypeHandler中会通过Statement对象提供的setXXX()方法为Statement对象中的参数占位符设置值。
  5. StatementHandler组件使用JDBC中的Statement对象与数据库完成交互后,当SQL语句类型为SELECT时,通过ResultSetHandler组件从Statement对象中获取ResultSet对象,然后将ResultSet对象转换为Java对象。

4.3 Configuration组件

MyBatis框架的配置信息有两种,一种是配置MyBatis框架属性的主配置文件,另一种是配置执行SQL语句的Mapper配置文件。

Configuration组件的作用是描述MyBatis主配置文件的信息,即mybatis-config.xml文件。

4.3.1 属性

在mybatis-config.xml文件中,属性使用标签进行配置,其特点是可外部配置可动态替换。例如:

<!-- mybatis-config.xml -->
<properties resource="C:\workspace\mybatis_demo2\config\config.properties">
    <property name="username" value="dev_user"/>
    <property name="password" value="*****"/>
</properties>

可外部配置的意思是,属性既可以在标签下使用标签直接配置,也可以通过resource属性引用外部的一个properties文件。如果两种方式都配置了属性,则优先加载标签下的属性,再加载resource路径下properties文件中的属性,并覆盖已有的同名属性。

可动态替换的意思是,标签下设置的属性,可以在整个配置文件中用于替换需要动态配置的属性值。例如,在配置文件的其它位置使用<property name="username" value="${username}"/>时,${username}会被替换为dev_user

在Configuration组件中,组合了一个Properties对象,用于保存属性配置。

源码1org.apache.ibatis.session.Configuration

protected Properties variables = new Properties();

借助Debug工具,可以看到属性均被加载到Configuration组件中:

4.3.2 设置

在mybatis-config.xml文件中,属性使用标签进行配置,这些设置属性的值会改变MyBatis运行时的行为,因此非常重要。

相对应的,Configuration组件定义了一系列属性来保存这些设置属性。例如:

<!-- mybatis-config.xml -->
<settings>
    <!--支持返回自动生成主键-->
    <setting name="useGeneratedKeys" value="true"/>
    <!--支持自动驼峰命名规则-->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

对应到Configuration组件定义的属性是:

源码2org.apache.ibatis.session.Configuration

public class Configuration {
    protected boolean mapUnderscoreToCamelCase;
    protected boolean useGeneratedKeys;
    // ......
}

除了 源码1 中列出的2个设置属性,还有一系列属性,这些属性的作用、默认值等可以参见 W3Cschool的文档-MyBatis教程-XML配置 中的一张表。

借助Debug工具,可以看到设置属性被加载到Configuration组件中:

在这里插入图片描述

4.3.3 类型别名

类型别名就是为Java类型设置一个短的名字,用来减少类的完全限定名的冗余。例如使用User作为com.star.mybatis.entity.User的别名:

在mybatis-config.xml文件中,类型别名使用标签进行配置。例如:

<!-- mybatis-config.xml -->
<typeAliases>
    <typeAlias alias="User" type="com.star.mybatis.entity.User"/>
</typeAliases>

也可以指定一个包名,MyBatis会在包下面搜索需要的Java对象,例如:

<!-- mybatis-config.xml -->
<typeAliases>
    <package name="com.star.mybatis.entity"/>
</typeAliases>

在没有@Alias注解的情况下,MyBatis会使用Java对象的首字母小写的非限定类名来作为它的别名,例如com.star.mybatis.entity包下的User类的别名为user;若该类有@Alias注解,则别名为其注解值。

@Alias("user")
public class User {...}

MyBatis本身已经为许多常见的Java类型内置了相应的类型别名,如下表:

在这里插入图片描述

对应到Configuration组件,组合了一个类型别名注册器,用于注册所有的类型别名。其源码如下:

源码3org.apache.ibatis.session.Configuration

// 用于注册所有的类型别名
protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();

借助Debug工具,可以看到加载到Configuration组件中的别名有81个,其中包括自定义的User类的别名:

4.3.3 类型处理器

类型处理器的作用在于,MyBatis在预处理语句(PreparedStatement)中设置一个参数时,或者从ResulrSet结果集中取出一个值时,都会用类型处理器将获取的值以合适的方式转换成JDBC类型或Java类型。

在mybatis-config.xml文件中,类型别名使用标签进行配置。例如:

<!-- mybatis-config.xml -->
<typeHandlers>
    <typeHandler handler="com.star.mybatis.handler.ExampleTypeHandler"
        javaType="String"
        jdbcType="VARCHAR"/>
</typeHandlers>

MyBatis有许多默认的类型处理器实现,基本涵盖Java全部基本数据类型,如下表所示:

另外,类型处理器支持重写,或创建自定义的类型处理器来处理不支持的或非标准的类型

具体做法是:实现 org.apache.ibatis.type.TypeHandler接口, 或继承org.apache.ibatis.type.BaseTypeHandler,然后在主配置文件mybatis-config.xml中使用标签进行配置。例如:

@MappedTypes({String.class})
@MappedJdbcTypes({JdbcType.VARCHAR})
public class ExampleTypeHandler extends BaseTypeHandler {...}

那如何确定这个自定义的类型处理器是处理什么类型的呢?

设置类型处理器处理的Java类型:

  • 在类型处理器的配置元素上增加一个javaType属性,如:<typeHandler javaType="String"/>
  • 在类型处理器的类上增加一个@MappedTypes注解,如:@MappedTypes({String.class})。 如果同时配置javaType属性和@MappedTypes注解,则注解方式将被忽略。

设置类型处理器处理的JDBC类型:

  • 在类型处理器的配置元素上增加一个jdbcType属性,如:<typeHandler jdbcType="VARCHAR"/>
  • 在类型处理器的类上增加一个@MappedJdbcTypes注解,如:@MappedJdbcTypes({JdbcType.VARCHAR})。 如果同时配置jdbcType属性和@MappedJdbcTypes注解,则注解方式将被忽略。

最后,还可以通过设置包名让MyBatis自动查找类型处理器,此时只能通过注解方式来指定类型处理器要处理的Java类型和JDBC类型。例如:

<!-- mybatis-config.xml -->
<typeHandlers>
    <package name="com.star.mybatis.handler"/>
</typeHandlers>

在Configuration组件中,组合了一个类型处理器的注册器,用于注册所有的类型处理器。

源码4org.apache.ibatis.session.Configuration

// 用于注册所有的类型处理器
protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry(this);

借助Debug可知,Configuration组件中最终注册的类型处理器一共有41个,包括1个自定义的ExampleTypeHandler:

4.3.5 对象工厂

MyBatis每次创建结果映射对象的新实例时,会使用一个对象工厂(ObjectFactory)实例来完成。 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化。

在mybatis-config.xml文件中,对象工厂使用标签进行配置。例如:

<!-- mybatis-config.xml -->
<objectFactory type="com.star.mybatis.factory.ExampleObjectFactory">
    <property name="name" value="test"/>
</objectFactory>

通过创建自定义的对象工厂,可以覆盖对象工厂的默认行为。例如:

public class ExampleObjectFactory extends DefaultObjectFactory {

    // 处理默认构造方法
    @Override
    public <T> T create(Class<T> type) {
        return super.create(type);
    }

    // 处理带参数的构造方法
    @Override
    public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
        return super.create(type, constructorArgTypes, constructorArgs);
    }

    // 配置ObjectFactory属性
    @Override
    public void setProperties(Properties properties) {

    }

}

在Configuration组件中,组合了一个ObjectFactory对象,用于保存对象工厂,默认实现类为DefaultObjectFactory。

源码5org.apache.ibatis.session.Configuration

protected ObjectFactory objectFactory = new DefaultObjectFactory();

借助Debug可知,Configuration组件最终会将自定义的对象工厂注册到Configuration组件中:

4.3.6 插件

MyBatis允许在SQL语句执行过程中的某一点使用插件进行拦截调用。默认情况下,允许使用插件来拦截的方法包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

自定义一个插件比较简单,只需实现Interceptor接口,并指定了想要拦截的方法:

@Intercepts({@Signature(
        type= Executor.class,
        method = "update",
        args = {MappedStatement.class, Object.class})})
public class ExamplePlugin implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        return invocation.proceed();
    }

}

在mybatis-config.xml文件中,插件使用标签进行配置。例如:

<!-- mybatis-config.xml -->
<plugins>
    <plugin interceptor="com.star.mybatis.plugin.ExamplePlugin">
        <property name="name" value="ExamplePlugin"/>
    </plugin>
</plugins>

在Configuration组件中,组合了一个拦截器链,用于存放自定义的插件。

源码6org.apache.ibatis.session.Configuration

protected final InterceptorChain interceptorChain = new InterceptorChain();

借助Debug可知,Configuration组件最终会注册自定义的插件:

4.3.7 配置环境

MyBatis可以配置成适应多种环境,例如,开发、测试和生产环境有不同的配置。

但要注意,尽管可以配置多个环境,但每个SqlSessionFactory实例只能选择其中一个环境。因此,有几个数据库需要连接,就需要创建几个SqlSessionFactory实例。

在mybatis-config.xml文件中,配置环境使用标签进行配置。例如:

<!-- mybatis-config.xml -->
<environments default="dev">
    <environment id="dev">
        <transactionManager type="JDBC">
            <property name="..." value="..."/>
        </transactionManager>
        <dataSource type="POOLED">
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
        </dataSource>
    </environment>
    <environment id="test">
        ...
    </environment>
    <environment id="prod">
        ...
    </environment>
    ...
</environments>

如例子所示,标签的default属性要和标签的id属性相匹配,选择出当前生效的环境,生效的环境才会注册到Configuration组件中的环境配置。

  • 事务管理器:

在MyBatis中,有两种事务管理器:JDBC、MANAGED。

(1)JDBC

这种事务管理器直接使用JDBC的提交和回滚设置,它依赖于从数据源得到的连接来管理事务。

(2)MANAGED

这种事务管理器相当于没有事务管理器,因为它从不提交或回滚一个连接,而是全权交给了容器来管理。

  • 数据源:

注意,这里使用${...}的方式,就是取用【4.3.1 属性】中配置的属性。

标签的type属性是指数据源类型,它的取值包括UNPOOLED、POOLED、JNDI。

(1)UNPOOLED

即非“池”类型的数据源,它的实现会在每次请求时打开和关闭连接。相比连接池,它虽然有一点慢,但对于没有性能要求的简单应用程序是一个很好的选择。

UNPOOLED类型的数据源仅需要配置以下5种属性:

  • driver– JDBC驱动的Java类的完全限定名。
  • url– 数据库的JDBC URL地址。
  • username– 登录数据库的用户名。
  • password– 登录数据库的密码。
  • defaultTransactionIsolationLevel– 默认的连接事务隔离级别。

(2)POOLED

即“池”类型的数据源,它的实现会将JDBC连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。这是一种使得并发Web应用快速响应请求的流行处理方式。

除了上述提到的5种属性,还有更多属性用来配置POOLED类型的数据源:

  • poolMaximumActiveConnections– 最大活动连接数,默认值:10。
  • poolMaximumIdleConnections– 最大空闲连接数。
  • poolMaximumCheckoutTime– 池中连接最大被检出时间,超时将被强制返回,默认值:20000毫秒。
  • poolTimeToWait– 获取连接如果超过这个时间,则会给连接池打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直失败但没有任何提示),默认值:20000毫秒。
  • poolPingQuery– 发送到数据库的心跳查询SQL语句,用来检验连接是否处在正常状态并准备接受请求。默认是NO PING QUERY SET,当数据库驱动失败时,返回一个错误消息。
  • poolPingEnabled– 是否启用心跳查询。若开启,必须使用一个可执行的SQL语句设置poolPingQuery属性(最好是一个非常快的SQL语句),默认值:false。
  • poolPingConnectionsNotUsedFor– 配置poolPingQuery的使用频度。可以设置成数据库连接超时时间,来避免不必要的检测,默认值:0(即所有连接每一时刻都被检测 — 当然仅当poolPingEnabled为true时适用)。

(3)JNDI

这种数据源的实现是为了能在如EJB或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用。

这种数据源配置只需要2个属性:

  • initial_context– 用来在InitialContext中寻找上下文。这是个可选属性。
  • data_source– 引用数据源实例位置的上下文的路径。提供了initial_context配置时会在其返回的上下文中进行查找,没有提供时则直接在InitialContext中查找。

在Configuration组件中,组合了一个Environment对象,用于存放被选中的环境配置。

源码7org.apache.ibatis.session.Configuration

protected Environment environment;

借助Debug可知,Configuration组件最终会注册一个Environment对象:

4.3.8 映射器

映射器用于配置SQL映射文件的位置,也就是告诉MyBatis到哪里去找SQL映射文件。

在mybatis-config.xml文件中,映射器使用标签进行配置。例如:

    <!--映射文件-->
    <mappers>
        <!--通过指定XML文件的类路径来注册-->
        <mapper resource="mapper/UserMapper.xml"/>
        <!--通过指定XML文件的完全限定资源定位符来注册-->
        <!--<mapper url="file:///C:\workspace\mybatis_demo2\src\main\resources\mapper\UserMapper.xml"/>-->
        <!--通过Mapper接口的类路径来注册-->
        <!--<mapper class="com.star.mybatis.mapper.UserMapper"/>-->
        <!--通过Mapper接口所在包路径类注册-->
        <!--<package name="com.star.mybatis.mapper"/>-->
    </mappers>

如上面的配置所示,配置SQL映射文件的位置有4种方法是:第一是使用XML文件的类路径;第二是使用XML文件的完全限定资源定位符(即包括 file:///的URL);第三是使用Mapper接口的类路径;第四是使用Mapper接口所在包路径。

在Configuration组件中,组合了一个Mapper注册器,用于注册Mapper接口信息:

源码:

protected final MapperRegistry mapperRegistry;

借助Debug可知,Configuration组件最终会注册配置好的映射器:

本节完,更多内容请查阅分类专栏:MyBatis3源码深度解析

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《操作系统实践-基于Linux应用与内核编程》第10章-Linux综合应用

前言: 内容参考《操作系统实践-基于Linux应用与内核编程》一书的示例代码和教材内容&#xff0c;所做的读书笔记。本文记录再这里按照书中示例做一遍代码编程实践加深对操作系统的理解。 引用: 《操作系统实践-基于Linux应用与内核编程》 作者&#xff1a;房胜、李旭健、黄…

网络通信与网络协议

网络编程是指利用计算机网络实现程序之间通信的一种编程方式。在网络编程中&#xff0c;程序需要通过网络协议(如 TCP/IP)来进行通信&#xff0c;以实现不同计算机之间的数据传输和共享。在网络编程中&#xff0c;通常有三个基本要素 IP 地址:定位网络中某台计算机端口号port:定…

Pyqt5中,QGroupBox组件标题字样(标题和内容样式分开设置)相对于解除继承

Python代码示例&#xff1a; import sys from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QGroupBox, QLabelclass MyApp(QWidget):def __init__(self):super().__init__()# 创建一个 QVBoxLayout 实例layout QVBoxLayout()# 创建 QGroupBox 实例self.grou…

【中等】保研/考研408机试-二叉树相关

目录 一、基本二叉树 1.1结构 1.2前序遍历&#xff08;注意三种遍历中Visit所在的位置&#xff09; 1.2中序遍历 1.3后序遍历 二、真题实战 2.1KY11 二叉树遍历&#xff08;清华大学复试上机题&#xff09;【较难】 2.2KY212 二叉树遍历二叉树遍历&#xff08;华中科技大…

王道机试C++第8章递归与分治 Day35和蓝桥杯两道真题程序

第 8 章 递归与分治 递归是指&#xff1a;函数直接或间接调用自身的一种方法&#xff0c;通常可把一个复杂的大型问题层层转化为与原问题相似但规模较小的问题来求解。 递归策略只需少量的程序就可描述解题过程所需的多次重复计算&#xff0c;因此大大减少了程序的代码量。 8.…

OLED 菜单操作

本次介绍一款中景园带字库的OLED显示屏&#xff0c;并基于该模块描述一种菜单操作方法&#xff0c;能够极大的减少显示界面开发工作量。 使用的2.08寸OLED显示屏&#xff0c;字库芯片为GT30L32S4W&#xff0c;支持多种字号中英文。 官方提供了很完善的参考资料&#xff0c;包括…

结构体联合体枚举和位段

文章目录 结构体结构体类型的声明特殊的声明 结构的自引用结构体变量的定义和初始化结构体内存对齐为什么要内存对齐结构体传参结构体实现位段&#xff08;位段的填充&可移植性&#xff09;位段位段的内存分配空间如何开辟位段的跨平台问题位段的应用 枚举枚举类型的定义枚…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:Column)

沿垂直方向布局的容器。 说明&#xff1a; 该组件从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 可以包含子组件。 接口 Column(value?: {space?: string | number}) 从API version 9开始&#xff0c;该接口…

vscode 生成树状图工具:project-tree

按下快捷键“CtrlShiftP”, 在弹框中输入 Project Tree&#xff0c;然后敲回车即会在根目录自动生成README.md&#xff08;如果之前没有的话&#xff09;。

pytorch 入门基础知识二(Pytorch 02)

一 微积分 1.1 导数和微分 微分就是求导&#xff1a; %matplotlib inline import numpy as np from matplotlib_inline import backend_inline from d2l import torch as d2l def f(x):return 3 * x ** 2 - 4 * x 定义&#xff1a; 然后求 f(x) 在 x 1 时的导数&#xff…

HarmonyOS NEXT应用开发—折叠屏音乐播放器方案

介绍 本示例介绍使用ArkUI中的容器组件FolderStack在折叠屏设备中实现音乐播放器场景。 效果图预览 使用说明 播放器预加载了歌曲&#xff0c;支持播放、暂停、重新播放&#xff0c;在折叠屏上&#xff0c;支持横屏悬停态下的组件自适应动态变更。 实现思路 采用MVVM模式进…

【Algorithms 4】算法(第4版)学习笔记 18 - 4.4 最短路径

文章目录 前言参考目录学习笔记0&#xff1a;引入介绍1&#xff1a;APIs1.1&#xff1a;API&#xff1a;加权有向边1.2&#xff1a;Java 实现&#xff1a;加权有向边1.3&#xff1a;API&#xff1a;加权有向图1.4&#xff1a;Java 实现&#xff1a;加权有向图1.5&#xff1a;AP…

Unity类银河恶魔城学习记录10-12 p100 Improve aliments - chill源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili CharacterStats.cs using System.Collections; using System.Collections…

docker容器镜像管理

目录 一、 Docker的基本组成 二、 容器和镜像的关系 2.1 面向对象角度 2.2 从镜像容器角度 三、镜像命令 3.1 查看当前已有镜像 3.2 查看已有的全部镜像 3.3 查看镜像ID 3.4 镜像删除 四、 容器命令 4.1 下载镜像 4.2 新建和启动容器 run 4.3 交互式 4.…

探讨大世界游戏的制作流程及技术——大场景制作技术概况篇

接上文&#xff0c;我们接下来了解一下大世界场景制作技术有哪些&#xff0c;本篇旨在给大家过一遍目前业界的做法&#xff0c;能让大家有一个宏观的知识蓝图。实际上&#xff0c;针对不同的游戏类型和美术风格&#xff0c;制作技术在细节上有着非常大的不同&#xff0c;业界目…

【UE5】持枪状态站立移动的动画混合空间

项目资源文末百度网盘自取 创建角色在持枪状态站立移动的动画混合空间 在BlendSpace文件夹中单击右键选择动画(Animation)中的混合空间(Blend Space) 选择SK_Female_Skeleton 命名为BS_RifleStand 打开 水平轴表示角色的方向&#xff0c;命名为Direction&#xff0c;方…

SD-WAN技术助力跨境电商网络搭建的解决方案

随着全球贸易的蓬勃发展&#xff0c;跨境电商成为了商业领域中的一个重要组成部分。然而&#xff0c;跨境电商面临着网络搭建和管理的复杂性&#xff0c;而SD-WAN技术的引入为解决这些问题提供了一种创新的方法。本文将深入探讨SD-WAN如何有效解决跨境电商行业的网络搭建问题。…

UE5.1 iClone8 正确导入角色骨骼与动作

使用iClone8插件Auto Setup 附录下载链接 里面有两个文件夹,使用Auto Setup C:\Program Files\Reallusion\Shared Plugins 在UE内新建Plugins,把插件复制进去 在工具栏出现这三个人物的图标就安装成功了 iClone选择角色,导入动作 选择导出FBX UE内直接导入 会出现是否启动插件…

同城预约上门服务APP小程序开发 打造快捷便利生活

随着移动互联网的快速发展&#xff0c;人们的生活方式正在发生深刻的变化。特别是在城市生活中&#xff0c;人们越来越依赖移动应用来解决日常生活中的各种问题。其中&#xff0c;同城预约上门服务APP正成为一种新型的生活服务平台&#xff0c;为人们提供了更加便利和快捷的服务…

RTC的Google拥塞控制算法 rmcat-gcc-02

摘要 本文档描述了使用时的两种拥塞控制方法万维网&#xff08;RTCWEB&#xff09;上的实时通信&#xff1b;一种算法是基于延迟策略&#xff0c;一种算法是基于丢包策略。 1.简介 拥塞控制是所有共享网络的应用程序的要求互联网资源 [RFC2914]。 实时媒体的拥塞控制对于许…