自己創(chuàng)一個demo,然后在:Student student = studentDao.queryById();打斷點
...
public static void main(String[] args) throws IOException {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory build = builder.build(Resources.getResourceAsReader("mybatis-config.xml"));
SqlSession sqlSession = build.openSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = studentDao.queryById();
System.out.println(student);
sqlSession.commit();
sqlSession.close();
}
...
1.可以看到它調用的是MapperProxy
2.進入到MapperProxy這里可以看到是invoke 該方法谷炸。
方法會先判斷該方法是不是一個object類榛臼。如果為true直接調用。為false的話從緩存調用器里調用該方法郁岩。
3.我們可以看看它是為false的搓劫。
MethodProxy中的邏輯代理
MapperProxy.invoke() 方法是代理對象的執(zhí)行入口,它會攔截所有非object類型的方法塑荒。而且針對每個方法都會調用cacheInvoked()方法獲取對應的MapperMethod對象国觉。并調用invoke()方法執(zhí)行對應的代理邏輯及目標方法酒贬。
從上圖可以看到DefaultMethodInvoker和PlainMethodInvoker都是MapperMethodInvoker的實現(xiàn)類又憨。
通過對 MapperProxy 的分析我們知道,MapperMethod 是最終執(zhí)行 SQL 語句的地方锭吨,同時也記錄了 Mapper 接口中的對應方法蠢莺,其核心字段也圍繞這兩方面的內(nèi)容展開。
** SqlCommand**
MapperMethod 的第一個核心字段是 command(SqlCommand 類型)零如,其中維護了關聯(lián) SQL 語句的相關信息躏将。在 MapperMethod$SqlCommand 這個內(nèi)部類中,通過 name 字段記錄了關聯(lián) SQL 語句的唯一標識考蕾,通過 type 字段(SqlCommandType 類型)維護了 SQL 語句的操作類型祸憋,這里 SQL 語句的操作類型分為 INSERT、UPDATE肖卧、DELETE蚯窥、SELECT 和 FLUSH 五種。
下面我們就來看看 SqlCommand 如何查找 Mapper 接口中一個方法對應的 SQL 語句的信息,該邏輯在 SqlCommand 的構造方法中實現(xiàn)拦赠,如下:
相對應的解析
//獲取接口對應的名稱
final String methodName = method.getName();
//獲取Mapper接口的類型
final Class<?> declaringClass = method.getDeclaringClass();
// 將Mapper接口名稱和方法名稱拼接起來作為SQL語句唯一標識巍沙,
// 到Configuration這個全局配置對象中查找SQL語句
// MappedStatement對象就是Mapper.xml配置文件中一條SQL語句解析之后得到的對象
MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
configuration);
if (ms == null) {
// 針對@Flush注解的處理
if (method.getAnnotation(Flush.class) != null) {
name = null;
type = SqlCommandType.FLUSH;
} else {
// 沒有@Flush注解,會拋出異常
throw new BindingException("Invalid bound statement (not found): "
+ mapperInterface.getName() + "." + methodName);
}
} else {
// 記錄SQL語句唯一標識
name = ms.getId();
// 記錄SQL語句的操作類型
type = ms.getSqlCommandType();
if (type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + name);
}
這里調用的 resolveMappedStatement() 方法不僅會嘗試根據(jù) SQL 語句的唯一標識從 Configuration 全局配置對象中查找關聯(lián)的 MappedStatement 對象荷鼠,還會嘗試順著 Mapper 接口的繼承樹進行查找句携,直至查找成功為止。具體實現(xiàn)如下: