最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MyBatis攔截器的實(shí)現(xiàn)原理

 更新時(shí)間:2022年08月22日 14:57:13   作者:CaptHua  
這篇文章主要介紹了MyBatis攔截器的實(shí)現(xiàn)原理,Mybatis攔截器并不是每個(gè)對象里面的方法都可以被攔截的,其具體內(nèi)容感興趣的小伙伴課題參考一下下面文章內(nèi)容

前言

Mybatis攔截器并不是每個(gè)對象里面的方法都可以被攔截的。Mybatis攔截器只能攔截Executor、StatementHandler、ParameterHandler、ResultSetHandler四個(gè)類里面的方法,這四個(gè)對象在創(chuàng)建的時(shí)候才會創(chuàng)建代理。

用途:實(shí)際工作中,可以使用Mybatis攔截器來做一些SQL權(quán)限校驗(yàn)、數(shù)據(jù)過濾、數(shù)據(jù)加密脫敏、SQL執(zhí)行時(shí)間性能監(jiān)控和告警等。

 1.使用方法

以在Spring中創(chuàng)建 StatementHandler.update()方法的攔截器為例:

@Component
@Order(1)
@Intercepts({@Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),})
public class SqlValidateMybatisInterceptor extends PRSMybatisInterceptor {
 
    @Override
    protected Object before(Invocation invocation) throws Throwable {
        String sql="";
        Statement statement=(Statement) invocation.getArgs()[0];
        if(Proxy.isProxyClass(statement.getClass())){
            MetaObject metaObject= SystemMetaObject.forObject(statement);
            Object h=metaObject.getValue("h");
            if(h instanceof StatementLogger){
                RoutingStatementHandler rsh=(RoutingStatementHandler) invocation.getTarget();
                sql=rsh.getBoundSql().getSql();
            }else {
                PreparedStatementLogger psl=(PreparedStatementLogger) h;
                sql=psl.getPreparedStatement().toString();
            }
        }else{
            sql=statement.toString();
        }
        if(containsDelete(sql)&&!containsWhere(sql)){
            throw new SQLException("不能刪除整張表,sql:"+sql);
        }
        return null;
    }
 
    private boolean containsDelete(String sql){
        return sql.contains("delete")||sql.contains("DELETE");
    }
 
    private boolean containsWhere(String sql){
        return sql.contains("where")||sql.contains("WHERE");
    }
}
public class PRSMybatisInterceptor implements Interceptor {
 
    Boolean needBreak=false;
 
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object result= before(invocation);
        if(needBreak){
            return result;
        }
        result= invocation.proceed();
        result=after(result,invocation);
        return result;
    }
 
    protected Object before(Invocation invocation) throws Throwable{
        return null;
    }
    protected Object after(Object result,Invocation invocation) throws Throwable{
        return result;
    }
    @Override
    public Object plugin(Object o) {
        return Plugin.wrap(o, this);
    }
    @Override
    public void setProperties(Properties properties) {
    }
}

1. 自定義攔截器 實(shí)現(xiàn) org.apache.ibatis.plugin.Interceptor 接口與其中的方法。在plugin方法中需要返回 return Plugin.wrap(o, this)。在intercept方法中可以實(shí)現(xiàn)攔截的業(yè)務(wù)邏輯,改方法的 參數(shù) Invocation中有原始調(diào)用的 對象,方法和參數(shù),可以對其任意處理。

2. 在自定義的攔截器上添加需要攔截的對象和方法,通過注解 org.apache.ibatis.plugin.Intercepts 添加。如示例代碼所示:

Intercepts的值是一個(gè)簽名數(shù)組,簽名中包含要攔截的 類,方法和參數(shù)。

2.MyBatis對象的創(chuàng)建

代理對象指的是:可以被攔截的4個(gè)類的實(shí)例。

代理對象創(chuàng)建時(shí)需要解析攔截器,從而利用JDK動態(tài)代理將攔截器的邏輯織入原始對象。

DefaultSqlSession中依賴Executor,如果新建的時(shí)候會創(chuàng)建executor

private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
    ...
    final Executor executor = configuration.newExecutor(tx, execType);
    return new DefaultSqlSession(configuration, executor, autoCommit);
}
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中要用StatementHandler執(zhí)行sql語句,StatementHandler是調(diào)用configuration.newStatementHandler()方法創(chuàng)建的。

StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
 
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
  statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
  return statementHandler;
}

StatementHandler依賴 parameterHandler 和 resultSetHandler,在構(gòu)造 StatementHandler 時(shí)會調(diào)用一下方法創(chuàng)建這兩個(gè) handler。

this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
  ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
  parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
  return parameterHandler;
}
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
    ResultHandler resultHandler, BoundSql boundSql) {
  ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
  resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
  return resultSetHandler;
}

3.代理對象的創(chuàng)建

3.1 攔截器的獲取

從對象的創(chuàng)建過程中可以看出 代理 對象的創(chuàng)建時(shí)通過 InterceptorChain.pluginAll() 方法創(chuàng)建的。

查看 攔截器鏈 InterceptorChain 發(fā)現(xiàn),其中的攔截器的添加是在 Configuration 中。因?yàn)閿r截器被聲明為Bean了,所以在MyBatis初始化的時(shí)候,會掃描所有攔截器,添加到 InterceptorChain 中。

3.2 代理對象的創(chuàng)建

