首先mybatis的官方给了我们三个代码去加载一个sqlSessionFactory
- String resource = “mybatis-config.xml”;
这一步我们获得了mybatis的核心配置文件的路径,之后会根据这个路径去加载一个流 - InputStream inputStream = Resources.getResourceAsStream(resource);
根据路径加载一个流 - 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对象,而这个对象包含了所有的配置信息