当前位置: 代码迷 >> SQL >> ibatis 3.0 Dynamic Sql 设计解析(并与2.x的差别)
  详细解决方案

ibatis 3.0 Dynamic Sql 设计解析(并与2.x的差别)

热度:31   发布时间:2016-05-05 13:07:52.0
ibatis 3.0 Dynamic Sql 设计解析(并与2.x的差异)

前段时间ibatis3.0发布出来了,迫不及待,将其源码下载拜读。相对ibatis 2.x来说,3.0已是完全改变。具体我就不在这细说,论坛中有一个帖子介绍了ibatis 3.0的新特征及使用。

?? ? ?由于其他模块的源码我还未细读,在这篇中,先来讨论Dynamic Sql在ibatis 3.0中的实现并比较2.x对应模块的设计。

?

写在前头的话:

?? ? ?其实如从设计模式应用角度去看待ibatis 3.0中Dynamic Sql的实现,这篇跟我的上篇(HtmlParser设计解析(1)-解析器模式)相同,都是使用Interpreter模式。

?? ? ?这篇权当Interpreter模式的另一个demo,认我们体会这些开源项目中设计模式的使用。学习都是从模仿开始的,让 我们吸收高人们的经验,应用于我们实践项目需求中。

?

?? 从总结中提高:

?? 一、对比2.x中与3.0的Sqlmap中dynamic sql配置

?? 2.x:

Xml代码 复制代码?收藏代码
  1. <select?id="dynamicGetAccountList"?parameterClass="Account"?resultClass="Account">? ??
  2. ??????select?ACC_ID?as?id, ??
  3. ??????ACC_FIRST_NAME?as?firstName, ??
  4. ??????ACC_LAST_NAME?as?lastName, ??
  5. ??????ACC_EMAIL?as?emailAddress?from?ACCOUNT ??
  6. ?????? ??
  7. ????<dynamic?prepend="WHERE">??
  8. ??????<isNotNull?prepend="AND"?property="emailAddress">??
  9. ????????ACC_EMAIL?=?#emailAddress# ??
  10. ??????</isNotNull>??
  11. ??????<isNotNull?property="idList"?prepend="?or?ACC_ID?in?">??? ??
  12. ????????<iterate?property="idList"?conjunction=","?open="("?close=")"?>??? ??
  13. ????????????#id#?? ??
  14. ????????</iterate>??? ??
  15. ??????</isNotNull>??? ??
  16. ????</dynamic>??
  17. </select>??
<select id="dynamicGetAccountList" parameterClass="Account" resultClass="Account">       select ACC_ID as id,      ACC_FIRST_NAME as firstName,      ACC_LAST_NAME as lastName,      ACC_EMAIL as emailAddress from ACCOUNT	  	<dynamic prepend="WHERE">	  <isNotNull prepend="AND" property="emailAddress">        ACC_EMAIL = #emailAddress#      </isNotNull>      <isNotNull property="idList" prepend=" or ACC_ID in ">   		<iterate property="idList" conjunction="," open="(" close=")" >   			#id#  		</iterate>   	  </isNotNull>       </dynamic></select>

?

?? 3.0:

Xml代码 复制代码?收藏代码
  1. <select?id="dynamicGetAccountList"?parameterType="Account"?resultType="Account">??
  2. ??????select?ACC_ID?as?id, ??
  3. ??????ACC_FIRST_NAME?as?firstName, ??
  4. ??????ACC_LAST_NAME?as?lastName, ??
  5. ??????ACC_EMAIL?as?emailAddress?from?ACCOUNT ??
  6. ??
  7. ????<where>??
  8. ????????<if?test="emailAddress?!=?null">ACC_EMAIL?=?#{emailAddress}</if>??
  9. ????????<if?test="idList?!=?null">??
  10. ????????????or?ACC_ID?IN ??
  11. ????????????<foreach?item="id"?index="index"?open="("?close=")"?separator=","?collection="idList">??
  12. ????????????????#{idList[${index}]} ??
  13. ????????????</foreach>??
  14. ???????</if>??
  15. ????</where>??
  16. </select>??
