通過檢視mybatis源碼,解決有疑惑的問題:
- 并不知道mybatis是不是這個執行流程;
- 即使是如上的流程,那麼為什麼根本沒有的屬性會被mybatis正常解析;
- 為什麼mybatis會去執行isValid方法而不去執行其他的方法。
寫在前面
《Docker+SpringBoot+Mybatis+thymeleaf的Java部落格系統開源啦》
由于開源了項目的緣故,很多使用了My Blog項目的朋友遇到問題也都會聯系我去解決,有的是把問題留在項目的issue裡提出,有的是在我的私人部落格裡留言,還有的則是直接添加我的qq來找我講自己遇到的問題,有些問題比較簡單直接就解決了,有些問題的解決記錄也留在issue記錄裡,有些則是網上有相關教程,而剩下問題的解決方案,如果時間允許我都會單獨的做一篇部落格來解答。
問題描述
當時的聊天記錄:
截圖中提到的代碼(節選):
ContentVoMapper.xml:
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
CommentVoExample:
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
...
問題整理:在GeneratedCriteria類中并沒有valid這一屬性,僅僅隻有一個
isValid()
方法,但是在Mapper檔案中mybatis的
<if test>
文法中,卻有
criteria.valid
的表達式,而且程式可以正常運作,這是怎麼回事呢?
思路整理
首先,我剛看到這個問題的時候也是有點懵,因為這個代碼其實不是我寫的,Mapper檔案是我通過Mybatis-Generator自動生成的,是以這段代碼我也是有點陌生的,哈哈哈哈。
但是看了一遍代碼之後,我覺得應該是mybatis根據valid屬性自動找到了isValid()方法,然後執行了邏輯判斷,當然,這都是個人感覺,沒什麼依據,隐隐約約覺得應該是這麼個道理。但是呢,畢竟這位朋友是來問問題的,我不能就簡簡單單的回複這麼一句話,而且是連我自己都不确定的答案。
疑惑的問題有:
- 并不知道mybatis是不是這個執行流程;
- 即使是如上的流程,那麼為什麼根本沒有的屬性會被mybatis正常解析;
- 為什麼mybatis會去執行
方法而不去執行其他的方法。isValid()
解決過程
帶着以上的問題和心中的不确定,我唯一能做的就是去檢視這部分過程的源碼了,最終也如願得到了答案,通過IDEA的debug功能得到了代碼的執行過程,可以自行執行檢視一下整個過程:
- 在
類中,擷取了IfSqlNode
标簽中表達式的值:if test
;criteria.valid
- 接着是在
類中解析到了需要操作的屬性值ObjectPropertyAccessor
類中的Criteria
valid
- 然後是在
類中得到了表達式對應執行的MethodOgnlRuntime
方法。isValid()
接下來就是執行方法并擷取傳回值了,就不再截圖了。
上面的前兩個問題就有了答案:
- 由
到執行<if test="criteria.valid">
方法的執行流程找到了,雖然過程較多但是幾個重要的節點就是以上三點,擷取Mapper表達式中的類名和屬性值,然後擷取需要執行的方法,最終實作整個功能。isValid()
- mybatis并沒有去關注是否存在這個屬性,而是根據屬性去找到對應的方法并執行。
至于第三個問題,我也做了一下擴充,如果其他帶有valid字元串的方法會不會也被執行到,結果是肯定回答,如圖:
将
isValid()
改為
getValid()
OgnlRuntime
類中得到了對應執行的Method
getValid()
方法
當兩個方法都存在時,會執行
isValid()
方法,因為
if test
需要的是一個boolean傳回值,當隻存在
getValid()
方法時,則會執行
getValid()
。
結語
首發于我的個人部落格。
如果有問題或者有一些好的創意,歡迎給我留言,也感謝向我指出項目中存在問題的朋友,關于這篇文章,特别感謝一下
@libinghui
代碼和這次的問題都是My Blog項目中的,如果你想繼續了解該項目可以檢視整個系列文章Java開源部落格My-Blog(SpringBoot+Docker)系列文章,也可以到我的GitHub倉庫或者開源中國代碼倉庫中檢視源碼及詳細的部署過程和使用文檔。
我曾七次鄙視自己的靈魂:
第一次,當它本可進取時,卻故作謙卑;
第二次,當它空虛時,用愛欲來填充;
第三次,在困難和容易之間,它選擇了容易;
第四次,它犯了錯,卻借由别人也會犯錯來寬慰自己;
第五次,它自由軟弱,卻把它認為是生命的堅韌;
第六次,當它鄙夷一張醜惡的嘴臉時,卻不知那正是自己面具中的一副;
第七次,它側身于生活的污泥中雖不甘心,卻又畏首畏尾。