婷婷久久综合九色综合,欧美成色婷婷在线观看视频,偷窥视频一区,欧美日本一道道一区二区

<tt id="bu9ss"></tt>
  • <span id="bu9ss"></span>
  • <pre id="bu9ss"><tt id="bu9ss"></tt></pre>
    <label id="bu9ss"></label>

    當(dāng)前位置:首頁(yè) >  站長(zhǎng) >  編程技術(shù) >  正文

    簡(jiǎn)單了解mybatis攔截器實(shí)現(xiàn)原理及實(shí)例

     2020-10-30 16:29  來(lái)源: 黎青松SEO博客   我來(lái)投稿 撤稿糾錯(cuò)

      阿里云優(yōu)惠券 先領(lǐng)券再下單

    這篇文章主要介紹了簡(jiǎn)單了解mybatis*實(shí)現(xiàn)原理及實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

    例行慣例,先看些基本概念:

    1 *的作用就是我們可以攔截某些方法的調(diào)用,在目標(biāo)方法前后加上我們自己邏輯

    2 Mybatis*設(shè)計(jì)的一個(gè)初衷是為了供用戶在某些時(shí)候可以實(shí)現(xiàn)自己的邏輯而不必去動(dòng)Mybatis固有的邏輯。

    自定義*

    * mybatis 自定義*

    * 三步驟:

    * 1 實(shí)現(xiàn) {@link Interceptor} 接口

    * 2 添加攔截注解 {@link Intercepts}

    * 3 配置文件中添加*

    * 1 實(shí)現(xiàn) {@link Interceptor} 接口

    * 具體作用可以看下面代碼每個(gè)方法的注釋

    * 2 添加攔截注解 {@link Intercepts}

    * mybatis *默認(rèn)可攔截的類型只有四種,即四種接口類型 Executor、StatementHandler、ParameterHandler 和 ResultSetHandler

    * 對(duì)于我們的自定義*必須使用 mybatis 提供的注解來(lái)指明我們要攔截的是四類中的哪一個(gè)類接口

    * 具體規(guī)則如下:

    * a:Intercepts *: 標(biāo)識(shí)我的類是一個(gè)*

    * b:Signature 署名: 則是指明我們的*需要攔截哪一個(gè)接口的哪一個(gè)方法

    * type 對(duì)應(yīng)四類接口中的某一個(gè),比如是 Executor

    * method 對(duì)應(yīng)接口中的哪類方法,比如 Executor 的 update 方法

    * args 對(duì)應(yīng)接口中的哪一個(gè)方法,比如 Executor 中 query 因?yàn)橹剌d原因,方法有多個(gè),args 就是指明參數(shù)類型,從而確定是哪一個(gè)方法

    * 3 配置文件中添加*

    * *其實(shí)就是一個(gè) plugin,在 mybatis 核心配置文件中我們需要配置我們的 plugin :

    * plugin interceptor="liu.york.mybatis.study.plugin.MyInterceptor"

    * property name="username" value="LiuYork"/

    * property name="password" value="123456"/

    * /plugin

    * *順序

    * 1 不同*順序:

    * Executor - ParameterHandler - StatementHandler - ResultSetHandler

    * 2 對(duì)于同一個(gè)類型的*的不同對(duì)象攔截順序:

    * 在 mybatis 核心配置文件根據(jù)配置的位置,攔截順序是 從上往下

    @Intercepts({

    @Signature(method = "update", type = Executor.class, args = {MappedStatement.class, Object.class}),

    @Signature(method = "query", type = StatementHandler.class, args = {Statement.class, ResultHandler.class})

    public class MyInterceptor implements Interceptor {

    * 這個(gè)方法很好理解

    * 作用只有一個(gè):我們不是攔截方法嗎,攔截之后我們要做什么事情呢?

    * 這個(gè)方法里面就是我們要做的事情

    * 解釋這個(gè)方法前,我們一定要理解方法參數(shù) {@link Invocation} 是個(gè)什么鬼?

    * 1 我們知道,mybatis*默認(rèn)只能攔截四種類型 Executor、StatementHandler、ParameterHandler 和 ResultSetHandler

    * 2 不管是哪種代理,代理的目標(biāo)對(duì)象就是我們要攔截對(duì)象,舉例說(shuō)明:

    * 比如我們要攔截 {@link Executor#update(MappedStatement ms, Object parameter)} 方法,

    * 那么 Invocation 就是這個(gè)對(duì)象,Invocation 里面有三個(gè)參數(shù) target method args

    * target 就是 Executor

    * method 就是 update

    * args 就是 MappedStatement ms, Object parameter

    * 如果還是不能理解,我再舉一個(gè)需求案例:看下面方法代碼里面的需求

    * 該方法在運(yùn)行時(shí)調(diào)用

    @Override

    public Object intercept(Invocation invocation) throws Throwable {

    * 需求:我們需要對(duì)所有更新操作前打印查詢語(yǔ)句的 sql 日志

    * 那我就可以讓我們的自定義* MyInterceptor 攔截 Executor 的 update 方法,在 update 執(zhí)行前打印sql日志

    * 比如我們攔截點(diǎn)是 Executor 的 update 方法 : int update(MappedStatement ms, Object parameter)

    * 那當(dāng)我們?nèi)罩敬蛴〕晒χ?,我們是不是還需要調(diào)用這個(gè)query方法呢,如何如調(diào)用呢?

    * 所以就出現(xiàn)了 Invocation 對(duì)象,它這個(gè)時(shí)候其實(shí)就是一個(gè) Executor,而且 method 對(duì)應(yīng)的就是 query 方法,我們

    * 想要調(diào)用這個(gè)方法,只需要執(zhí)行 invocation.proceed()

    /* 因?yàn)槲覕r截的就是Executor,所以我可以強(qiáng)轉(zhuǎn)為 Executor,默認(rèn)情況下,這個(gè)Executor 是個(gè) SimpleExecutor */

    Executor executor = (Executor)invocation.getTarget();

    * Executor 的 update 方法里面有一個(gè)參數(shù) MappedStatement,它是包含了 sql 語(yǔ)句的,所以我獲取這個(gè)對(duì)象

    * 以下是偽代碼,思路:

    * 1 通過(guò)反射從 Executor 對(duì)象中獲取 MappedStatement 對(duì)象

    * 2 從 MappedStatement 對(duì)象中獲取 SqlSource 對(duì)象

    * 3 然后從 SqlSource 對(duì)象中獲取獲取 BoundSql 對(duì)象

    * 4 最后通過(guò) BoundSql#getSql 方法獲取 sql

    MappedStatement mappedStatement = ReflectUtil.getMethodField(executor, MappedStatement.class);

    SqlSource sqlSource = ReflectUtil.getField(mappedStatement, SqlSource.class);

    BoundSql boundSql = sqlSource.getBoundSql(args);

    String sql = boundSql.getSql();

    logger.info(sql);

    * 現(xiàn)在日志已經(jīng)打印,需要調(diào)用目標(biāo)對(duì)象的方法完成 update 操作

    * 我們直接調(diào)用 invocation.proceed() 方法

    * 進(jìn)入源碼其實(shí)就是一個(gè)常見(jiàn)的反射調(diào)用 method.invoke(target, args)

    * target 對(duì)應(yīng) Executor對(duì)象

    * method 對(duì)應(yīng) Executor的update方法

    * args 對(duì)應(yīng) Executor的update方法的參數(shù)

    return invocation.proceed();

    * 這個(gè)方法也很好理解

    * 作用就只有一個(gè):那就是Mybatis在創(chuàng)建*代理時(shí)候會(huì)判斷一次,當(dāng)前這個(gè)類 MyInterceptor 到底需不需要生成一個(gè)代理進(jìn)行攔截,

    * 如果需要攔截,就生成一個(gè)代理對(duì)象,這個(gè)代理就是一個(gè) {@link Plugin},它實(shí)現(xiàn)了jdk的動(dòng)態(tài)代理接口 {@link InvocationHandler},

    * 如果不需要代理,則直接返回目標(biāo)對(duì)象本身

    * Mybatis為什么會(huì)判斷一次是否需要代理呢?

    * 默認(rèn)情況下,Mybatis只能攔截四種類型的接口:Executor、StatementHandler、ParameterHandler 和 ResultSetHandler

    * 通過(guò) {@link Intercepts} 和 {@link Signature} 兩個(gè)注解[!--empirenews.page--]三個(gè)核心方法都加了詳細(xì)的注釋,而且結(jié)合案例需求說(shuō)明問(wèn)題

    那么多文字不想行看,沒(méi)關(guān)系有概括

    總結(jié):

    1.在mybatis中可被攔截的類型有四種(按照攔截順序):

    Executor:攔截執(zhí)行器的方法。

    ParameterHandler:攔截參數(shù)的處理。

    ResultHandler:攔截結(jié)果集的處理。

    StatementHandler:攔截Sql語(yǔ)法構(gòu)建的處理。

    2.各個(gè)參數(shù)的含義:

    @Intercepts:標(biāo)識(shí)該類是一個(gè)*;

    @Signature:指明自定義*需要攔截哪一個(gè)類型,哪一個(gè)方法;

    2.1 type:對(duì)應(yīng)四種類型中的一種;

    2.2 method:對(duì)應(yīng)接口中的哪類方法(因?yàn)榭赡艽嬖谥剌d方法);

    2.3 args:對(duì)應(yīng)哪一個(gè)方法;

    不知道能否幫助你理解,我的表達(dá)能力有限~~~

    接下來(lái)我們看看 Plugin 類

    package org.apache.ibatis.plugin;

    * Plugin 類其實(shí)就是一個(gè)代理類,因?yàn)樗鼘?shí)現(xiàn)了jdk動(dòng)態(tài)代理接口 InvocationHandler

    * 我們核心只需要關(guān)注兩個(gè)方法

    * wrap:

    * 如果看懂了代碼案例1的例子,那么這個(gè)方法很理解,這個(gè)方法就是 mybatis 提供給開(kāi)發(fā)人員使用的一個(gè)工具類方法,

    * 目的就是幫助開(kāi)發(fā)人員省略掉 反射解析注解 Intercepts 和 Signature,有興趣的可以去看看源碼 Plugin#getSignatureMap 方法

    * invoke:

    * 這個(gè)方法就是根據(jù) wrap 方法的解析結(jié)果,判斷當(dāng)前*是否需要進(jìn)行攔截,

    * 如果需要攔截:將 目標(biāo)對(duì)象+目標(biāo)方法+目標(biāo)參數(shù) 封裝成一個(gè) Invocation 對(duì)象,給我們自定義的* MyInterceptor 的 intercept 方法

    * 這個(gè)時(shí)候就剛好對(duì)應(yīng)上了上面案例1中對(duì) intercept 方法的解釋了,它就是我們要處理自己邏輯的方法,

    * 處理好了之后是否需要調(diào)用目標(biāo)對(duì)象的方法,比如上面說(shuō)的 打印了sql語(yǔ)句,是否還要查詢數(shù)據(jù)庫(kù)呢?答案是肯定的

    * 如果不需要攔截:則直接調(diào)用目標(biāo)對(duì)象的方法

    * 比如直接調(diào)用 Executor 的 update 方法進(jìn)行更新數(shù)據(jù)庫(kù)

    class Plugin implements InvocationHandler {

    public static Object wrap(Object target, Interceptor interceptor) {

    // 省略

    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    // 省略

    }

    貼一段網(wǎng)上的通用解釋吧:

    Plugin的wrap方法,它根據(jù)當(dāng)前的Interceptor上面的注解定義哪些接口需要攔截,然后判斷當(dāng)前目標(biāo)對(duì)象是否有實(shí)現(xiàn)對(duì)應(yīng)需要攔截的接口,如果沒(méi)有則返回目標(biāo)對(duì)象本身,如果有則返回一個(gè)代理對(duì)象。而這個(gè)代理對(duì)象的InvocationHandler正是一個(gè)Plugin。所以當(dāng)目標(biāo)對(duì)象在執(zhí)行接口方法時(shí),如果是通過(guò)代理對(duì)象執(zhí)行的,則會(huì)調(diào)用對(duì)應(yīng)InvocationHandler的invoke方法,也就是Plugin的invoke方法。

    所以接著我們來(lái)看一下該invoke方法的內(nèi)容。這里invoke方法的邏輯是:如果當(dāng)前執(zhí)行的方法是定義好的需要攔截的方法,則把目標(biāo)對(duì)象、要執(zhí)行的方法以及方法參數(shù)封裝成一個(gè)Invocation對(duì)象,再把封裝好的Invocation作為參數(shù)傳遞給當(dāng)前*的intercept方法。如果不需要攔截,則直接調(diào)用當(dāng)前的方法。Invocation中定義了定義了一個(gè)proceed方法,其邏輯就是調(diào)用當(dāng)前方法,所以如果在intercept中需要繼續(xù)調(diào)用當(dāng)前方法的話可以調(diào)用invocation的procced方法。

    這就是Mybatis中實(shí)現(xiàn)Interceptor攔截的一個(gè)思想

    文章轉(zhuǎn)自:黎青松SEO博客

    來(lái)源地址:http://www.alitaohuo.com/fuwuqi/yunwei/1716.html

    申請(qǐng)創(chuàng)業(yè)報(bào)道,分享創(chuàng)業(yè)好點(diǎn)子。點(diǎn)擊此處,共同探討創(chuàng)業(yè)新機(jī)遇!

    相關(guān)文章

    熱門(mén)排行

    信息推薦