LanguageDriver主要用于构造SqlSource和ParameterHandler,从LanguageDriver在Mybatis中调用链路来看,Configuration#newParameterHandler通过调用LanguageDriver#createParameterHandler完成构建ParameterHandler,通过调用LanguageDriver#createSqlSource来完成构建SqlSource。
LanguageDriver接口一共只定义了createParameterHandler和两个createSqlSource方法,其结构也相当简单,Mybatis只实现了RawLanguageDriver和XMLLanguageDriver两个类,且RawLanguageDriver还继承自XMLLanguageDriver,如下图所示。
XMLLanguageDriver以XML打头就已经明确说明该实现主要是为了支持使用XML标签描述的动态SQL,其完整实现了LanguageDriver接口定义的三个方法,其中createParameterHandler方法的实现仅是通过DefaultParameterHandler构造函数构造了一个ParameterHandler,所以就不再做过多的讨论。
@Override
public ParameterHandler createParameterHandler(
MappedStatement mappedStatement,
Object parameterObject, BoundSql boundSql) {
return new DefaultParameterHandler(
mappedStatement, parameterObject, boundSql);
}
LanguageDriver接口定了两个createSqlSource方法从源代码来看二则唯一的区别就在于入参的第二个参数,一个接口定义所需要的XNode类型的script,另一个接口定义则需要String类型的script。Mybatis之所以这么设计,是因为一个方法是用于处理通过XML配置的SQL信息,另一个方法则用于处理通过注解配置的SQL信息。
从源代码来看,用于处理XML配置的SQL信息的createSqlSource方法逻辑相对清晰,
@Override
public SqlSource createSqlSource(
Configuration configuration,
XNode script, Class<?> parameterType) {
XMLScriptBuilder builder = new XMLScriptBuilder(
configuration, script, parameterType);
return builder.parseScriptNode();
}
XMLLanguageDriver使用XMLScriptBuilder来构建了SqlSource对象,由此可见XMLScriptBuilder的职责就是解析XML配置信息构建对应的SqlSource对象,如下源代码所示,XMLScriptBuilder的构造函数在完成对属性赋值之后,又通过initNodeHandlerMap方法初始化了一批针对XML配置标签的处理器。之后在调用XMLScriptBuilder#parseScriptNode方法时通过解析结果中的isDynamic来分别构建DynamicSqlSource和RawSqlSource。
public XMLScriptBuilder(
Configuration configuration,
XNode context, Class<?> parameterType) {
super(configuration);
this.context = context;
this.parameterType = parameterType;
initNodeHandlerMap();
}
private void initNodeHandlerMap() {
nodeHandlerMap.put("trim", new TrimHandler());
nodeHandlerMap.put("where", new WhereHandler());
nodeHandlerMap.put("set", new SetHandler());
nodeHandlerMap.put("foreach", new ForEachHandler());
nodeHandlerMap.put("if", new IfHandler());
nodeHandlerMap.put("choose", new ChooseHandler());
nodeHandlerMap.put("when", new IfHandler());
nodeHandlerMap.put("otherwise", new OtherwiseHandler());
nodeHandlerMap.put("bind", new BindHandler());
}
public SqlSource parseScriptNode() {
MixedSqlNode rootSqlNode = parseDynamicTags(context);
SqlSource sqlSource;
if (isDynamic) {
sqlSource = new DynamicSqlSource(configuration, rootSqlNode);
} else {
sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType);
}
return sqlSource;
}
处理注解配置的SQL信息的createSqlSource方法有两个处理分支,一个处理script文本中有”)
如果所传入的script文本中不包含