在上一篇【MyBtais源码阅读】(一)从头开始 中我们提到了几个重要的对象,今天我们带着之前的疑问来探究一下Configuration这个对象。这个对象是贯穿了整个mybatis,到处可以看见它的身影。
String resource = "mybatis-config.xml";
//加载mybatis核心配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
//构建sqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行查询数据库
Job job = (Job)sqlSession.selectOne("org.example.dao.JobMapper.selectJob", 3);
System.out.println(job.toString());
这段代码很熟悉吧,对的,就是测试例子中的测试代码,用来查询数据库job表中的一条数据,但是在这整个测试代码中都没有看到Configuration,这又是怎么回事呢?我们仔细看来,代码中有一行是在加载核心配置文件成为一个InputStream,莫非这个核心配置文件就是我们需要的Configuration,但是此处加载仅仅只是把它作为一个流传入后面的构建sqlSessionFactory里面了,并没有看到我们想要的类似 new Configuration();这样的代码存在呢?于是我们带着疑问,逐步进入后面的代码。。。
没错, 我们正打算阅读的代码就是 SqlSessionFactoryBuilder,因为我们加载的配置文件以流的形式传入了build() 方法,因此,我们要探究Configuration,就必须要探究这个类。
我们细读这个类里面的属性和方法,发现这个类没有属性,只有一大堆的重载build方法。因此我们只能探究这个调用的build()方法了
//代码1
//上述代码调用的,指传入一个inputStream的build方法
public SqlSessionFactory build(InputStream inputStream) {
//此处调用重载的另一个build方法,只不过除了inputStream,默认值都是null
return build(inputStream, null, null);
}
//代码2
//上述代码调用的方法
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//从传入的inputStream(因为剩下两个参数都是null)构建一个XMLConfigBuilder
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//调用重载的build方法返回一个SqlSessionFactory
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
//代码3
//上述代码调用的方法
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
我们发现,在上述代码中,通过代码1调用代码2再调用代码3的过程中。我们发现在代码3的入参看到了我们需要的Configuration,于是我们仔细阅读发现是代码2里面的parser.parse() 方法返回的。因此我们可以确定,Configuration就是通过XMLConfigBuilder 里面的parse()方法构建完成的。因此我们需要进一步了解构建Configuration这个对象的XMLConfigBuilder。
XMLConfigBuilder结构如下
XMLConfigBuilder继承关系如下(仅仅只继承了BaseBuilder)
BaseBuilder 结构如下
我们通过阅读上述代码的源码和继承关系发现, XMLConfigBuilder只继承于BaseBuilder,而且在BaseBuilder里面发现了我们需要的Configuration,于是我们关注回到上述的代码2
//代码2
//上述代码调用的方法
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//从传入的inputStream(因为剩下两个参数都是null)构建一个XMLConfigBuilder
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
......
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
......
}
}
//代码a
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
//代码b
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
我们进入代码2, 携带三个参数的XMLConfigBuilder的构造函数代码a,其内部调用了私有的构造函数代码b,就在此时,我们发现了在代码b中,我们找到了我们需要的代码new Configuration(),它作为参数传入的BaseBuilder的构造函数,经过初步的探寻,我们终于找到了Configuration是在哪里创建的。但是仅仅找到是在哪里创建的就结束了吗?我的好奇心促使我想进一步的了解,在代码a中new XPathParser() 和 XMLMapperEntityResolver(),以及整个Configuration是做什么的。
总结:
1:经过上述代码探究,我们初步了解了Configuration是在XMLConfigBuilder中创建的
2:Configuration是作为BaseBuilder的一个属性储存了下来
【个人阅读源码,能力有限,望各方大佬有幸瞧见后能指点一二,如果有错误之处,我看到后会立马改正,谢谢🙏🙏🙏】