【Mybatis源码分析 6】XMLConfigBuilder将Mybatis全局配置文件.xml中设置的节点提取赋给Configuration对象

目录

Configuration

mybatis的全局配置文件

1. properties属性

2. settings设置

3. typeAliases类型别名

4. typeHandlers类型处理器

5.ObjectFactory对象工厂

6. objectWrapperFactory对象加工工厂

7. reflectorFactory 反射工厂

8. plugins 插件机制,设置拦截器

9.environments 数据库环境

10. databaseIdProvider数据库厂商标识

11. mappers 映射器

XMLConfigBuilder将Mybatis全局配置文件.xml中设置的节点提取赋给Configuration对象

 

Configuration

Configuration类的结构很简单,包括environment(数据库环境)、typeHandlerRegistry(类型转换器注册器,将多个类型转换器注册到一个handler中)等protected的成员变量和它们的getter(Boolean类型的提供is方法)和setter方法。

mybatis的全局配置文件

mybatis的全局配置文件中引用了mybatis-3-config.dtd

<?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>

</configuration>

mybatis-3-config.dtd中设置了11个属性节点,规定mybatis配置文件中可以设置哪些属性

<!ELEMENT configuration (properties?, 
                         settings?, 
                         typeAliases?,
                         typeHandlers?, 
                         objectFactory?, 
                         objectWrapperFactory?, 
                         reflectorFactory?, 
                         plugins?, 
                         environments?, 
                         databaseIdProvider?, 
                         mappers?)>

1. properties属性

1)通过property定义

<properties>
     <property name="driver" value="com.mysql.cj.jdbc.Driver" />
     <property name="url"  value="jdbc:mysql://localhost:3306/testmybatisdb?serverTimezone=GMT%2B8&allowMultiQueries=true" />
     <property name="username" value="root" />
     <property name="password" value="18721426" />
 </properties>

2) 通过resource或url引用资源文件

<!--     设置或者引用资源文件 url:引用本地或者网络资源 resource:引用资源文件夹中的资源,
比如这里的db.propreties中设置了数据库连接信息,可以给下面的environments数据库环境节点引用
 -->
    <properties resource="db.properties"/>
#db.propreties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/testmybatisdb?serverTimezone=GMT%2B8&allowMultiQueries=true
name=root
pass=18721426

2. settings设置

这是 MyBatis 中极为重要的调整设置,规定 MyBatis 的运行时行为

<!--设置 -->
    <settings>
        <!--缓存配置的全局开关:如果这里设置成false,那么即便在映射器中配置开启也无济于事 -->
        <setting name="cacheEnabled" value="true" />
        <!--延时加载的全局开关 -->
        <setting name="lazyLoadingEnabled" value="false" />
        <!-- 是否允许单一语句返回多结果集 -->
        <setting name="multipleResultSetsEnabled" value="true" />
        <!-- 使用列标签代替列名,需要兼容驱动 -->
        <setting name="useColumnLabel" value="true" />
        <!-- 允许JDBC自动生成主键,需要驱动兼容。如果设置为true,则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍能正常工作 -->
        <setting name="useGeneratedKeys" value="false" />
        <!-- 指定MyBatis该如何自动映射列到字段或属性:NONE表示取消自动映射;PARTIAL表示只会自动映射,没有定义嵌套结果集和映射结果集;FULL会自动映射任意复杂的结果集,无论是否嵌套 -->
        <setting name="autoMappingBehavior" value="PARTIAL" />
        <!-- 配置默认的执行器:SIMPLE是普通的执行器;REUSE会重用预处理语句;BATCH会重用语句并执行批量更新 -->
        <setting name="defaultExecutorType" value="SIMPLE" />
        <!--设置超时时间:它决定驱动等待数据库响应的秒数,任何正整数-->
        <setting name="defaultStatementTimeout" value="25"/>
        <!--设置数据库驱动程序默认返回的条数限制,此参数可以重新设置,任何正整数 -->
        <setting name="defaultFetchSize" value="100" />
        <!-- 允许在嵌套语句中使用分页(RowBounds) -->
        <setting name="safeRowBoundsEnabled" value="false" />
        <!-- 是否开启自动驼峰命名规则,即从a_example到aExample的映射 -->
        <setting name="mapUnderscoreToCamelCase" value="true" />
        <!-- 本地缓存机制,防止循环引用和加速重复嵌套循环 -->
        <setting name="localCacheScope" value="SESSION" />
        <!-- 当没有为参数提供特定JDBC类型时,为空值指定JDBC类型。某些驱动需要指定列的JDBC类型,多数情况直接用一般类型即可,如NULL/VARCHAR/OTHER -->
        <setting name="jdbcTypeForNull" value="OTHER" />
        <!-- 指定触发延迟加载的方法,如equals/clone/hashCode/toString -->
        <setting name="lazyLoadTriggerMethods" value="equals" />
    </settings>