<select id="dynamicGetAccountList" parameterType="Account" resultType="Account">	  select ACC_ID as id,	  ACC_FIRST_NAME as firstName,	  ACC_LAST_NAME as lastName,	  ACC_EMAIL as emailAddress from ACCOUNT	<where>		<if test="emailAddress != null">ACC_EMAIL = #{emailAddress}</if>		<if test="idList != null">			or ACC_ID IN			<foreach item="id" index="index" open="(" close=")" separator="," collection="idList">				#{idList[${index}]}			</foreach>	   </if>	</where></select>

?? ? ?从上面这个简单的比较中,第一感觉3.0了中其dynamic sql更加简洁明了。

?? ? ?其二,test="emailAddress != null" 添加了OGNL的解释支持,可以动态支持更多的判断,这将不限于原2.x中提供

的判断逻辑,更不需要为每个判断条件加个标签进行配置。

?? ? ?例如:<if test="id > 10 && id < 20"> ACC_EMAIL = #{emailAddress}</if>

?? ? ? ? ? ? ? <if test="Account.emailAddress != null "> ACC_EMAIL = #{emailAddress}</if> ……

?

?? 二、2.x Dynamic Sql的设计

?

???2.1、2.x中dynamic流程。

?? 这里帖出,我先前在分析ibatis 2.3时画的一个对dynamic sql的整体使用的时序图,可能会显得乱而复杂。

ibatis dynamic sequence

?? 2.2、主要类设计

?? ? ? 在这,我们只关注这几个类:XMLSqlSource、DynamicSql、SqlTagHandler (具体类结构图见后)

?? ? ?XMLSqlSource:相当于一个工厂类,其核心方法parseDynamicTags(),用于解析sql Tag,并判断是否是动态SQL标签。如果true,返回一个DynamicSql对象并创建多个SqlChildt对象添加至动态SQL列表中(addChild());false,返回RawSql对象(简单的SQL语句) 。

?? ? DynamicSql:核心的动态SQL类。其动态条件判断逻辑,参数映射等都发生在这个类中。

?? ? SqlTagHandle:动态条件判断接口,其每个动态SQL标签对应其一个子类。

??接下来,我们具体看下在DynamicSql类中核心方法。

?? ?DynamicSql:

