Mybatis1.插件接口。
在Mybatis中使用插件的時候,就必須實現Interceptor接口。
public interface Interceptor{
Objectintercept(Invocation invocation) throws Throwable;
Objectplugin (Object target);
voidsetProperties(Properties properties);
}
Intercept方法:插件的核心方法,它將直接覆蓋你所攔截對象原有的方法。參數Invocation對象,通過它可以反射調度原來對象的方法。
Plugin方法:target是攔截的對象,它的作用是給攔截對象生成一個代理對象,并返回它。為了方便Mybatis使用org.apache.ibatis.plugin.Plugin中的wrap靜態方法提供生成代理對象,我們往往使用plugin方法便可以生成一個代理對象。
setProperties方法:允許在plugin元素中配置所需要的參數,方便在插件初始化的時候就被調用一次,然后把插件對象存存入到配置中,以便以后在取出。
2. 插件的初始化
插件的初始化是在Mybatis初始化的時候完成的,這點可以通過XMLConfigBuilder中的代碼可以知道。
publicvoid pluginElment(XNode parent) throws Exception{
if(parent!=null){
for(XNode child:parent.getChildren()){
Stringinterceptor=child.getStringAtrribute("interceptor");
Propertiesproperties=child.getChildrenAsProperties();
Interceptor interceptorInstance=(Interceptor)resolveClass(interceptor).newInstance();
interceptorInstance.setProperties(properties);
Configuration.addInterceptor(interceptorInstance);
}
}
}
在解析配置文件的時候,在Mybatis的上下文初始化過程中,就開始讀入插件的節點和我們配置的信息,同時使用反射技術生成對應的插件實例,然后調用setProperties方法,設置我們配置的參數,然后將插件的實例保存到配置的對象中,以便以后的讀取和使用它。插件的初始化是在Mybatis的初始化的時候進行的初始化,而不是在使用的時候才被初始化,這樣可以提高性能。
3. 插件的代理和反射的設計
插件用的是責任鏈的模式實現的。
所謂責任鏈就是,一個對象在Mybatis中可能是四大對象(Excetor、StatementHandler、ParameterHandler、ResultHandler)中的一個,在多個角色中傳遞,處在責任鏈上的任何角色都有處理它的機會。
作用:讓每一個責任鏈上的角色都有機會去攔截這個對象,在將來有新的角色也可以輕松攔截請求對象,進行處理。
Mybatis的責任鏈是用interceptorChain去定義的。我們知道plugin方法是生成代理對象的方法,當它取出插件的時候從Configuration對象中去取出。從第一對象開始,將對象傳遞給plugin方法,然后返回一個代理;如果存在第二個插件,那么我們就拿到第一個代理對象,傳遞給plugin方法在返回第一代理對象的代理….一次類推,有多少個攔截器就生成多少個代理對象。
在初始化的時候,我們一個個的加載插件實例,并用setProperties方法進行初始化,我們可以使用Mybatis提供的Plugin.wrap方法來生成代理對象,在一層層的使用Invaction對象的proceed()方法來推動代理對象的運行。在多個插件的環境下,調度proceed()方法時,Mybatis總是從最后一個代理對象運行到第一代理對象,最后是真實被攔截的對象方法被運行。
4.常用的工具類—MeteObject
在Mybatis插件中常用到一個工具類是MeteObject。
作用:可以有效的讀取或者修改一些重要對象的屬性。
常用的方法:
MeteObject forObject(Object object,ObjectFactoryobjectFactory,ObjectWrapperFactory objectWrapperFactory);
用于封裝對象,這個是已經過時了,現在使用SystemMetaObject(Object obj)
Object getValue(String name)方法:用于獲取對象的屬性值,支持OGNL。
void setValue(String name,Object value)方法:用于修改對象的屬性值,支持OGNL。
在Mybatis對象中大量使用這個類進行包裝,包括四大對象,使得我們可以通過它來給四大對象的某些屬性賦值從而滿足我們的需要。
5. 插件的開發步驟
(1)確定需要攔截的簽名
A:確定要攔截的對象
Exector對象:執行SQL全過程,包含組裝參數,組裝結果集返回和執行SQL過程,都可以攔截,較為廣泛,一般在實際中用的不多。
StatementHandler對象:執行SQL的過程,我們可以重寫執行SQL的過程,實際常用攔截對象。
ParamterHandler對象:主要是攔截執行SQL的參數組裝,可以重寫組裝參數規則。
ResultSetHandler對象:主要是攔截執行結果的組裝,可以重寫組裝結果規則。
B:攔截的方法和參數
public interface StatementHandler{
Statementprepare(Connection connection)throws SQLException;
voidparameterize(Statement statement)throws SQLException;
void batch(Statement statement)throwsSQLException;
int update(Statementstatement)throws SQLException;
BoundSql getBoundSql();
ParameterHandlergetParameterHandler();
}
定義插件簽名
@Inteceptor({@signature(type=Statement.class,method=”prepare”,args={Connection.class})
})
Public class Myplugin implements Interceptor{
}
(2)實現攔截的方法
package com.zl.mybatis.test;
import java.util.Properties;
import org.apache.ibatis.executor.Executor;
importorg.apache.ibatis.mapping.MappedStatement;
importorg.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
/**
*@author fab
*
*/
@Intercepts({ @Signature(type =Executor.class, // 確定攔截的對象
method = "update", // 確定攔截的方法
args = { MappedStatement.class,Object.class }// 確定攔截的參數
) })
public class MyPlugin implementsInterceptor {
Propertiesprops = null;
/**
* 代替攔截對象方法的內容
* @param invocation
* 責任鏈對象
*/
@Override
publicObject intercept(Invocation invocation) throws Throwable {
//TODO Auto-generated method stub
System.out.println("before.......");
//如果當前代理的是一個非代理對象,那么它就回調用真實攔截對象的方法,如果不是它將會調度下一個插件代理對象的invoke方法
Objectobject = invocation.proceed();
System.out.println("after.....");
returnobject;
}
/***
* 生成對象的代理,這用常用Mybatis提供的Plugin類的wrap方法
* @param target
* 被代理的對象
*/
@Override
publicObject plugin(Object target) {
//TODO Auto-generated method stub
//使用Mybatis提供的Plugin類生成代理對象
System.out.println("調用生成代理對象.....");
returnPlugin.wrap(target, this);
}
/***
* 獲取插件配置的屬性,在Mybatis的配置文件里面去配置
* @param props Mybatis的配置參數
*
*/
@Override
publicvoid setProperties(Properties props) {
//TODO Auto-generated method stub
System.out.println(props.get("dbType"));
this.props= props;
}
}
(3)配置
配置插件:
(4) 運行結果
調用生成代理對象.....
before.......
調用生成代理對象.....
調用生成代理對象.....
調用生成代理對象.....
after.....
7.簡單說
Mybatis插件的實現方法:
需要實現Interceptor接口,實現三個方法。
public Object intercept(Invocation invocation);
作用:插件的具體實現的地方,這是最復雜的地方。
public Object plugin(Object target);
作用:利用Mybatis自身的Plugin的Wrap()方法來獲得代理對象。
public void setProperties(Properties props);
作用:初始化一些基本設置,這些配置在Mybatis的.xml文件中體現。
需要明確:攔截那個對象,攔截那個方法,攔截那個參數。
8.總結
使用插件應注意的六點:
(1) 能不用插件盡量不用插件,因為它將修改Mybatis的底層設計。
(2) 插件生成的是層層代理對象的責任鏈模式,通過反射方法運行,性能不高,所以減少插件就能減少代理,從而提高系統的性能。
(3) 編寫插件需要了解Mybatis的運行原理,了解四大對象及其方法的作用,準確判斷需要攔截什么對象,什么方法,參數是什么,才能確定簽名如何編寫。
(4) 在插件中往往需要讀取和修改Mybatis映射器的對象屬性,你需要熟練掌握關于Mybatis映射器內部組成的知識。
(5) 插件的編寫需要考慮全面,特別是多個插件層層代理的時候,要保證邏輯的正確性。
(6) 盡量小改動Mybatis底層的東西,以減少錯誤的發生。
看文倉www.kanwencang.com網友整理上傳,為您提供最全的知識大全,期待您的分享,轉載請注明出處。
歡迎轉載:http://www.kanwencang.com/bangong/20170211/100431.html
文章列表