Mybatis源码篇(一)—— mybatis配置文件解析概览

在开始看mybatis源码之前,我们先回顾一下,在mybatis实践篇(一)中的测试类:

public class mybatisTest {
 
    @Test
    public void test() throws IOException {
        String resource = "configuration.xml";
         //将配置文件转换为流文件
        InputStream stream = Resources.getResourceAsStream(resource); 
         //读取配置文件(主要讲解它)
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(stream);
 
        SqlSession sqlSession = build.openSession();
        ManMapper mapper = sqlSession.getMapper(ManMapper.class);
        Man man = mapper.selectMan("2");
        System.out.println(man.toString());
    } 

我们可以看到,读取配置文件的操作是在SqlSessionFactoryBuilder类中的build方法中完成的,那么我们就从这里开始:

SqlSessionFactoryBuilder:

public class SqlSessionFactoryBuilder {
    public SqlSessionFactoryBuilder() {
    }

    public SqlSessionFactory build(Reader reader) {
        return this.build((Reader)reader, (String)null, (Properties)null);
    }

    public SqlSessionFactory build(Reader reader, String environment) {
        return this.build((Reader)reader, environment, (Properties)null);
    }

    public SqlSessionFactory build(Reader reader, Properties properties) {
        return this.build((Reader)reader, (String)null, properties);
    }
      //Reader读取mybatis配置文件,传入构造方法
      //environment读取设置的数据库链接
      //properties 读取外部的配置文件
    public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
        SqlSessionFactory var5;
        try {
            XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
            var5 = this.build(parser.parse());
        } catch (Exception var14) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
        } finally {
            ErrorContext.instance().reset();

            try {
                reader.close();
            } catch (IOException var13) {
                ;
            }

        }

        return var5;
    }

    public SqlSessionFactory build(InputStream inputStream) {
        return this.build((InputStream)inputStream, (String)null, (Properties)null);
    }

    public SqlSessionFactory build(InputStream inputStream, String environment) {
        return this.build((InputStream)inputStream, environment, (Properties)null);
    }

    public SqlSessionFactory build(InputStream inputStream, Properties properties) {
        return this.build((InputStream)inputStream, (String)null, properties);
    }
      //inputstream读取mybatis配置文件,传入构造方法
      //environment读取设置的数据库链接
      //properties 读取外部的配置文件
    public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        SqlSessionFactory var5;
        try {
            XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
            //读取配置文件中的信息(重点分析的地方)
            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) {
        return new DefaultSqlSessionFactory(config);
    }
}

从SqlSessionFactoryBuilder 的源码源码中可以看出,其实它里面主要就是两个重载的方法:build(Reader reader, String environment, Properties properties) 读取Reader中配置文件信息;build(InputStream inputStream, String environment, Properties properties) 读取InputStream中配置文件信息。

而无论是Reader还是InputStream,都又作为参数传入了XMLConfigBuilder的构造方法中,然后在XMLConfigBuilder类中的成员方法parse()中进行解析。

XMLConfigBuilder:

XMLConfigBuilder的构造方法没有特别的地方,只是对象的初始化、属性赋值。我们重点看一下parse()方法:

Parse:

    public Configuration parse() {
        if (this.parsed) {
            throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        } else {
            this.parsed = true;
            //根节点configuration
            this.parseConfiguration(this.parser.evalNode("/configuration"));
            return this.configuration;
        }
    }

parse方法又调用了parseConfiguration

    private void parseConfiguration(XNode root) {
        try {
            //解析properties标签
            this.propertiesElement(root.evalNode("properties"));
            //解析settings标签
            Properties settings = this.settingsAsProperties(root.evalNode("settings"));
            this.loadCustomVfs(settings);
            this.loadCustomLogImpl(settings);
            //解析typeAliases标签(下面的我们就不解释了,到了这里都能看懂了吧)
            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);
        }
    }

还记得我们在Mybatis实践篇(四)中罗列过mybatis中的配置文件标签信息,包括顶级标签configuration在内的所有父级标签,如下:

  • configuration(配置)
    • properties(属性设置)
    • settings(mybatis行为设置) 
    • typeAliases(类型别名) 
    • typeHandlers(类型处理器,数据库中字段类型与java中属性类型映射) 
    • objectFactory(对象工厂,mybatis创建结果对象新实例时使用) 
    • plugins(插件) 
    • environments(环境配置)
      • environment(环境变量)
        • transactionManager(事务管理器)
        • dataSource(数据源)
    • databaseIdProvider(数据库厂商标识,解决多数据库兼容问题)
    • mappers(映射器,映射SQL语句) 

后面的章节中我们会选取几个标签解析的列子进行讲解。

你可能感兴趣的:(Mybatis)