Java代码 复制代码?收藏代码
  1. private?void?processBodyChildren(StatementScope?statementScope,?SqlTagContext?ctx,?Object?parameterObject,?Iterator?localChildren,?PrintWriter?out)?{ ??
  2. ????while?(localChildren.hasNext())?{?//XMLSqlSource?生成的动态SQL列表 ??
  3. ??????SqlChild?child?=?(SqlChild)?localChildren.next(); ??
  4. ??????if?(child?instanceof?SqlText)?{ ??
  5. ??????????...?...?//组装SQL语句及映射SQL参数 ??
  6. ??????}?else?if?(child?instanceof?SqlTag)?{ ??
  7. ????????SqlTag?tag?=?(SqlTag)?child; ??
  8. ????????SqlTagHandler?handler?=?tag.getHandler();?//得到动态SQL标签处理器 ??
  9. ????????int?response?=?SqlTagHandler.INCLUDE_BODY; ??
  10. ????????do?{?????????? ??
  11. ??????????response?=?handler.doStartFragment(ctx,?tag,?parameterObject);?//处理开始片段 ??
  12. ??????????if?(response?!=?SqlTagHandler.SKIP_BODY)?{?//是否跳过,意思该判断的条件为false ??
  13. ????????????processBodyChildren(statementScope,?ctx,?parameterObject,?tag.getChildren(),?pw);?//递归处理 ??
  14. ????????????StringBuffer?body?=?sw.getBuffer(); ??
  15. ????????????response?=?handler.doEndFragment(ctx,?tag,?parameterObject,?body);?//处理结束片段 ??
  16. ????????????handler.doPrepend(ctx,?tag,?parameterObject,?body);?//组装SQL ??
  17. ???????????? ??
  18. ??????????} ??
  19. ????????}?while?(response?==?SqlTagHandler.REPEAT_BODY); ??
  20. ????????...?...????} ??
  21. }??
private void processBodyChildren(StatementScope statementScope, SqlTagContext ctx, Object parameterObject, Iterator localChildren, PrintWriter out) {    while (localChildren.hasNext()) { //XMLSqlSource 生成的动态SQL列表      SqlChild child = (SqlChild) localChildren.next();      if (child instanceof SqlText) {          ... ... //组装SQL语句及映射SQL参数      } else if (child instanceof SqlTag) {        SqlTag tag = (SqlTag) child;        SqlTagHandler handler = tag.getHandler(); //得到动态SQL标签处理器        int response = SqlTagHandler.INCLUDE_BODY;        do {                    response = handler.doStartFragment(ctx, tag, parameterObject); //处理开始片段          if (response != SqlTagHandler.SKIP_BODY) { //是否跳过,意思该判断的条件为false            processBodyChildren(statementScope, ctx, parameterObject, tag.getChildren(), pw); //递归处理            StringBuffer body = sw.getBuffer();            response = handler.doEndFragment(ctx, tag, parameterObject, body); //处理结束片段            handler.doPrepend(ctx, tag, parameterObject, body); //组装SQL                      }        } while (response == SqlTagHandler.REPEAT_BODY);		... ...    }}

?

?? ?2.3、SqlTagHandle设计

?? ?首先看下SqlTagHandle处理类的结果图:


?

????ConditionalTagHandler:

Java代码 复制代码?收藏代码
  1. public?abstract?class?ConditionalTagHandler?extends?BaseTagHandler?{ ??
  2. ??...?... ??
  3. ??public?abstract?boolean?isCondition(SqlTagContext?ctx,?SqlTag?tag,?Object?parameterObject); ??
  4. ??
  5. ??public?int?doStartFragment(SqlTagContext?ctx,?SqlTag?tag,?Object?parameterObject)?{ ??
  6. ????ctx.pushRemoveFirstPrependMarker(tag); ??
  7. ????if?(isCondition(ctx,?tag,?parameterObject))?{ ??
  8. ??????return?SqlTagHandler.INCLUDE_BODY; ??
  9. ????}?else?{ ??
  10. ??????return?SqlTagHandler.SKIP_BODY; ??
  11. ????} ??
  12. ??} ??
  13. ??...?... ??
  14. }??
public abstract class ConditionalTagHandler extends BaseTagHandler {  ... ...  public abstract boolean isCondition(SqlTagContext ctx, SqlTag tag, Object parameterObject);  public int doStartFragment(SqlTagContext ctx, SqlTag tag, Object parameterObject) {    ctx.pushRemoveFirstPrependMarker(tag);    if (isCondition(ctx, tag, parameterObject)) {      return SqlTagHandler.INCLUDE_BODY;    } else {      return SqlTagHandler.SKIP_BODY;    }  }  ... ...}

?

???IsNullTagHandler:

Java代码 复制代码?收藏代码
  1. public?class?IsNullTagHandler?extends?ConditionalTagHandler?{ ??
  2. ????private?static?final?Probe?PROBE?=?ProbeFactory.getProbe(); ??
  3. ????public?boolean?isCondition(SqlTagContext?ctx,?SqlTag?tag,?Object?parameterObject)?{ ??
  4. ????????if?(parameterObject?==?null)?{ ??
  5. ????????????return?true; ??
  6. ????????}?else?{ ??
  7. ????????????String?prop?=?getResolvedProperty(ctx,?tag); ??
  8. ????????????Object?value; ??
  9. ????????????if?(prop?!=?null)?{ ??
  10. ????????????????value?=?PROBE.getObject(parameterObject,?prop); ??
  11. ????????????}?else?{ ??
  12. ????????????????value?=?parameterObject; ??
  13. ????????????} ??
  14. ????????????return?value?==?null; ??
  15. ????????} ??
  16. ????} ??
  17. }??
public class IsNullTagHandler extends ConditionalTagHandler {	private static final Probe PROBE = ProbeFactory.getProbe();	public boolean isCondition(SqlTagContext ctx, SqlTag tag, Object parameterObject) {		if (parameterObject == null) {			return true;		} else {			String prop = getResolvedProperty(ctx, tag);			Object value;			if (prop != null) {				value = PROBE.getObject(parameterObject, prop);			} else {				value = parameterObject;			}			return value == null;		}	}}

?? 至于其他的相关类,不在这列出了,有兴趣的可以找其源码了解下。

?

?? 2.4、总结ibatis 2.X Dynamic Sql 的设计

?? ? ?从上面的分析中,可以体会出作者的dynamic sql这模块的设计思路。从装载sqlmap.xml中各sql配置(时序图中的1步),通过工厂创建DynamicSql和RawSql(时序图中的3步),然后分发之不同的处理器。

?? ? ?在DynamicSql中则调用SqlTagHandle判断其条件(时序图中的10步)。而SqlTagHandle的设计使用策略者模式,让其不同的子类来处理这个判断逻辑。

?? ? ?通过一系列的加工,最终组装一个Sql对象,将值set至MappedStatement(时序图中的14步)中,然后MappedStatement对象执行executeQueryWithCallback查询数据(时序图中的17步),这儿会调用先前组装的Sql对象(时序图中的19步)。至于这其中的细节已不在这篇的研究这内。

?

?? ?三、3.0 Dynamic Sql的设计

?? ? ? ? ? 至于3.0其基本流程跟2.x是一样的,从装载 ?-> 参数映射 -> 执行SQL -> 返回结果。我们直接切入主题,分析是核心部分。先从一个简单的Dynamic Sql的测试用例开始。

?

?? 3.1、 测试用例

?? ?dynamic sql test:

Java代码 复制代码?收藏代码
  1. @Test??
  2. public?void?shouldTrimWHEREInsteadOfORForSecondCondition()?throws?Exception?{ ??
  3. ?/*?SELECT?*?FROM?BLOG ?
  4. ????<where> ?
  5. ????????<if?test="id?!=?false">?and?ID?=?#{id}?</if> ?
  6. ????????<if?test="name?!=?false">?or?NAME?=?#{name}?</if> ?
  7. ????</where> ?
  8. ???*/??
  9. ????final?String?expected?=?"SELECT?*?FROM?BLOG?WHERE??NAME?=??"; ??
  10. ????DynamicSqlSource?source?=?createDynamicSqlSource( ??
  11. ????????????new?TextSqlNode("SELECT?*?FROM?BLOG"),? ??
  12. ????????????????new?WhereSqlNode(mixedContents( ??
  13. ????????????????????????new?IfSqlNode( ??
  14. ????????????????????????????????mixedContents(new?TextSqlNode("???and?ID?=????")),"false"),?new?IfSqlNode(mixedContents(new?TextSqlNode("???or?NAME?=????")),?"true")))); ??
  15. ????BoundSql?boundSql?=?source.getBoundSql(null); ??
  16. ????assertEquals(expected,?boundSql.getSql()); ??
  17. } ??
  18. ??
  19. private?DynamicSqlSource?createDynamicSqlSource(SqlNode...?contents) ??
  20. ????????throws?IOException,?SQLException?{ ??
  21. ????createBlogDataSource(); ??
  22. ????final?String?resource?=??".../MapperConfig.xml"; ??
  23. ????final?Reader?reader?=?Resources.getResourceAsReader(resource); ??
  24. ????SqlSessionFactory?sqlMapper?=?new?SqlSessionFactoryBuilder() ??
  25. ????????????.build(reader); ??
  26. ????Configuration?configuration?=?sqlMapper.getConfiguration(); ??
  27. ????MixedSqlNode?sqlNode?=?mixedContents(contents); ??
  28. ????return?new?DynamicSqlSource(configuration,?sqlNode); ??
  29. } ??
  30. ??
  31. private?MixedSqlNode?mixedContents(SqlNode...?contents)?{ ??
  32. ????return?new?MixedSqlNode(Arrays.asList(contents)); ??
  33. }??
	@Test	public void shouldTrimWHEREInsteadOfORForSecondCondition() throws Exception {	 /*	SELECT * FROM BLOG		<where>			<if test="id != false"> and ID = #{id} </if>			<if test="name != false"> or NAME = #{name} </if>		</where>	   */		final String expected = "SELECT * FROM BLOG WHERE  NAME = ?";		DynamicSqlSource source = createDynamicSqlSource(				new TextSqlNode("SELECT * FROM BLOG"), 					new WhereSqlNode(mixedContents(							new IfSqlNode(									mixedContents(new TextSqlNode("   and ID = ?  ")),"false"), new IfSqlNode(mixedContents(new TextSqlNode("   or NAME = ?  ")), "true"))));		BoundSql boundSql = source.getBoundSql(null);		assertEquals(expected, boundSql.getSql());	}	private DynamicSqlSource createDynamicSqlSource(SqlNode... contents)			throws IOException, SQLException {		createBlogDataSource();		final String resource =  ".../MapperConfig.xml";		final Reader reader = Resources.getResourceAsReader(resource);		SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder()				.build(reader);		Configuration configuration = sqlMapper.getConfiguration();		MixedSqlNode sqlNode = mixedContents(contents);		return new DynamicSqlSource(configuration, sqlNode);	}	private MixedSqlNode mixedContents(SqlNode... contents) {		return new MixedSqlNode(Arrays.asList(contents));	}

?

??有经验的人,我想一眼就能看出其3.0中的设计思想,从Test中可以看出,或者我上一篇介绍的HtmlParser NodeFilter。

?? ?YES,在ibatis 3.0 dynamic sql设计正是应用了解释器模式,替换了原在这种需求下相对显得笨拙的策略者模式。

?

?? 下面具体看下类结构图。

?

?? 3.2、类结构图

?? SqlNode Class?Diagram:

?? SqlSource Class?Diagram:

?

?? 3.3、配置文件的解析

?? 在这,我就顺便提下ibatis解析组件对dynamic sql的解析方式,以代码见分晓吧。

?

???XMLStatementBuilder:

Java代码 复制代码?收藏代码
  1. public?void?parseStatementNode(XNode?context)?{ ??
  2. ???????????????...??... ??
  3. ????List<SqlNode>?contents?=?parseDynamicTags(context); ??
  4. ????MixedSqlNode?rootSqlNode?=?new?MixedSqlNode(contents);//再次包装dynamic?sql处理链 ??
  5. ????SqlSource?sqlSource?=?new?DynamicSqlSource(configuration,?rootSqlNode);?//默认初始化DynamicSqlSource ??
  6. ???????????????...?... ??
  7. ????builderAssistant.addMappedStatement(id,?sqlSource,?statementType, ??
  8. ????????????sqlCommandType,?fetchSize,?timeout,?parameterMap, ??
  9. ????????????parameterTypeClass,?resultMap,?resultTypeClass, ??
  10. ????????????resultSetTypeEnum,?flushCache,?useCache,?keyGenerator, ??
  11. ????????????keyProperty);?//将解析的所有属性构建成相应的对象存入全局的申明对象(MappedStatement)中,后面只传递该对象。 ??
  12. } ??
  13. ??
  14. private?List<SqlNode>?parseDynamicTags(XNode?node)?{ ??
  15. ????List<SqlNode>?contents?=?new?ArrayList<SqlNode>(); ??
  16. ????NodeList?children?=?node.getNode().getChildNodes(); ??
  17. ????for?(int?i?=?0;?i?<?children.getLength();?i++)?{ ??
  18. ????????XNode?child?=?node.newXNode(children.item(i)); ??
  19. ????????String?nodeName?=?child.getNode().getNodeName(); ??
  20. ????????if?(child.getNode().getNodeType()?==?Node.CDATA_SECTION_NODE ??
  21. ????????????????||?child.getNode().getNodeType()?==?Node.TEXT_NODE)?{ ??
  22. ????????????String?data?=?child.getStringBody(""); ??
  23. ????????????contents.add(new?TextSqlNode(data)); ??
  24. ????????}?else?{ ??
  25. ????????????NodeHandler?handler?=?nodeHandlers.get(nodeName); ??
  26. ????????????if?(handler?==?null)?{ ??
  27. ????????????????throw?new?BuilderException("Unknown?element?<"?+?nodeName?">?in?SQL?statement."); ??
  28. ????????????} ??
  29. ????????????handler.handleNode(child,?contents); ??
  30. ????????} ??
  31. ????} ??
  32. ????return?contents; ??
  33. }????????? ??
  34. private?Map<String,?NodeHandler>?nodeHandlers?=?new?HashMap<String,?NodeHandler>()?{ ??
  35. ????{ ??
  36. ????????put("where",?new?WhereHandler()); ??
  37. ????????put("set",?new?SetHandler()); ??
  38. ????????put("foreach",?new?ForEachHandler()); ??
  39. ????????put("if",?new?IfHandler()); ??
  40. ????????...?... ??
  41. ????} ??
  42. }; ??
  43. private?interface?NodeHandler?{ ??
  44. ????void?handleNode(XNode?nodeToHandle,?List<SqlNode>?targetContents); ??
  45. } ??
  46. private?class?WhereHandler?implements?NodeHandler?{ ??
  47. ????public?void?handleNode(XNode?nodeToHandle,?List<SqlNode>?targetContents)?{ ??
  48. ????????List<SqlNode>?contents?=?parseDynamicTags(nodeToHandle);//?遍历 ??
  49. ????????MixedSqlNode?mixedSqlNode?=?new?MixedSqlNode(contents);//对应测试用例中的mixedContents方法 ??
  50. ????????WhereSqlNode?where?=?new?WhereSqlNode(mixedSqlNode); ??
  51. ????????targetContents.add(where); ??
  52. ????} ??
  53. } ??
  54. private?class?IfHandler?implements?NodeHandler?{ ??
  55. ????public?void?handleNode(XNode?nodeToHandle,?List<SqlNode>?targetContents)?{ ??
  56. ????????List<SqlNode>?contents?=?parseDynamicTags(nodeToHandle);//遍历 ??
  57. ????????MixedSqlNode?mixedSqlNode?=?new?MixedSqlNode(contents); ??
  58. ????????String?test?=?nodeToHandle.getStringAttribute("test"); ??
  59. ????????IfSqlNode?ifSqlNode?=?new?IfSqlNode(mixedSqlNode,?test);//初始化对应的处理器 ??
  60. ????????targetContents.add(ifSqlNode);// ??
  61. ????} ??
  62. }?//?其他的Handle详见ibatis源码~??
	public void parseStatementNode(XNode context) {                ...  ...		List<SqlNode> contents = parseDynamicTags(context);		MixedSqlNode rootSqlNode = new MixedSqlNode(contents);//再次包装dynamic sql处理链		SqlSource sqlSource = new DynamicSqlSource(configuration, rootSqlNode); //默认初始化DynamicSqlSource                ... ...		builderAssistant.addMappedStatement(id, sqlSource, statementType,				sqlCommandType, fetchSize, timeout, parameterMap,				parameterTypeClass, resultMap, resultTypeClass,				resultSetTypeEnum, flushCache, useCache, keyGenerator,				keyProperty); //将解析的所有属性构建成相应的对象存入全局的申明对象(MappedStatement)中,后面只传递该对象。	}	private List<SqlNode> parseDynamicTags(XNode node) {		List<SqlNode> contents = new ArrayList<SqlNode>();		NodeList children = node.getNode().getChildNodes();		for (int i = 0; i < children.getLength(); i++) {			XNode child = node.newXNode(children.item(i));			String nodeName = child.getNode().getNodeName();			if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE					|| child.getNode().getNodeType() == Node.TEXT_NODE) {				String data = child.getStringBody("");				contents.add(new TextSqlNode(data));			} else {				NodeHandler handler = nodeHandlers.get(nodeName);				if (handler == null) {					throw new BuilderException("Unknown element <" + nodeName "> in SQL statement.");				}				handler.handleNode(child, contents);			}		}		return contents;	}         	private Map<String, NodeHandler> nodeHandlers = new HashMap<String, NodeHandler>() {		{			put("where", new WhereHandler());			put("set", new SetHandler());			put("foreach", new ForEachHandler());			put("if", new IfHandler());			... ...		}	};	private interface NodeHandler {		void handleNode(XNode nodeToHandle, List<SqlNode> targetContents);	}	private class WhereHandler implements NodeHandler {		public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {			List<SqlNode> contents = parseDynamicTags(nodeToHandle);// 遍历			MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);//对应测试用例中的mixedContents方法			WhereSqlNode where = new WhereSqlNode(mixedSqlNode);			targetContents.add(where);		}	}	private class IfHandler implements NodeHandler {		public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {			List<SqlNode> contents = parseDynamicTags(nodeToHandle);//遍历			MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);			String test = nodeToHandle.getStringAttribute("test");			IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);//初始化对应的处理器			targetContents.add(ifSqlNode);//		}	} // 其他的Handle详见ibatis源码~

?? ?上面是其解析代码的一部分,我想从这几行代码中,可以看出作者的思想了(遍历XML各节点,以节点名查找相应对应的处理器,分发之该处理器执行"业务分析" — 策略者模式,这样在XML中定义了多少标签,这里就需要多少个类与之对应,但如果策略类太多,这种方式就显得笨拙了)。

?

?? ?以下就是其核心类的一部分源码,先看再说。

?? ?3.4、DynamicSqlSource(核心类)

Java代码 复制代码?收藏代码
  1. public?class?DynamicSqlSource?implements?SqlSource?{ ??
  2. ????public?DynamicSqlSource(Configuration?configuration,?SqlNode?rootSqlNode)?{ ??
  3. ????????this.configuration?=?configuration; ??
  4. ????????this.rootSqlNode?=?rootSqlNode; ??
  5. ????} ??
  6. ????public?BoundSql?getBoundSql(Object?parameterObject)?{ ??
  7. ????????DynamicContext?context?=?new?DynamicContext(parameterObject);//组装后的结果存储类 ??
  8. ????????rootSqlNode.apply(context);//调用SqlNode解释sql,并组装成完整的sql(SqlNode的客户端调用就在这) ??
  9. ????????SqlSourceBuilder?sqlSourceParser?=?new?SqlSourceBuilder(configuration); ??
  10. ????????Class?parameterType?=?parameterObject?==?null???Object.class?:?parameterObject.getClass(); ??
  11. ????????SqlSource?sqlSource?=?sqlSourceParser.parse(context.getSql(),?parameterType); ??
  12. ????????BoundSql?boundSql?=?sqlSource.getBoundSql(parameterObject); ??
  13. ????????for?(Map.Entry<String,?Object>?entry?:?context.getBindings().entrySet())?{ ??
  14. ????????????boundSql.setAdditionalParameter(entry.getKey(),?entry.getValue()); ??
  15. ????????} ??
  16. ????????return?boundSql; ??
  17. ????} ??
  18. }??
public class DynamicSqlSource implements SqlSource {	public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {		this.configuration = configuration;		this.rootSqlNode = rootSqlNode;	}	public BoundSql getBoundSql(Object parameterObject) {		DynamicContext context = new DynamicContext(parameterObject);//组装后的结果存储类		rootSqlNode.apply(context);//调用SqlNode解释sql,并组装成完整的sql(SqlNode的客户端调用就在这)		SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);		Class parameterType = parameterObject == null ? Object.class : parameterObject.getClass();		SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType);		BoundSql boundSql = sqlSource.getBoundSql(parameterObject);		for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {			boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());		}		return boundSql;	}}

?

?? 3.5、SqlNode

?

Java代码 复制代码?收藏代码
  1. public?interface?SqlNode?{ ??
  2. ????public?boolean?apply(DynamicContext?context); ??
  3. }??
public interface SqlNode {	public boolean apply(DynamicContext context);}

?

?? ?MixedSqlNode.class

Java代码 复制代码?收藏代码
  1. public?class?MixedSqlNode?implements?SqlNode?{ ??
  2. ????????...?.... ??
  3. ????public?boolean?apply(DynamicContext?context)?{ ??
  4. ????????//遍历组装的解析内容 ??
  5. ????????for?(SqlNode?sqlNode?:?contents)?{? ??
  6. ????????????//?转发至相关解释器处理 ??
  7. ????????????sqlNode.apply(context);? ??
  8. ????????} ??
  9. ????????return?true; ??
  10. ????} ??
  11. }??
public class MixedSqlNode implements SqlNode {        ... ....	public boolean apply(DynamicContext context) {		//遍历组装的解析内容		for (SqlNode sqlNode : contents) { 			// 转发至相关解释器处理			sqlNode.apply(context); 		}		return true;	}}

???IfSqlNode.class

Java代码 <
  相关解决方案