3. typeAliases类型别名

比如有些pojo对象的完全限定名较长,可以通过typeAliases起别名简化标识

<!--别名:pojo对象的别名 -->
    <typeAliases>
        <!--对类单独进行别名设置  -->
        <typeAlias alias="user" type="com.daily.pojo.User"></typeAlias>
        <typeAlias alias="product" type="com.daily.pojo.Product"></typeAlias>
        <!-- 对包进行扫描,可以批量进行别名设置,设置规则是:获取类名称,将其第一个字母变为小写 -->
        <package name="com.daily.pojo"/>
    </typeAliases>

4. typeHandlers类型处理器

在JDBC中,我们在PreparedStatement中设置预编译sql所需的参数或执行sql后根据结果集ResultSet对象获取得到的数据时,需要将数据库中的类型和java中字段的类型进行转换一样,在MyBatis中使用typeHandler来实现。简单来说,typeHandlers就是用来完成javaType和jdbcType之间的转换

比如java pojo对象中的Date类型的date属性和数据库表中一个varchar类型的date字段,在select、insert等操作时需要进行进行java的Date类型和jdbc的varchar类型之间的转换,我们定义一个类型转换器MyTypeHandler

package Plugins;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;


import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;


/**
 * 自定义一个TypeHandler用来将javatype的日期类型和jdbctype的VARCHAR进行转换
 */
public class MyTypeHandler implements TypeHandler<Date> {

    static private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd,HH:mm:ss");

    @Override
    // 设置sql中指定索引的参数,即将javaType转化为jdbcType
    public void setParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException {
        //我的数据库中date字段是varchar类型,yyyy-MM-dd格式
        ps.setString(i, sdf.format(parameter));
    }

