mybatis获得SqlSessionFactory对象的简单流程源码分析

首先mybatis的官方给了我们三个代码去加载一个sqlSessionFactory

  1. String resource = “mybatis-config.xml”;
    这一步我们获得了mybatis的核心配置文件的路径,之后会根据这个路径去加载一个流
  2. InputStream inputStream = Resources.getResourceAsStream(resource);
    根据路径加载一个流
  3. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    这句代码是重点,我们之后根据这句代码发掘源码

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

我们跟进这句代码的build方法,进入了SqlSessionFactoryBuilder这个类的build方法中,build主要是返回一个sqlSessionFactory 对象

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

发现这个方法调用了本类重载的build方法,我们继续跟进

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    SqlSessionFactory var5;//这句代码申明了要返回的SqlSessionFactory对象
    try {
        XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);//这里调用了XMLConfigBuilder类去解析输入流,等一下我们继续去分析源码
        var5 = this.build(parser.parse());//这里继续使用了重载的另一个build方法,传入的参数是一个Configuration类型的对象,这个对象包含了许多配置信息
    } catch (Exception var14) {
        throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
    } finally {
        ErrorContext.instance().reset();

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

    }

    return var5;//返回了SqlSessionFactory对象
}

发现主要调用了XMLConfigBuilder去解析配置文件,用了新的重载的build去返回了SqlSessionFactory对象

我们先去继续看XMLConfigBuilder这个类

public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
    this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}

这个构造方法调用了另一个构造方法,把输入流转换为另一个XPathParser对象,这里我们就不去深究里面的东西,直接看另一个构造方法

private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
    //这里我们知道,environment,props这两个对象是空的,直接看parser
    super(new Configuration());
    this.localReflectorFactory = new DefaultReflectorFactory();
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
}

发现调用了父类的构造方法,把参数都赋值给对象的变量了,这些参数包含了配置文件的所有信息,然后得到了一个XMLConfigBuilder 对象名为parser
我们回到下面这段代码

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;
}

我们发现parser调用了一个parse方法,我们去看看这个方法

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;
    }
}

我们可以看到这里做了一个限制,每个XMLConfigBuilder只能调用一次这个方法去获得configuration对象,这和我们的SqlSessionFactory工厂类有关,因为这个类最好只有一个对象,所有在这里在调用配置文件去创建SqlSessionFactory的时候做了一个限制
然后这里调用了parseConfiguration方法,这个方法大概做了把之前的加载的输入流,enviroment,properties做了一次整合,都放到了configuration里面

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);
    }
}

在这里我们可以看见,这个方法加载了所有配置文件的标签进了configuration里面,我们点进第一个propertiesElement方法里面去看看

private void propertiesElement(XNode context) throws Exception {
    if (context != null) {
        Properties defaults = context.getChildrenAsProperties();
        String resource = context.getStringAttribute("resource");
        String url = context.getStringAttribute("url");
        if (resource != null && url != null) {
            throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference.  Please specify one or the other.");
        }

        if (resource != null) {
            defaults.putAll(Resources.getResourceAsProperties(resource));
        } else if (url != null) {
            defaults.putAll(Resources.getUrlAsProperties(url));
        }

        Properties vars = this.configuration.getVariables();
        if (vars != null) {
            defaults.putAll(vars);
        }

        this.parser.setVariables(defaults);
        this.configuration.setVariables(defaults);
    }

}

发现了这个方法把properties标签的所有子标签如resource和url加载进去了,然后通过它们之一又去加载了properties文件的所有内容,然后把所有的内容都放在了parser和configuration这两个对象之中。
回到下面的方法

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);
    }
}

其他的方法应该和我们查看的propertiesElement这个方法一样,把数据都放在了parser和configuration中,主要是configuration这个对象
再回到下面这段代码

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;
    }
}

这个方法最后返回了configuconration这个对象,这个对象就存储了所有的配置信息,再回到引用这个对象的方法去

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;
}

var5 = this.build(parser.parse()); 在这句代码中传入了configuconration这个对象,用了另一个build方法,再去看看这个方法

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

发现使用了另一个类的构造方法,返回了一个DefaultSqlSessionFactory对象

public DefaultSqlSessionFactory(Configuration configuration) {
    this.configuration = configuration;
}

这是DefaultSqlSessionFactory这个类的构造方法,configuration属性获得了之前的configuration对象,而我们发现DefaultSqlSessionFactory这个类就是SqlSessionFactory这个接口的实现类。

至此我们就已经发现,我们得到的SqlSessionFactory对象其实是一个DefaultSqlSessionFactory对象,而这个对象包含了所有的配置信息

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值