Mybatis 攔截器實現原理
標簽(空格分隔): mybatis
攔截器概述
- 像springmvc一樣,mybatis也提供了攔截器實現,只是他們攔截的對象不同。
- mybatis給Executor、StatementHandler、ResultSetHandler、ParameterHandler提供了攔截器功能,
- Executor提供了增刪改查的接口.
- StatementHandler負責處理Mybatis與JDBC之間Statement的交互.
- ResultSetHandler負責處理Statement執行后產生的結果集,生成結果列表.
- ParameterHandler是Mybatis實現Sql入參設置的對象。
- 攔截器采用了責任鏈模式,把請求發送者和請求處理者分開,各司其職。
立即開始
<plugins>
<plugin interceptor="com.tamguo.demo.interceptor.StatementInterceptor"></plugin>
</plugins>
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class StatementInterceptor implements Interceptor {
public Object intercept(Invocation invocation) throws Throwable {
System.out.println(" hello Statement interceptor !");
return invocation.proceed();
}
public Object plugin(Object target) {
Object wrap = Plugin.wrap(target, this);
return wrap;
}
public void setProperties(Properties properties) {
}
}
開始一個Statement攔截器,在mybatis-config.xml加入plugin配置,編寫一個StatementInterceptor類。這樣就已經完成了一個攔截器的編寫,該類會鏈接StatementHandler的prepare方法。
MyBatis 加載intercetor過程
pluginElement() 是Confiration中,解析XML並把interceptorInstance加入到interceptorChain。
private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
String interceptor = child.getStringAttribute("interceptor");
Properties properties = child.getChildrenAsProperties();
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
interceptorInstance.setProperties(properties);
configuration.addInterceptor(interceptorInstance);
}
}
}
到這里Confiration對象已經持有了一個InterceptorChain屬性, InterceptorChain中只有一個intercetor的list集合。
sqlSessionFactory.openSession(),會創建Executor、StatementHandler、ResultSetHandler、ParameterHandler對象。
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
executor = (Executor) interceptorChain.pluginAll(executor); 注意這一行代碼,executor在這里已經被修改成一個代理對象。