    @Override
    // 根据列名称从结果集获取值,并将jdbcType转换成javaType
    public Date getResult(ResultSet rs, String columnName) throws SQLException {
        String columnValue = rs.getString(columnName);
        if (null != columnValue) {
            try {
                Date date = sdf.parse(columnValue);//将格式化的时期对象通过parse方法去解析当前字符串,返回的是日期格式
                return date;
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    @Override
    // 根据列索引从结果集获取值,并将jdbcType转换成javaType
    public Date getResult(ResultSet rs, int columnIndex) throws SQLException {
        String columnValue = rs.getString(columnIndex);
        if (null != columnValue) {
            try {
                Date date = sdf.parse(columnValue);//将格式化的时期对象通过parse方法去解析当前字符串,返回的是日期格式
                return date;
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    @Override
    public Date getResult(CallableStatement cs, int columnIndex) throws SQLException {
        String columnValue = cs.getString(columnIndex);
        if (null != columnValue) {
            try {
                Date date = sdf.parse(columnValue);//将格式化的时期对象通过parse方法去解析当前字符串,返回的是日期格式
                return date;
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

}

然后在mybatis全局文件中的typeHandlers属性中注册这个类型转换器

<!--    typeHandlers类型处理器,1)	无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型-->
    <typeHandlers>
        <!-- 注册自定义handler,说明它作用的jdbcType和javaType -->
        <typeHandler jdbcType="VARCHAR" javaType="Date" handler="Plugins.MyTypeHandler"/>
    </typeHandlers>

在接口中使用

package DAO;

import Entity.User;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.type.JdbcType;

import java.util.Date;
import java.util.List;

@Mapper
public interface UserDAO {

    //@Results将数据库中的字段和pojo中的属性映射,只有一个id(标识),和value(是一个Result[]数组),@Results注解必须和@Select注解一起使用
    //@Result具体映射
    @Select("select * from manage")
    @Results(id="userMap", value={
            @Result(column="id", property="id"),
            @Result(column="name", property="name"),
            @Result(column="date", property="date", javaType = Date.class, jdbcType = JdbcType.VARCHAR, typeHandler = Plugins.MyTypeHandler.class),
    })
    List<User> selectAll();

    //@ResultMap复用指定id的@Results描述的映射
    @Select("select * from manage where id = #{id}")
    @ResultMap("userMap")
    User selectById(int id) ;

    @Select("select * from manage where name = #{name}")
    @ResultMap("userMap")
    List<User> selectByName(String name);

    @Insert({"insert manage(id,name,date) values(#{id}, #{name}, #{date, typeHandler=Entity.MyTypeHandler})"})
    int insertUser(User user);

    @Update("update manage set name=#{name} where id=#{id}")
    int updateUserById(User user);

    @Delete("delete from manage where id = #{id}")
    int deleteUserById(int id);

}

5.ObjectFactory对象工厂

在 MyBatis 中,当其 sql 映射配置文件中的 sql 语句所得到的查询结果,被动态映射到 resultType 或其他处理结果集的参数配置对应的 Java 类型,其中就有 JavaBean 等封装类。而 objectFactory 对象工厂就是用来创建实体对象的类。

在 MyBatis 中,默认的 objectFactory 要做的就是实例化查询结果对应的目标类,有两种方式可以将查询结果的值映射到对应的目标类,一种是通过目标类的默认构造方法,另外一种就是通过目标类的有参构造方法。

有时候在 new 一个新对象(构造方法或者有参构造方法),在得到对象之前需要处理一些逻辑,或者在执行该类的有参构造方法时,在传入参数之前,要对参数进行一些处理,这时就可以创建自己的 objectFactory 来加载该类型的对象。

自定义对象工厂只需要继承DefaultObjectFactory,并重写create,setProperties,isCollection等方法

package MyConfig;

import java.util.Collection;
import java.util.Iterator;
import java.util.Properties;
import Entity.User;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;

public class MyObjectFactory extends DefaultObjectFactory {

    // 反射,创建对象
    @Override
    public Object create(Class type) {
        //意思一下,就添加一个逻辑,判断该对象如果是User类型的,直接转换为User类型
        if (type.equals(User.class)) {
            User p = (User) super.create(type);
            System.out.println(p.toString());
            return p;
        }
        return super.create(type);
    }

    // 处理配置文件中ObjectFactory属性的property子属性,并打印
    @Override
    public void setProperties(Properties properties) {
        Iterator iterator = properties.keySet().iterator();
        while (iterator.hasNext()) {
            String keyValue = String.valueOf(iterator.next());
            System.out.println(properties.getProperty(keyValue));
        }
        super.setProperties(properties);
    }

    @Override
    public <T> boolean isCollection(Class<T> type) {
        return Collection.class.isAssignableFrom(type);
    }

}

然后在mybatis全局配置文件中设置objectFactory属性

<objectFactory type="MyConfig.MyObjectFactory"/>

6. objectWrapperFactory对象加工工厂

MyBatis 提供在构造对象的时候,对于指定的对象进行特殊的加工

mybatis反射包中提供objectWrapperFactory接口的默认实现类DefaultObjectWrapperFactory,自定义对象加功工厂只需要继承DefaultObjectWrapperFactory重写其中的hasWrapperFor和getWrapperFor方法,或者实现ObjectWrapperFactory接口实现其中的hasWrapperFor和getWrapperFor方法

package MyConfig;


import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapper;

// 自定义对象加工工厂,这里不添加其他功能,就意思一下,很少用
public class MyObjectWrapperFactory extends DefaultObjectWrapperFactory {
    
    @Override
    public boolean hasWrapperFor(Object object) {
        return super.hasWrapperFor(object);
    }

    @Override
    public ObjectWrapper getWrapperFor(MetaObject metaObject, Object object) {
        return super.getWrapperFor(metaObject, object);
    }
}

然后在mybatis全局配置文件中objectWrapperFactory属性中注册MyObjectWrapperFactory 

<!--    对象加工工厂-->
    <objectWrapperFactory type="MyConfig.MyObjectWrapperFactory"/>

7. reflectorFactory 反射工厂

MyBatis 用于缓存 Reflector 的功能,ReflectorFactory 接口提供三个方法,mybatis反射包中提供ReflectorFactory 接口的默认实现类DefaultReflectorFactory

package org.apache.ibatis.reflection;

public interface ReflectorFactory {
	// 此 Class 的 Reflector 是否需要缓存
    boolean isClassCacheEnabled();
	// 设置 Class 的 Reflector 是否需要缓存
    void setClassCacheEnabled(boolean classCacheEnabled);
	// 找到对应 Class 的 Reflector
    Reflector findForClass(Class<?> type);
}

//
package org.apache.ibatis.reflection;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class DefaultReflectorFactory implements ReflectorFactory {
    // 默认开启缓存Class的Reflector
    private boolean classCacheEnabled = true;
    private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap();

    public DefaultReflectorFactory() {
    }

    public boolean isClassCacheEnabled() {
        return this.classCacheEnabled;
    }

    public void setClassCacheEnabled(boolean classCacheEnabled) {
        this.classCacheEnabled = classCacheEnabled;
    }

    public Reflector findForClass(Class<?> type) {
        return this.classCacheEnabled ? (Reflector)this.reflectorMap.computeIfAbsent(type, Reflector::new) : new Reflector(type);
    }
}

自定义反射工厂只需要继承DefaultReflectFactory或者实现ReflectFactory

package MyConfig;

import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.Reflector;

// 自定义反射工厂
public class MyReflectorFactory extends DefaultReflectorFactory {

    @Override
    public boolean isClassCacheEnabled() {
        return super.isClassCacheEnabled();
    }

    @Override
    public void setClassCacheEnabled(boolean classCacheEnabled) {
        super.setClassCacheEnabled(classCacheEnabled);
    }

    @Override
    public Reflector findForClass(Class<?> type) {
        return super.findForClass(type);
    }
}

然后在mybatis全局配置文件中reflectFactory属性中注册MyObjectWrapperFactory 

<!--    反射工厂-->
    <reflectorFactory type="MyConfig.MyReflectorFactory"/>

8. plugins 插件机制,设置拦截器

插件,用于在执行相关操作时,在执行前后插入自定义行为,如缓存,分页等,可指定多个插件,每个插件可拦截指定方法,可以在不修改原来的代码的情况下,通过拦截的方式,改变四大核心对象(Executor、StatementHandler、ParameterHandler、ResultSetHandler)的行为,比如处理参数,处理SQL,处理结果,让我们可以根据自己的需要去增强MyBatis 的功能(代理模式的体现)

图片来自https://www.cnblogs.com/wuzhenzhao/p/11120848.html

自定义拦截器

package MyConfig;

import org.apache.ibatis.builder.StaticSqlSource;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Properties;

//需要拦截的方法
@Intercepts({
        @Signature(type = Executor.class,method = "query",
                args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class,method = "query",
                args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}
)})

//自定义拦截器,实现分页
public class MyInterceptor implements Interceptor {

    // 用于覆盖被拦截对象的原有方法(在调用代理对象Plugin 的invoke()方法时被调用)
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("将逻辑分页改为物理分页");
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0]; // MappedStatement
        BoundSql boundSql = ms.getBoundSql(args[1]); // Object parameter
        RowBounds rb = (RowBounds) args[2]; // RowBounds
        // RowBounds为空,无需分页
        if (rb == RowBounds.DEFAULT) {
            return invocation.proceed();
        }// 在SQL后加上limit语句
        String sql = boundSql.getSql();
        String limit = String.format("LIMIT %d,%d", rb.getOffset(), rb.getLimit());
        sql = sql + " " + limit;

        // 自定义sqlSource
        SqlSource sqlSource = new StaticSqlSource(ms.getConfiguration(), sql, boundSql.getParameterMappings());

        // 修改原来的sqlSource
        Field field = MappedStatement.class.getDeclaredField("sqlSource");
        field.setAccessible(true);
        field.set(ms, sqlSource);

        // 执行被拦截方法
        return invocation.proceed();
    }

    // target 是被拦截对象,这个方法的作用是给被拦截对象生成一个代理对象,并返回它
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }


    // 设置拦截器配置的参数
    @Override
    public void setProperties(Properties properties) {
        Iterator iterator = properties.keySet().iterator();
        while (iterator.hasNext()) {
            String keyValue = String.valueOf(iterator.next());
            System.out.println(properties.getProperty(keyValue));
        }
    }
}

然后在mybatis全局配置中plugins属性中注册该拦截器(可以注册多个拦截器)

<!--    plugins 插件机制, 设置拦截器, 通过动态代理机制,可以介入SqlSession四大重要的对象:
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)
这些方法的执行
-->
    <plugins>
        <plugin interceptor="MyConfig.MyInterceptor"></plugin>
    </plugins>

9.environments 数据库环境

MyBatis可以配置多种环境,比如开发、测试和生产环境需要有不同的配置,每种环境使用一个environment标签进行配置并指定唯一标识符,environments通过default属性指定默认的数据库环境

environment-指定具体环境

id:指定当前环境的唯一标识

transactionManager:

         type:  JDBC | MANAGED | 自定义

                    JDBC:使用了 JDBC 的提交和回滚设置,依赖于从数据源得到的连接来管理事务范围,JdbcTransactionFactory;

                    MANAGED:不提交或回滚一个连接、让容器来管理事务的整个生命周期,ManagedTransactionFactory;

                    自定义:实现TransactionFactory接口,type=全类名/别名.

dataSource

        type:  UNPOOLED | POOLED | JNDI | 自定义

                     UNPOOLED:不使用连接池, UnpooledDataSourceFactory;

                     POOLED:使用连接池, PooledDataSourceFactory;

                     JNDI: 在EJB 或应用服务器这类容器中查找指定的数据源;

                     自定义:实现DataSourceFactory接口,定义数据源的获取方式。

 <!--   数据库连接环境的配置,可以写多个数据库环境,比如开发、测试和生产环境需要有不同的配置,以id标识,default设置默认使用的数据库环境id -->
    <environments default="development">
        <environment id="development">
            <!--使用JDBC事务管理器-->
            <transactionManager type="JDBC"/>
            <!--配置数据库连接池的信息 -->
            <dataSource type="POOLED">
                <!--使用${}获取配置文件db.properties中配置的字段 -->
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${name}"/>
                <property name="password" value="${pass}"/>
            </dataSource>

        </environment>
    </environments>

10. databaseIdProvider数据库厂商标识

<!--    databaseIdProvider数据库厂商标识-->
    <databaseIdProvider type="DB_VENDOR">
<!--        name:数据库厂商标识, value:别名-->
        <property name="MySQL" value="mysql"/>
    </databaseIdProvider>

11. mappers 映射器

用来在mybatis初始化的时候,告诉mybatis需要引入哪些Mapper映射文件

resource : 引入类路径下的文件

url :      引入网络路径或者是磁盘路径下的文件

         class :    引入Mapper接口.

                   有SQL映射文件 , 要求Mapper接口与 SQL映射文件同名同位置.

                   没有SQL映射文件 , 使用注解在接口的方法上写SQL语句.

<!--    引入映射文件-->
    <mappers>
<!--        使用.xml映射文件-->
<!--        <mapper resource="Mapper.xml" />-->
<!--        引用包下指定的mapper接口或则批量扫描包下所有的mapper接口-->
        <mapper class="DAO.UserDAO"/>
<!--        <package name="DAO"/>-->

XMLConfigBuilder将Mybatis全局配置文件.xml中设置的节点提取赋给Configuration对象

首先读取Mybatis全局配置文件.xml的字节流数据inputStream,然后通过SqlSessionFactoryBuilder(建造者模式)创建SqlSessionFactory对象(内部维护一个Configuration对象),下面是SqlSessionFactoryBuilder的build方法中的关键代码:

    XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
    Configuration configuration = parser.parse();



//XMLConfigBuilder 

    // Configuration对象从BaseBuilder中继承
    public Configuration parse() {
        // 保证Configuration对象只创建一次
        if (this.parsed) {
            throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        } else {
            this.parsed = true;
            // 遍历所有的节点
            this.parseConfiguration(this.parser.evalNode("/configuration"));
            return this.configuration;
        }
    }

    // 遍历所有的节点
    private void parseConfiguration(XNode root) {
        try {
            // 提取properties属性节点,调用propertiesElement方法赋给Configuration对象
            this.propertiesElement(root.evalNode("properties"));
            // 提取settings设置节点,调用settingsElement方法赋给Configuration对象
            Properties settings = this.settingsAsProperties(root.evalNode("settings"));
            this.loadCustomVfs(settings);
            this.loadCustomLogImpl(settings);
            this.settingsElement(settings);
            // 提取typeAliases类型别名节点,调用typeAliasesElement方法赋给Configuration对象
            this.typeAliasesElement(root.evalNode("typeAliases"));
            // 提取typeHandlers类型转换器节点,调用typeHandlerElement方法赋给Configuration对象
            this.typeHandlerElement(root.evalNode("typeHandlers"));
            // 提取objectFactory对象工厂节点,调用objectFactoryElement方法赋给Configuration对象
            this.objectFactoryElement(root.evalNode("objectFactory"));
            // 提取objectWrapperFactory对象加工工厂节点,调用objectWrapperFactoryElement方法赋给Configuration对象
            this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
            // 提取reflectorFactory反射工厂节点,调用reflectorFactoryElement方法赋给Configuration对象
            this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
            // 提取plugins插件节点,调用pluginElement方法赋给Configuration对象
            this.pluginElement(root.evalNode("plugins"));
            // 提取environments数据库环境节点,调用environmentsElement方法赋给Configuration对象
            this.environmentsElement(root.evalNode("environments"));
            // 提取databaseIdProvider数据库厂商标识节点,调用databaseIdProviderElement方法赋给Configuration对象
            this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
            // 提取mappers映射器节点,调用mapperElement方法赋给Configuration对象
            this.mapperElement(root.evalNode("mappers"));
        } catch (Exception var3) {
            throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
        }
    }

比如提取数据库环境节点提取子节点等数据

// 提取environments数据库环境节点,调用environmentsElement方法赋给Configuration对象
            this.environmentsElement(root.evalNode("environments"));

private void environmentsElement(XNode context) throws Exception {
        if (context != null) {
            if (this.environment == null) {
                // 提取environments的default标签中标识的environment
                this.environment = context.getStringAttribute("default");
            }

            // 获取所有environment的迭代器
            Iterator var2 = context.getChildren().iterator();
            // 遍历所有environment
            while(var2.hasNext()) {
                XNode child = (XNode)var2.next();
                //environment的id属性标识一个唯一的environment
                String id = child.getStringAttribute("id");
                if (this.isSpecifiedEnvironment(id)) {
                    //transactionManager事务管理器
                    TransactionFactory txFactory = this.transactionManagerElement(child.evalNode("transactionManager"));
                    //dataSource配置数据库连接池的信息
                    DataSourceFactory dsFactory = this.dataSourceElement(child.evalNode("dataSource"));
                    DataSource dataSource = dsFactory.getDataSource();
                    //使用事务工厂txFactory和数据库工厂dsFactory创建environmentBuilder对象,提供Environment对象(建造者模式,提供封装数据库连接环境的Environment对象)
                    Builder environmentBuilder = (new Builder(id)).transactionFactory(txFactory).dataSource(dataSource);
                    // setter,将Environment对象赋给configuration
                    this.configuration.setEnvironment(environmentBuilder.build());
                }
            }
        }

    }

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值