<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          PageHelper導(dǎo)致自定義Mybatis攔截器不生效

          共 4758字,需瀏覽 10分鐘

           ·

          2021-04-19 15:00


          來源:www.jianshu.com/p/8dc9f8a4cce9

          背景:

          最近由于公司要做統(tǒng)一的數(shù)據(jù)變更記錄,以前是基于Aop來做的,這樣效率很低,而且在做批量處理(insert,update,delete)操作時基本不可用。所以我打算使用CDC(如Canal,Maxwell等工具)來監(jiān)聽mysql的binlog來做。

          但是不是所有的表都會有user_id字段,所以我們須要在sql上做一些處理,因為公司現(xiàn)在統(tǒng)一用的是mybatis,那么現(xiàn)在我覺得比較好的方式就是在mybatis上進(jìn)行攔截改造sql.將userId從應(yīng)用層獲取到并寫入到須要執(zhí)行的sql上(只對insert,update,delete記錄)。

          如:有如下sql:

          update table set a= 1 where name =3

          改造的結(jié)果就是:

          /** userId:1,traceId:123456**/ 
          update table set a= 1 where name =3

          這樣我們就可以記錄一次操作改了哪些數(shù)據(jù),改數(shù)據(jù)的人是哪個。

          開始干:

          這里面有幾個技術(shù)點,且都不怎么復(fù)雜,今天我們只聊mybatis攔截器。其實寫一個攔截器還是很簡單的,網(wǎng)上有很多的代碼。代碼寫完后,突然發(fā)現(xiàn)有些項目的自定義mybatis攔截器沒有生效。

          于是就開始google研究了一下,發(fā)現(xiàn)是因為我們這些不生效的項目使用了PageHelper.于是找了一些大神的解決方案,和攔截器的順序有關(guān)。先說一下結(jié)論:

          MyBatis的攔截器采用責(zé)任鏈設(shè)計模式,多個攔截器之間的責(zé)任鏈?zhǔn)峭ㄟ^動態(tài)代理組織的。我們一般都會在攔截器中的intercept方法中往往會有invocation.proceed()語句,其作用是將攔截器責(zé)任鏈向后傳遞,本質(zhì)上便是動態(tài)代理的invoke。

          PageHelper在intercept方法中執(zhí)行完后沒有執(zhí)行invocation.proceed(),意味著這玩意兒沒有繼續(xù)傳遞責(zé)任鏈(可能他有自己的想法)。所以他就沒有進(jìn)入我們自己的攔截器。

          注意,敲黑板:

          A.不是所有的攔截器都必須要指定先后順序。

          攔截器的調(diào)用順序分為兩大種,第一種是攔截的不同對象,例如攔截 Executor 和 攔截 StatementHandler 就屬于不同的攔截對象, 這兩類的攔截器在整體執(zhí)行的邏輯上是不同的,在 Executor 中的 query 方法執(zhí)行過程中會調(diào)用StatementHandler。

          所以StatementHandler 屬于 Executor 執(zhí)行過程中的一個子過程。所以這兩種不同類別的插件在配置時,一定是先執(zhí)行 Executor 的攔截器,然后才會輪到 StatementHandler。所以這種情況下配置攔截器的順序就不重要了,在 MyBatis 邏輯上就已經(jīng)控制了先后順序。

          所以如果你一個是Executor 類型的攔截器,一個是StatementHandler類型的攔截器,你可以不用管他順序,也就是說你只須要定義好類型都Executor的攔截器順序。

          B.類型都為Executor的攔截器順序問題。

          如果你的攔截器定義的順序是這樣的(你可以通過獲取sqlSessionFactory.getConfiguration()去查看里面的InterceptorChain然后看到各個interceptor的順序):

          <plugins>
          <plugin interceptor="com.github.pagehelper.ExecutorQueryInterceptor1"/>
          <plugin interceptor="com.github.pagehelper.ExecutorQueryInterceptor2"/>
          <plugin interceptor="com.github.pagehelper.ExecutorQueryInterceptor3"/>
          </plugins>

          他執(zhí)行的順序不是先執(zhí)行1,2,3,而執(zhí)行的順序是3,2,1。

          Interceptor3:{
              Interceptor2: {
                  Interceptor1: {
                      target: Executor
                  }
              }
          }

          從這個結(jié)構(gòu)應(yīng)該就很容易能看出來,將來執(zhí)行的時候肯定是按照 3>2>1>Executor>1>2>3 的順序去執(zhí)行的。可能有些人不知道為什么3>2>1>Executor之后會有1>2>3,這是因為使用代理時,調(diào)用完代理方法后,還能繼續(xù)進(jìn)行其他處理。處理結(jié)束后,將代理方法的返回值繼續(xù)往外返回即可。

          C.解決方案

          因為PageHelper是Excetor類型的攔截器,所以按照前面兩條的理論,我們?nèi)绻胍赑ageHelper攔截器前面執(zhí)行,就必須要將我們自己的攔截器添加到他的攔截器后面。

          那該怎么做呢?

          我們可以通過這種方式來做:

          我們?nèi)タ碢ageHelperAutoConfiguration的代碼是不是發(fā)現(xiàn),該類上面有一個@AutoConfigureAfter(MybatisAutoConfiguration.class)注解,這表明他是在MybatisAutoConfiguration加載完成后,才執(zhí)行自己的加載。那么我們是不是可以也可以構(gòu)建一個類似的代碼呢,雖然我們不是一個starter,但是我們可以通過這種操作來實現(xiàn)我們的須求。

          1.在src/main/resources/META-INF目錄下面,創(chuàng)建一個spring.factories的文件

          2.spring.factories里的內(nèi)容是:org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.llyt.exculd.TestLogAutoConfiguration這個com.llyt.exculd.TestLogAutoConfiguration,就是你自己的配置類的全路徑。該類的代碼在后面。

          3.TestLogAutoConfiguration代碼:

          @Configuration
          @AutoConfigureAfter(PageHelperAutoConfiguration.class)
          public class TestLogAutoConfiguration 
          {
              @Autowired
              private List<SqlSessionFactory> sqlSessionFactoryList;

              @PostConstruct
              public void addMyInterceptor() {
                  ExampleOnePlugin e = new ExampleOnePlugin();
                  for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
                      sqlSessionFactory.getConfiguration().addInterceptor(e);
                  }
              }
          }

          至此,這種方法就OK了。但是你可能會執(zhí)行不成功,該類的addMyInterceptor方法總是先于PageHelperAutoConfiguration的addPageInterceptor()方法執(zhí)行,這就意味著你的攔截器總是添加到在pageHelper攔截前面的,那么他總是在PageHelper攔截器后面執(zhí)行。

          如果出現(xiàn)這種情況,說明你可能在spring boot主類上配置了

          @ComponentScan("****"),且該類會被這個掃描到,這個就是導(dǎo)致的原因所在。

          這里面有一個知識點就是,不是配置了@AutoConfigureAfter(A.class)就一定表示該類一定在A類后面執(zhí)行。

          如果配置類在 spring.factories 中配置了且而如果你的類被自己 Spring Boot 啟動類掃描到了,那么該類會被會優(yōu)先掃描到,配置類對順序有要求時就會出錯。那么該怎么解決呢?

          解決的方法有兩個:

          a.使用騷操作。

          如果你將自己的配置類放到特別的包下,不使用 Spring Boot 啟動類掃描。完全通過 spring.factories 讀取配置就可以實現(xiàn)這個目的。

          比如,你@ComponentScan掃描的包是com.bb.cc,那么你就將該配置類放在com.bb.dd包下面。

          b.如果你覺得上面這種不習(xí)慣,可以用使用excludeFilters。

          @ComponentScan(basePackages = {"com.llyt"},  excludeFilters = @ComponentScan.Filter(
               type = FilterType.REGEX,
               pattern = "com.llyt.exculd.*"))

          將你的配置類放在com.llyt.exculd包下面就行了。

          至此,mybatis攔截器的不生效的問題,搞完了。

          最近給大家找了  JVM學(xué)習(xí)視頻


          資源,怎么領(lǐng)取?


          掃二維碼為,加我微信,回復(fù):JVM

           注意,不要亂回復(fù) 

          沒錯,不是機(jī)器人
          記得一定要等待,等待才有好東西
          瀏覽 52
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久99精品久久久久久不卡l中文无码精品 | 黄色一级片免费直播 | 一级黄色录相片 | 麻豆成人精品国产免费 | 免费看一区二区三区A片 |