01-mybatis解析配置文件.md

2022-08-22
0 1,479
<?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>

  <!-- 标签必须按照这个顺序-->
  <!-- properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?-->

   <!-- settings -->
   <settings>
     <!-- 打开延迟加载的开关 -->
     <setting name="lazyLoadingEnabled" value="true"/>
     <!-- 将积极加载改为消极加载(即按需加载) -->
     <setting name="aggressiveLazyLoading" value="false"/>
     <!-- 打开全局缓存开关(二级缓存)默认值就是 true -->
     <setting name="cacheEnabled" value="true"/>
     <setting name="mapUnderscoreToCamelCase" value="true" />
   </settings>

    <!-- 别名定义 -->
   <typeAliases>
     <package name="cn.fzkj.entity"/>
   </typeAliases>

   <environments default="development">
     <environment id="development">
     <transactionManager type="JDBC"></transactionManager>
     <dataSource type="POOLED">
       <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
       <property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=utf8&amp;zeroDateTimeBehavior=convertToNull&amp;useSSL=true&amp;serverTimezone=Asia/Shanghai"/>
       <property name="username" value="root"/>
       <property name="password" value="root"/>
     </dataSource>
   </environment>
 </environments>


 <!-- 加载映射文件 -->
 <mappers>
   <!-- 通过 resource 方法一次加载一个映射文件 -->
   <mapper resource="mybatis/UserMapper.xml"/>
   <!-- 批量加载mapper -->
  <!-- <package name="cn.fzkj.mapper"/>-->
   </mappers>
</configuration>
public static void main(String[] args) {
    String resource = "mybatis-config.xml";
    SqlSession sqlSession = null;

    // 将xmybatis配置文件加载到内存
    try(InputStream in = Resources.getResourceAsStream(resource)){
        // 创建SqlSessionFactoryBuilder
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        // 创建SqlSessionFactory
        SqlSessionFactory factory = builder.build(in);
        // 创建SqlSession
        sqlSession = factory.openSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        System.out.println(mapper.selectUserById(2));
    }catch (Exception e) {
        e.printStackTrace();
    }finally {
        sqlSession.close();
    }
}

从这个简单的例子入手。

1、加载配置文件

Resources.getResourceAsStream(resource)
这一步会将mybaits的配置文件内容读进内存。

2、创建SqlSessionFactory

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。

现在从xml中创建了一个SqlSessionFactoryBuilder。然后会创建出SqlSessionFactory。

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    SqlSessionFactory var5;
    try {
        XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
        // 解析xml文件
        var5 = this.build(parser.parse()); 
    } catch (Exception var14) {
        throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
    } finally {
        ErrorContext.instance().reset();
 
        try {
            inputStream.close();
        } catch (IOException var13) {
        }
 
    }
 
    return var5;
}
public SqlSessionFactory build(Configuration config) {
     // 使用创建好的configuration对象创建出SqlSessionFactory
    return new DefaultSqlSessionFactory(config);
}

2.1、解析xml

parser.parse()方法最终会调用到parseConfiguration方法。这个方法中会解析再mybatis配置文件中的所有配置项,并初始化Configuration对象。

private void parseConfiguration(XNode root) {
    try {
        Properties settings = this.settingsAsPropertiess(root.evalNode("settings"));
        this.propertiesElement(root.evalNode("properties"));
        this.loadCustomVfs(settings);
        this.typeAliasesElement(root.evalNode("typeAliases"));
        this.pluginElement(root.evalNode("plugins"));
        this.objectFactoryElement(root.evalNode("objectFactory"));
        this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
        this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
        this.settingsElement(settings);
        this.environmentsElement(root.evalNode("environments"));
        this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
        this.typeHandlerElement(root.evalNode("typeHandlers"));
        this.mapperElement(root.evalNode("mappers"));
    } catch (Exception var3) {
        throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
    }
}

2.2、初始化Configuration对象

在this.settingsElement(settings);方法中会初始化Configuration对象中的setting配置项。

private void settingsElement(Properties props) throws Exception {
    this.configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
    this.configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
    this.configuration.setCacheEnabled(this.booleanValueOf(props.getProperty("cacheEnabled"), true));
    this.configuration.setProxyFactory((ProxyFactory)this.createInstance(props.getProperty("proxyFactory")));
    this.configuration.setLazyLoadingEnabled(this.booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
    this.configuration.setAggressiveLazyLoading(this.booleanValueOf(props.getProperty("aggressiveLazyLoading"), true));
    this.configuration.setMultipleResultSetsEnabled(this.booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
    this.configuration.setUseColumnLabel(this.booleanValueOf(props.getProperty("useColumnLabel"), true));
    this.configuration.setUseGeneratedKeys(this.booleanValueOf(props.getProperty("useGeneratedKeys"), false));
    this.configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
    this.configuration.setDefaultStatementTimeout(this.integerValueOf(props.getProperty("defaultStatementTimeout"), (Integer)null));
    this.configuration.setDefaultFetchSize(this.integerValueOf(props.getProperty("defaultFetchSize"), (Integer)null));
    this.configuration.setMapUnderscoreToCamelCase(this.booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
    this.configuration.setSafeRowBoundsEnabled(this.booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
    this.configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
    this.configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
    this.configuration.setLazyLoadTriggerMethods(this.stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
    this.configuration.setSafeResultHandlerEnabled(this.booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
    this.configuration.setDefaultScriptingLanguage(this.resolveClass(props.getProperty("defaultScriptingLanguage")));
    this.configuration.setCallSettersOnNulls(this.booleanValueOf(props.getProperty("callSettersOnNulls"), false));
    this.configuration.setUseActualParamName(this.booleanValueOf(props.getProperty("useActualParamName"), false));
    this.configuration.setLogPrefix(props.getProperty("logPrefix"));
    Class<? extends Log> logImpl = this.resolveClass(props.getProperty("logImpl"));
    this.configuration.setLogImpl(logImpl);
    this.configuration.setConfigurationFactory(this.resolveClass(props.getProperty("configurationFactory")));
}