mybatis 自定義實現(xiàn)攔截器插件Interceptor示例
首先熟悉一下Mybatis的執(zhí)行過程,如下圖:
類型
先說明Mybatis中可以被攔截的類型具體有以下四種:
1.Executor:攔截執(zhí)行器的方法。
2.ParameterHandler:攔截參數(shù)的處理。
3.ResultHandler:攔截結(jié)果集的處理。
4.StatementHandler:攔截Sql語法構(gòu)建的處理。
規(guī)則
Intercepts注解需要一個Signature(攔截點)參數(shù)數(shù)組。通過Signature來指定攔截哪個對象里面的哪個方法。@Intercepts注解定義如下:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Intercepts { /** * 定義攔截點 * 只有符合攔截點的條件才會進入到攔截器 */ Signature[] value(); }
Signature來指定咱們需要攔截那個類對象的哪個方法。定義如下:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({}) public @interface Signature { /** * 定義攔截的類 Executor、ParameterHandler、StatementHandler、ResultSetHandler當中的一個 */ Class<?> type(); /** * 在定義攔截類的基礎之上,在定義攔截的方法 */ String method(); /** * 在定義攔截方法的基礎之上在定義攔截的方法對應的參數(shù), * JAVA里面方法可能重載,故注意參數(shù)的類型和順序 */ Class<?>[] args(); }
標識攔截注解@Intercepts
規(guī)則使用,簡單實例如下:
@Intercepts({//注意看這個大花括號,也就這說這里可以定義多個@Signature對多個地方攔截,都用這個攔截器 @Signature( type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class}), @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}) })
說明:
@Intercepts:標識該類是一個攔截器;
@Signature:指明自定義攔截器需要攔截哪一個類型,哪一個方法;
- type:上述四種類型中的一種;
- method:對應接口中的哪類方法(因為可能存在重載方法);
- args:對應哪一個方法的入?yún)ⅲ?/p>
method
中對應四種的類型的方法:
攔截類型 | 攔截方法 |
---|---|
Executor | update, query, flushStatements, commit, rollback,getTransaction, close, isClosed |
ParameterHandler | getParameterObject, setParameters |
StatementHandler | prepare, parameterize, batch, update, query |
ResultSetHandler | handleResultSets, handleOutputParameters |
介紹
談到自定義攔截器實踐部分,主要按照以下三步:
實現(xiàn)org.apache.ibatis.plugin.Interceptor
接口,重寫以下方法:
public interface Interceptor { Object intercept(Invocation var1) throws Throwable; Object plugin(Object var1); void setProperties(Properties var1); }
添加攔截器注解@Intercepts{...}
。具體值遵循上述規(guī)則設置。
配置文件中添加攔截器。
intercept(Invocation invocation)
從上面我們了解到interceptor能夠攔截的四種類型對象,此處入?yún)?code>invocation便是指攔截到的對象。
舉例說明:攔截**StatementHandler#query(Statement st,ResultHandler rh)**方法,那么Invocation就是該對象。
plugin(Object target)
這個方法的作用是就是讓mybatis判斷,是否要進行攔截,然后做出決定是否生成一個代理。
@Override public Object plugin(Object target) { //判斷是否攔截這個類型對象(根據(jù)@Intercepts注解決定),然后決定是返回一個代理對象還是返回原對象。 //故我們在實現(xiàn)plugin方法時,要判斷一下目標類型,如果是插件要攔截的對象時才執(zhí)行Plugin.wrap方法,否則的話,直接返回目標本身。 if (target instanceof StatementHandler) { return Plugin.wrap(target, this); } return target; }
注意:每經(jīng)過一個攔截器對象都會調(diào)用插件的plugin方法,也就是說,該方法會調(diào)用4次。根據(jù)@Intercepts注解來決定是否進行攔截處理。
setProperties(Properties properties)
攔截器需要一些變量對象,而且這個對象是支持可配置的。
實戰(zhàn)
自定義攔截器
@Intercepts(value = {@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) public class MyInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); BoundSql boundSql = statementHandler.getBoundSql(); Object obj = boundSql.getParameterObject(); String sql = boundSql.getSql(); if (sql.trim().toUpperCase().startsWith("INSERT")) { ReflectUtil.setFieldValue(obj, "rev", 0); ReflectUtil.setFieldValue(obj, "createTime", new Date()); ReflectUtil.setFieldValue(obj, "operateTime", new Date()); ReflectUtil.setFieldValue(boundSql,"parameterObject", obj); } else if (sql.trim().toUpperCase().startsWith("UPDATE")) { sql = sql.replaceAll(" set ", " SET ") .replaceAll(" Set ", " SET ") .replaceAll(" SET ", " SET rev = rev+1, operate_time = NOW(), "); ReflectUtil.setFieldValue(boundSql,"sql", sql); } return invocation.proceed(); } @Override public Object plugin(Object o) { return Plugin.wrap(o, this); } @Override public void setProperties(Properties properties) { } }
主要看下核心代碼方法intercept()
:
這段代碼主要目的:攔截insert和update語句,利用反射機制,設置insert語句的參數(shù)rev(版本號,利用樂觀鎖),第一次查詢,故創(chuàng)建時間和操作時間相同;update是將版本號+1,統(tǒng)一修改其操作時間。
mybatis-config
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <plugins> <plugin interceptor="com.qxy.mybatis.interceptor.MyInterceptor"/> </plugins> </configuration>
application.yml
特別重要的一點,一定將mybatis-config中的對象注入到Sprint容器中,否則不會生效。
...//省略其他配置 mybatis: config-location: classpath:/mybatis-config.xml
ReflectUtil
...//省略其他配置 mybatis: config-location: classpath:/mybatis-config.xml
debug
上圖中能夠看到BoundSql對象中主要存儲的屬性值,所以我們自定義攔截器時,主要針對BoundSql的屬性值進行修改。
程序代碼沒有走到我們反射機制設置值的位置,測試createTime=null;
返回之前,看下BoundSql對象的值,創(chuàng)建時間已被賦值。
源代碼:https://github.com/stream-source
到此這篇關于mybatis 自定義實現(xiàn)攔截器插件Interceptor的文章就介紹到這了,更多相關mybatis 自定義實現(xiàn)攔截器插件Interceptor內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java如何使用JSR303校驗數(shù)據(jù)與自定義校驗注解
這篇文章主要介紹了Java如何使用JSR303校驗數(shù)據(jù)與自定義校驗注解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-09-09spring的構(gòu)造函數(shù)注入屬性@ConstructorBinding用法
這篇文章主要介紹了關于spring的構(gòu)造函數(shù)注入屬性@ConstructorBinding用法,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12Maven中的dependencyManagement 實例詳解
dependencyManagement的中文意思就是依賴關系管理,它就是為了能通更好統(tǒng)一管理項目的版本號和各種jar版本號,可以更加方便升級,解決包沖突問題,這篇文章主要介紹了Maven中的dependencyManagement 實例詳解,需要的朋友可以參考下2024-02-02