從上一步得知代理對象的創(chuàng)建是調(diào)用 Interceptor.pugin() 方法,然后調(diào)用 Plugin.wrap() 方法

Interceptor
@Override
public Object plugin(Object o) {
    return Plugin.wrap(o, this);
}

Plugin實(shí)現(xiàn)了 InvocationHandler 接口

 在 Plugin.wrap() 方法中會獲取當(dāng)前攔截器的接口,生成動態(tài)代理。

4. 攔截器的執(zhí)行過程

在動態(tài)代理中當(dāng)代理對象調(diào)用方法時(shí),會將方法的調(diào)用委托給 InvocationHandler,也就是 Plugin,

如下圖所示;

 在該方法中 獲取攔截器簽名中的方法,如果包含當(dāng)前方法,則調(diào)用攔截方法,否則執(zhí)行原方法的調(diào)用。

5. 攔截器的執(zhí)行順序

攔截器的順序配置使用 Spring 中的 org.springframework.core.annotation.Order 注解配置。

order值大的攔截器先執(zhí)行,order值大的在interceptors中越靠后,最后生成代理,所以先執(zhí)行。

到此這篇關(guān)于MyBatis攔截器的實(shí)現(xiàn)原理的文章就介紹到這了,更多相關(guān)MyBatis攔截器 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java反射之Method的invoke方法實(shí)現(xiàn)教程詳解

    java反射之Method的invoke方法實(shí)現(xiàn)教程詳解

    這篇文章主要給大家介紹了關(guān)于java反射之Method的invoke方法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Java使用CountDownLatch實(shí)現(xiàn)統(tǒng)計(jì)任務(wù)耗時(shí)

    Java使用CountDownLatch實(shí)現(xiàn)統(tǒng)計(jì)任務(wù)耗時(shí)

    這篇文章主要為大家詳細(xì)介紹了Java如何使用CountDownLatch實(shí)現(xiàn)統(tǒng)計(jì)任務(wù)耗時(shí)的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2023-06-06
  • Mybatis返回結(jié)果封裝map過程解析

    Mybatis返回結(jié)果封裝map過程解析

    這篇文章主要介紹了Mybatis返回結(jié)果封裝map過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Springboot單體架構(gòu)http請求轉(zhuǎn)換https請求來支持微信小程序調(diào)用接口

    Springboot單體架構(gòu)http請求轉(zhuǎn)換https請求來支持微信小程序調(diào)用接口

    這篇文章主要介紹了Springboot單體架構(gòu)http請求轉(zhuǎn)換https請求來支持微信小程序調(diào)用接口,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • 淺談sql_@SelectProvider及使用注意說明

    淺談sql_@SelectProvider及使用注意說明

    這篇文章主要介紹了sql_@SelectProvider及使用注意說明,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • 詳解JAVA之運(yùn)算符

    詳解JAVA之運(yùn)算符

    這篇文章主要介紹了詳解Java中運(yùn)算符以及相關(guān)的用法講解,一起跟著小編學(xué)習(xí)下吧,希望能夠給你帶來幫助
    2021-11-11
  • 利用Java對PDF文件進(jìn)行電子簽章的實(shí)戰(zhàn)過程

    利用Java對PDF文件進(jìn)行電子簽章的實(shí)戰(zhàn)過程

    隨著電子賬單、回單、通知、合同的流行,電子文檔的可信度變得非常重要,為防止非法篡改,確保文檔的權(quán)威性,我們可以對PDF進(jìn)行電子簽章,這篇文章主要給大家介紹了關(guān)于如何利用Java對PDF文件進(jìn)行電子簽章的相關(guān)資料,需要的朋友可以參考下
    2021-07-07
  • mybatis中批量插入的兩種方式(高效插入)

    mybatis中批量插入的兩種方式(高效插入)

    MyBatis是一個(gè)支持普通SQL查詢,存儲過程和高級映射的優(yōu)秀持久層框架。這篇文章主要介紹了mybatis中批量插入的兩種方式(高效插入)的相關(guān)資料,非常不錯,具有參考借鑒價(jià)值,感興趣的朋友一起看看吧
    2016-09-09
  • MyBatis存儲過程、MyBatis分頁、MyBatis一對多增刪改查操作

    MyBatis存儲過程、MyBatis分頁、MyBatis一對多增刪改查操作

    本文通過一段代碼給大家介紹了MyBatis存儲過程、MyBatis分頁、MyBatis一對多增刪改查操作,非常不錯,具有參考借鑒價(jià)值,感興趣的朋友一起看看吧
    2016-11-11
  • 關(guān)于java關(guān)鍵字this和super的區(qū)別和理解

    關(guān)于java關(guān)鍵字this和super的區(qū)別和理解

    這篇文章主要給大家介紹了關(guān)于java關(guān)鍵字this和super的區(qū)別和理解的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01

最新評論

昌图县| 远安县| 高雄市| 定西市| 柘城县| 吉水县| 北宁市| 宝兴县| 永年县| 邢台市| 阿拉善左旗| SHOW| 江源县| 嘉善县| 尼木县| 将乐县| 南澳县| 平武县| 历史| 东宁县| 盘山县| 循化| 开化县| 淳化县| 建平县| 平舆县| 漠河县| 陆良县| 肃北| 定州市| 华容县| 宁乡县| 新密市| 元阳县| 车致| 黄陵县| 武宁县| 深圳市| 洛川县| 营口市| 泾源县|