mybatis+mybatisplus源码学习(⼗⼆)XMLLanguageDriver ⽬录
前⾔
XMLLanguageDriver⽤于对sql脚本进⾏解析,解析各种标签。
⼀、初始化
(1)createSqlSource( )
@Override
public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType){
// issue #3
if(script.startsWith("<script>")){
//xPath解析器
XPathParser parser = new XPathParser(script, false, Variables(), new XMLMapperEntityResolver());
//解析sql脚本中的标签
return createSqlSource(configuration, parser.evalNode("/script"), parameterType);
}else{
// issue #127
//处理⽂本格式的sql
script = PropertyParser.parse(script, Variables());
TextSqlNode textSqlNode = new TextSqlNode(script);
if(textSqlNode.isDynamic()){
return new DynamicSqlSource(configuration, textSqlNode);
}else{
return new RawSqlSource(configuration, script, parameterType);
}
}
}
(2)createSqlSource( )
public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType){
//创建XMLScriptBuilder ,初始化NodeHandler
XMLScriptBuilder builder = new XMLScriptBuilder(configuration, script, parameterType);
return builder.parseScriptNode();
}
(3)初始化NodeHandler
9种NodeHandler,⽤于处理sql脚本中9种不同的标签
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());
}
(4)parseScriptNode( )
public SqlSource parseScriptNode(){
//解析动态标签
MixedSqlNode rootSqlNode =parseDynamicTags(context);
SqlSource sqlSource;
if(isDynamic){
//动态sql
sqlSource = new DynamicSqlSource(configuration, rootSqlNode);
}else{
resultset 遍历//静态sql
sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType); }
return sqlSource;
}
⼆、解析标签
(1)MixedSqlNode
public class MixedSqlNode implements SqlNode {
//包含多个SqlNode
private final List<SqlNode> contents;
public MixedSqlNode(List<SqlNode> contents){
}
@Override
public boolean apply(DynamicContext context){
//遍历每个SqlNode
contents.forEach(node -> node.apply(context));
return true;
}
}
(2)parseDynamicTags( )
protected MixedSqlNode parseDynamicTags(XNode node){
List<SqlNode> contents = new ArrayList<>();
NodeList children = Node().getChildNodes();
for(int i =0; i < Length(); i++){
XNode child = wXNode(children.item(i));
Node().getNodeType()== Node.CDATA_SECTION_NODE || Node().getNodeType()== Node.TEXT_NODE){ String data = StringBody("");
//动态⽂本TextSqlNode,包含#{}
TextSqlNode textSqlNode = new TextSqlNode(data);
if(textSqlNode.isDynamic()){
contents.add(textSqlNode);
isDynamic = true;
}else{
//静态⽂本StaticTextSqlNode
contents.add(new StaticTextSqlNode(data));
}
}else Node().getNodeType()== Node.ELEMENT_NODE){// issue #628
//如果是字标签
String nodeName = Node().getNodeName();
//到对应的NodeHandler
NodeHandler handler = (nodeName);
if(handler == null){
throw new BuilderException("Unknown element <"+ nodeName +"> in SQL statement.");
}
//解析字标签
handler.handleNode(child, contents);
isDynamic = true;
}
}
return new MixedSqlNode(contents);
}
其实,就是⼀个递归解析字标签的过程,标签之间可以多层次嵌套,⼀直递归解析直到解析成静态⽂本或动态⽂本。
(3)IfHandler
解析if标签
public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents){
//递归解析标签
MixedSqlNode mixedSqlNode =parseDynamicTags(nodeToHandle);
String test = StringAttribute("test");
//构建IfSqlNode
IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);
targetContents.add(ifSqlNode);
}
}
其他的标签也是同样的⽅式,解析成对应的SqlNode,最终解析成分层次的树形结构MixedSqlNode。
三、获取sql
DynamicSqlSource动态sql的获取
public class DynamicSqlSource implements SqlSource {
private final Configuration configuration;
private final SqlNode rootSqlNode;
public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode){
}
@Override
public BoundSql getBoundSql(Object parameterObject){
DynamicContext context = new DynamicContext(configuration, parameterObject);
//1、通过SqlNode拼接sql,存放在context中
rootSqlNode.apply(context);
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
Class<?> parameterType = parameterObject == null ? Object.class : Class();
//2、解析成StaticSqlSource
SqlSource sqlSource = sqlSourceParser.Sql(), parameterType, Bindings());
BoundSql boundSql = BoundSql(parameterObject);
return boundSql;
}
1、解析${}
(1)IfSqlNode
public class IfSqlNode implements SqlNode {
private final ExpressionEvaluator evaluator;
private final String test;
private final SqlNode contents;
public IfSqlNode(SqlNode contents, String test){
this.evaluator = new ExpressionEvaluator();
}
@Override
public boolean apply(DynamicContext context){
//if条件判断
if(evaluator.evaluateBoolean(test, Bindings())){
/
/⼦标签,
contents.apply(context);
return true;
}
return false;
}
}
IfSqlNode ,在条件满⾜时,会调⽤if下的所有⼦标签,最终会调⽤到动态标签TextSqlNode或者静态标签StaticTextSqlNode。(2)TextSqlNode
拼接sql
public boolean apply(DynamicContext context){
//占位符解析器
GenericTokenParser parser =createParser(new BindingTokenParser(context, injectionFilter));
context.appendSql(parser.parse(text));
return true;
}
${}解析器
private GenericTokenParser createParser(TokenHandler handler){ return new GenericTokenParser("${","}", handler);
}
解析占位符
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论