配置文件解析主要用到XMLConfigBuilder(解析mybatis-config.xml) --> XMLMapperBuilder(解析mapper.xml) --> XMLStatementBuilder(解析mapper.xml中cache, resultMap等配置信息,包括处理sql语句中的include标签) -->XMLScriptBuilder(解析mapper.xml中insert update select delete等sql语句节点)
1. 每个SQL语句节点都会生成一个SqlSource,每个SqlSource中都会保存一个SqlNode,SqlNode中又有子的SqlNode(包括普通sql语句也是一个文本SqlNode(StaticTextSqlNode))
2. 对于每个SQL语句节点,不同Node的解析会使用不同的NodeHandler,XMLScriptBuilder中有一个内部接口NodeHandler,有多个实现类(IfNodeHandler, WhereNodeHandler, ChooseNodeHandler等), 这些实现类的作用就是处理SQL语句节点内部的每种不同的节点标签(如<if></if> <where></where>等)
3. 对于上边红色标示的处理include标签,是在XMLStatementBuilder中来做的,源码:
1 /** 2 * XMLStatmentBuilder 3 */ 4 public void parseStatementNode() { 5 //...处理属性 6 7 // Include Fragments before parsing 处理include标签 8 XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant); 9 includeParser.applyIncludes(context.getNode()); 10 11 // Parse selectKey after includes and remove them. 处理<selectKey>标签 12 processSelectKeyNodes(id, parameterTypeClass, langDriver); 13 14 // Parse the SQL (pre: <selectKey> and <include> were parsed and removed) 处理SQL语句和内部标签 15 //... 16 }
1 /** 2 * XMLIncludeTransformer 3 */ 4 public void applyIncludes(Node source) { 5 if (source.getNodeName().equals("include")) { 6 Node toInclude = findSqlFragment(getStringAttribute(source, "refid")); 7 applyIncludes(toInclude); 8 if (toInclude.getOwnerDocument() != source.getOwnerDocument()) { 9 toInclude = source.getOwnerDocument().importNode(toInclude, true); 10 } 11 source.getParentNode().replaceChild(toInclude, source); 12 while (toInclude.hasChildNodes()) { 13 toInclude.getParentNode().insertBefore(toInclude.getFirstChild(), toInclude); 14 } 15 toInclude.getParentNode().removeChild(toInclude); 16 } else if (source.getNodeType() == Node.ELEMENT_NODE) { 17 NodeList children = source.getChildNodes(); 18 for (int i=0; i<children.getLength(); i++) { 19 applyIncludes(children.item(i)); 20 } 21 } 22 }
1 /** 2 * XMLStatmentBuilder 3 */ 4 private void processSelectKeyNodes(String id, Class<?> parameterTypeClass, LanguageDriver langDriver) { 5 List<XNode> selectKeyNodes = context.evalNodes("selectKey"); 6 if (configuration.getDatabaseId() != null) { 7 parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, configuration.getDatabaseId()); 8 } 9 parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, null); 10 removeSelectKeyNodes(selectKeyNodes); 11 }