<p id="m2nkj"><option id="m2nkj"><big id="m2nkj"></big></option></p>
    <strong id="m2nkj"></strong>
    <ruby id="m2nkj"></ruby>

    <var id="m2nkj"></var>
  • Mybatis 插件加載原理與實(shí)戰(zhàn)

    共 5679字,需瀏覽 12分鐘

     ·

    2021-07-15 19:33

    點(diǎn)擊上方「Java有貨」關(guān)注我們


    技術(shù)交流群添加方式


    +



    添加小編微信:372787553,備注:進(jìn)群
    帶您進(jìn)入Java技術(shù)交流群

    導(dǎo)語



    想知道Mybatis的插件是如何生效的就需要了解mybatis的配置,所有的信息都在Mybatis Configuration內(nèi)部,

    在之前的文章中,我們也會看到或如下的代碼:

    public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {  ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);  // 加載插件  parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);  return parameterHandler;}


    Mybatis 配置文件概覽



    MyBatis 的配置文件包含了會深深影響 MyBatis 行為的設(shè)置和屬性信息。配置文檔的頂層結(jié)構(gòu)如下:

    • configuration(配置)

      • environment(環(huán)境變量)

      • transactionManager(事務(wù)管理器)

      • dataSource(數(shù)據(jù)源)

      • properties(屬性)

      • settings(設(shè)置)

      • typeAliases(類型別名)

      • typeHandlers(類型處理器)

      • objectFactory(對象工廠)

      • plugins(插件)

      • environments(環(huán)境配置)

      • databaseIdProvider(數(shù)據(jù)庫廠商標(biāo)識)

      • mappers(映射器)


    InterceptorChain




    看了Mybatis的源碼我們發(fā)現(xiàn),加載插件其實(shí)是通過InterceptorChain進(jìn)行加載的;

    public class InterceptorChain {
    private final List<Interceptor> interceptors = new ArrayList<>();
    public Object pluginAll(Object target) { for (Interceptor interceptor : interceptors) { target = interceptor.plugin(target); } return target;}
    public void addInterceptor(Interceptor interceptor) { interceptors.add(interceptor);}
    public List<Interceptor> getInterceptors() { return Collections.unmodifiableList(interceptors);}
    }

    InterceptorChain 內(nèi)部維護(hù)了一個集合Interceptor(Interceptor 是一個接口), 然后通過 pluginAll 進(jìn)行循環(huán)加載;


    插件(plugins)


    MyBatis 允許你在映射語句執(zhí)行過程中的某一點(diǎn)進(jìn)行攔截調(diào)用。默認(rèn)情況下,MyBatis 允許使用插件來攔截的方法調(diào)用包括:

    • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)

    • ParameterHandler (getParameterObject, setParameters)

    • ResultSetHandler (handleResultSets, handleOutputParameters)

    • StatementHandler (prepare, parameterize, batch, update, query)

    這些類中方法的細(xì)節(jié)可以通過查看每個方法的簽名來發(fā)現(xiàn),或者直接查看 MyBatis 發(fā)行包中的源代碼。如果你想做的不僅僅是監(jiān)控方法的調(diào)用,那么你最好相當(dāng)了解要重寫的方法的行為。因?yàn)樵谠噲D修改或重寫已有方法的行為時,很可能會破壞 MyBatis 的核心模塊。這些都是更底層的類和方法,所以使用插件的時候要特別當(dāng)心。

    通過 MyBatis 提供的強(qiáng)大機(jī)制,使用插件是非常簡單的,只需實(shí)現(xiàn) Interceptor 接口,并指定想要攔截的方法簽名即可。

    如果您不確定攔截了哪些對象,可以在 Configuration 搜素 pluginAll ;


    自定義Mybatis 插件


    在前面我們說過,插件其本質(zhì)就是攔截器的原理 ,那么我們實(shí)現(xiàn)Interceptor 接口既可以;


    @Intercepts({ @Signature(type = org.apache.ibatis.executor.Executor.class, method = "update", args = {MappedStatement.class, Object.class}), @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})public class ExamplePlugin implements Interceptor { private Properties properties = new Properties();
    @Override public Object intercept(Invocation invocation) throws Throwable { System.out.println("自定義攔截器已經(jīng)被執(zhí)行....."); Object returnObject = invocation.proceed(); // 必要時進(jìn)行后期處理 return returnObject; }
    @Override public void setProperties(Properties properties) { this.properties = properties; }}
    // 可在在其中獲取哪些值/** * 獲取被攔截的目前類,在這里是攔截了statementHandler,所有目前類也就是它 * 通過這個類我們可以拿到待執(zhí)行的sql語句,通常使用mataObject工具類來獲取 * 關(guān)于這個工具類,大家可自行了解,個人認(rèn)為這個工具類很強(qiáng)大 */ StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); MetaObject metaObject = SystemMetaObject.forObject(statementHandler); /** * 先解釋下為什么寫成delegate.boundSql就可以拿到boundSql類 * 從前面也可以得知,statementHandler的默認(rèn)實(shí)現(xiàn)是routingStatementHandler。 * 這個類有一個屬性statementHandler,屬性名就叫delegate,而這個屬性的默認(rèn)實(shí)現(xiàn)又是preparedStatementHandler * 后面這個類又有屬性boundSql,所以,最終形成的寫法就是delegate.boundSql。 * 所以這也體現(xiàn)了MetaObject工具類的強(qiáng)大,可以通過實(shí)例傳參,就可以根據(jù)屬性名獲取對應(yīng)屬性值 */ BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
    // 待執(zhí)行的sql,在這里也就是預(yù)編譯后的sql,即參數(shù)位都是?號 String sql = boundSql.getSql(); /** * 既然拿到了預(yù)編譯后的sql,那就可以按照你自己的想法為所欲為,如分頁,按年分表等等 * 分表的話,個人推薦druid的sql解析器,我認(rèn)為還是不錯的,大家可以自行了解 * 最后改造完sql,別忘了把它設(shè)置回去 * metaObject.setValue("delegate.boundSql.sql",sql); * invocation.proceed,即原始方法的執(zhí)行 * 注意點(diǎn)就是,因?yàn)閙ybatis插件采用的是代理模式,所以如果存在多個插件,會形成多個代理 * 你如果要拿到最原始的對象,還得進(jìn)一步進(jìn)行分解 * 如:while(metaObject.getValue(""h) != null){ * Object obj = metaObject.getValue("h"); * .... * } */ return invocation.proceed();

    配置插件

    • XML配置

      <!-- mybatis-config.xml -->
      <plugins>
       <plugin interceptor="com.javayh.mybatis.config.ExamplePlugin">
         <property name="someProperty" value="100"/>
       </plugin>
      </plugins>
    • java配置類

      @org.springframework.context.annotation.Configurationpublic class MapperConfig {
      //注冊插件 @Bean public ExamplePlugin myPlugin() { ExamplePlugin myPlugin = new ExamplePlugin(); //設(shè)置參數(shù),比如閾值等,可以在配置文件中配置,這里直接寫死便于測試 Properties properties = new Properties(); //這里設(shè)置慢查詢閾值為1毫秒,便于測試 properties.setProperty("time", "1"); myPlugin.setProperties(properties); return myPlugin; } //將插件加入到mybatis插件攔截鏈中 /*@Bean public ConfigurationCustomizer configurationCustomizer() { return configuration -> { //插件攔截鏈采用了責(zé)任鏈模式,執(zhí)行順序和加入連接鏈的順序有關(guān) ExamplePlugin myPlugin = new ExamplePlugin(); //設(shè)置參數(shù),比如閾值等,可以在配置文件中配置,這里直接寫死便于測試 Properties properties = new Properties(); //這里設(shè)置慢查詢閾值為1毫秒,便于測試 properties.setProperty("time", "1"); myPlugin.setProperties(properties); configuration.addInterceptor(myPlugin); }; }*/}

    上面的插件將會攔截在 Executor 實(shí)例中所有的 “update 、query” 方法調(diào)用, 這里的 Executor 是負(fù)責(zé)執(zhí)行底層映射語句的內(nèi)部對象。

    提示 覆蓋配置類

    除了用插件來修改 MyBatis 核心行為以外,還可以通過完全覆蓋配置類來達(dá)到目的。只需繼承配置類后覆蓋其中的某個方法,再把它傳遞到 SqlSessionFactoryBuilder.build(myConfig) 方法即可。再次重申,這可能會極大影響 MyBatis 的行為,務(wù)請慎之又慎。

    瀏覽 61
    點(diǎn)贊
    評論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)
    評論
    圖片
    表情
    推薦
    點(diǎn)贊
    評論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)
    <p id="m2nkj"><option id="m2nkj"><big id="m2nkj"></big></option></p>
    <strong id="m2nkj"></strong>
    <ruby id="m2nkj"></ruby>

    <var id="m2nkj"></var>
  • 国产理论视频在线观看 | 久九九久国产精品 | 精品欧美日韩视频在线 | 欧美黄色操逼视频 | 以及视频片又粗又猛 | 无码一区二区三区在线 | 狠狠操狠狠色 | 三级视频在线播放 | 国产精品做受 | 午夜真实日逼视频 |