Mybatis源码学习(一)SqlSessionFactory

1.使用JAVA API 方式构建

JAVA API初始化的方式虽然不常用,但是相较于XML的方式可以更清楚的看到Configuration的构成,其示例如下:

PooledDataSource dataSource = new PooledDataSource();
dataSource.setDriver("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test?serverTimezone=GMT");
dataSource.setUsername("root");
dataSource.setPassword("root");
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(UmsMemberMapper.class);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

2.使用XML方式构建

2.1.获取InputStream

        【代码2-1】

InputStream inputStream = null;
try {
    inputStream =  Resources.getResourceAsStream("/mybatis-config.xml");
} catch (IOException e) {
    e.printStackTrace();
}

在代码2-1中将配置文件的路径传递给了Resource中的getResourceAsStream方法。我们下面来看看getResourceAsStream方法的详情

【代码2-2】org.apache.ibatis.io.Resources

public static InputStream getResourceAsStream(String resource) throws IOException {
    return getResourceAsStream((ClassLoader)null, resource);
}
public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
    InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);
    if (in == null) {
        throw new IOException("Could not find resource " + resource);
    } else {
        return in;
    }
}

代码【2-3】org.apache.ibatis.io.ClassLoaderWrapper

public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
    return this.getResourceAsStream(resource, this.getClassLoaders(classLoader));
}
InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
    ClassLoader[] var3 = classLoader;
    int var4 = classLoader.length;

    for(int var5 = 0; var5 < var4; ++var5) {
        ClassLoader cl = var3[var5];
        if (null != cl) {
            InputStream returnValue = cl.getResourceAsStream(resource);
            if (null == returnValue) {
                returnValue = cl.getResourceAsStream("/" + resource);
            }

            if (null != returnValue) {
                return returnValue;
            }
        }
    }

    return null;
}

        代码2-2的 getResourceAsStream方法都在org.apache.ibatis.io中的Resource类中,代码2-1中的代码调用了Resource类中的getResourceAsStream方法,Resource类中的getResourceAsStream方法最终调用了ClassLoaderWrapper的getResourceAsStream(String resource, ClassLoader[] classLoader),根据 配置文件的路径获取到配置文件的输入流。代码2-3给出了该方法的源码。

          代码2-3的getResourceAsStream方法会依次调用传入的每一个类加载器的getResourceAsStream方法来尝试获取配置文件的输入流。在尝试过程中如果失败的话,会在传入的地址前加入"/" 再试一次,只要尝试成功,即表明成功加载了指定的资源,会将所获得的输入流返回。

        整个过程中涉及的Resource类和ClassLoadWrapper均在Mybatis的io包中,这也印证了Resource类和ClassLoaderWrapper类是负责读写外部文件的。

补充说明:类加载器具有读取外部资源的能力,所以这里要借助的是类加载器的这种能力

2.2.配置信息读取

读取inputStream之后,然后进行的代码2-4的操作

【代码2-4】

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

代码2-4首先构造了一个SqlSessionFactoryBuilder对象,然后调用SqlSessionFactoryBuilder对象的build。然后返回SqlSessionFactory对象,build方法是有多个的,其中的核心代码如代码2-5所示

【代码2-5】

public SqlSessionFactory build(InputStream inputStream) {
    return this.build((InputStream)inputStream, (String)null, (Properties)null);
}
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);
}

build(InputStream inputStream, String environment, Properties properties)方法最核心的部分如代码2-6所示

【代码2-6】

XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
var5 = this.build(parser.parse());

这两行代码进行了三步操作

1.生成了一个XMLConfigBuilder对象

2.调用XMLConfigBuilder对象的parse方法,得到一个Configuration对象(因为parse方法的返回值是Configuration对象)

3.调用了SqlSessionFactoryBuilder的build方法,传入参数为Configuration对象

我们对上述三步进行追踪,首先找到XMLConfigBuilder类的parse方法,如代码2-7所示

【代码2-7】

public Configuration parse() {
    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;
    }
}

代码2-7核心部分为 this.parseConfiguration(this.parser.evalNode("/configuration"));,因为configuration节点是mybatis配置文件的根节点,因此这里是解析整个配置文件的入口。而parseConfiguration是解析配置文件的入口,parseConfiguration方法的详情如代码【2-8】所示

【代码2-8】

private void parseConfiguration(XNode root) {
    try {
        this.propertiesElement(root.evalNode("properties"));
        Properties settings = this.settingsAsProperties(root.evalNode("settings"));
        this.loadCustomVfs(settings);
        this.loadCustomLogImpl(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-8中,parseConfiguration方法依次解析了配置文件的configuration下的一级节点,各个子方法,每个子方法对应的是每一个一级节点,解析出来的信息都放到Configuration实例中。Configuration对象保存配置文件的所有设置信息,也保存映射文件的信息。

2.3 构造SqlSessionFactory

生成Configuration象之对后,之后进行的是代码2-9的操作

【代码2-9】

public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
}

        代码2-9返回的DefaultSqlSessionFactory对象,SqlSessionFactory是一个接口, DefaultSqlSessionFactory是实现SqlSessionFactory接口的实现类。

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 这一句解析就结束了,

总结

        通过上面的分析,Mybatis的初始化阶段已经分析完毕,在初始化阶段,Mybatis主要进行了以下几项工作:

        1.根据配置文件的位置,获取它的输入流InputStream。

        2.从配置文件的根节点开始,逐层解析配置文件,解析过程中不断把解析结果放进Configuration对象

        3.以配置好的Configuration对象为参数,获取一个SqlsessionFactory对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值