SQL是怎样执行的呢?
SQL在执行之前,是怎么从xml中拿到的呢?然后放在哪里呢?带着这个疑问,我们debug下源码。
//加载配置文件
SqlSessionFactory sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);
其实sqlSessionFactory中就已经准备好SQL了。我们看下截图
SqlSessionFactory是个接口,有两个实现类,默认是DefaultSqlSessionFactory。先看下该类的结构
configuration,且是通过构造方法来赋值的。该类还有一个作用就是拿到sqlsession。
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
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.
}
}
}
重点看下XMLConfigBuilder的构造函数
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
//重点。这里会构造一个Configuration对象。
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
我们看下Configuration的源码。
先看下构造函数
public Configuration() {
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
...//删除一些代码
//注册一些类对应的别名。xml配置中可体现
//typeAliasRegistry这个属性是直接new,从而获取的。
}
现在我们进入parser.parse()
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
//解析xml
//--从根节点configuration
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
进入
//--此方法就是解析configuration节点下的子节点
//--由此也可看出,我们在configuration下面能配置的节点为以下10个节点
private void parseConfiguration(XNode root) {
try {
// 解析properties元素
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
//解析typeAliases节点
typeAliasesElement(root.evalNode("typeAliases"));
// plugins 节点解析
pluginElement(root.evalNode("plugins"));
//objectFactory 节点解析
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// 解析enviroments元素节点的方法
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
//解析typeHandlers节点
typeHandlerElement(root.evalNode("typeHandlers"));
//sql就是在这里产生的
// mappers 节点解析
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
进入
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
//如果mappers节点的子节点是package, 那么就扫描package下的文件, 注入进configuration
if ("package".equals(child.getName())) {
String mapperPackage = child.getStringAttribute("name");
configuration.addMappers(mapperPackage);
} else {
String resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
//resource, url, class 三选一
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
InputStream inputStream = Resources.getResourceAsStream(resource);
//mapper映射文件都是通过XMLMapperBuilder解析
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
ErrorContext.instance().resource(url);
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url == null && mapperClass != null) {
Class<?> mapperInterface = Resources.classForName(mapperClass);
configuration.addMapper(mapperInterface);
} else {
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
}
}
}
}
进入mapperParser.parse()
public void parse() {
if (!configuration.isResourceLoaded(resource)) {
configurationElement(parser.evalNode("/mapper"));
configuration.addLoadedResource(resource);
bindMapperForNamespace();
}
parsePendingResultMaps();
parsePendingCacheRefs();
parsePendingStatements();
}
进入到
public StaticSqlSource(Configuration configuration, String sql, List<ParameterMapping> parameterMappings) {
this.sql = sql;
this.parameterMappings = parameterMappings;
this.configuration = configuration;
}
此时已经拿到sql了