在 MyBatis 中,代理物件是透過動態代理技術生成的物件,用於攔截對介面方法的呼叫並將這些呼叫轉發給相應的 SQL 對映檔案中的 SQL 語句執行。具體來說,代理物件是一個實現了某個介面的類例項,但這個例項的實際行為是在執行時動態生成的,而不是在編譯時固定的。
### 動態代理
在 Java 中,動態代理通常透過 `java.lang.reflect.Proxy` 類和 `InvocationHandler` 介面來實現。MyBatis 使用了這種機制來生成 Mapper 介面的代理物件。
### 代理物件的工作原理
1. **介面定義**:
定義一個 Mapper 介面,如 `UserMapper`。
```java
public interface UserMapper {
User getUserById(int id);
}
```
2. **MapperFactoryBean 建立代理物件**:
當 MyBatis 初始化時,`MapperFactoryBean` 會為每個 Mapper 介面建立一個代理物件。這個代理物件實現了 `UserMapper` 介面。
3. **代理物件攔截方法呼叫**:
當你透過代理物件呼叫 `getUserById` 方法時,實際的呼叫會被代理物件攔截。
4. **呼叫轉換**:
代理物件會將攔截到的方法呼叫轉換為對相應 SQL 對映檔案中的 SQL 語句的呼叫。具體步驟包括:
- 查詢與方法名匹配的 SQL 語句(如 XML 配置檔案中的 `<select>` 語句)。
- 將方法引數傳遞給 SQL 語句。
- 執行 SQL 語句。
- 將 SQL 執行結果對映為方法的返回型別(如 `User` 物件)。
### 代理物件的示例
以下是一個使用動態代理的簡單示例,以幫助理解代理物件的概念。
```java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 定義介面
interface UserMapper {
User getUserById(int id);
}
// 模擬 User 物件
class User {
private int id;
private String name;
// getters and setters
}
// 實現 InvocationHandler
class MapperInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 這裡可以新增對方法呼叫的攔截邏輯
System.out.println("Method " + method.getName() + " is called with args " + args[0]);
// 模擬返回結果
User user = new User();
user.setId((int) args[0]);
user.setName("John Doe");
return user;
}
}
public class Main {
public static void main(String[] args) {
// 建立代理物件
UserMapper userMapper = (UserMapper) Proxy.newProxyInstance(
UserMapper.class.getClassLoader(),
new Class[]{UserMapper.class},
new MapperInvocationHandler()
);
// 呼叫代理物件的方法
User user = userMapper.getUserById(1);
System.out.println("User: " + user.getName());
}
}
```
在這個示例中:
- `UserMapper` 是一個介面。
- `MapperInvocationHandler` 實現了 `InvocationHandler` 介面,定義瞭如何處理方法呼叫。
- 使用 `Proxy.newProxyInstance` 建立了一個 `UserMapper` 介面的代理物件。
- 當呼叫 `userMapper.getUserById` 方法時,實際的呼叫被 `MapperInvocationHandler` 攔截並處理。
在 MyBatis 中,類似的機制被用來攔截對 Mapper 介面方法的呼叫,並將這些呼叫轉換為對 SQL 對映檔案的操作。透過這種方式,MyBatis 實現了將 Java 方法呼叫與 SQL 語句執行的無縫整合。