天天看點

原了解密 → Spring AOP 實作動态資料源(讀寫分離),底層原理是什麼

  女孩睡醒玩手機,收到男孩發來一條資訊:我要去跟我喜歡的人表白了!

  女孩的心猛的一痛,回了條資訊:去吧,祝你好運!

  男孩回了句:但是我沒有勇氣說不來,怕被打!

  女孩:沒事的,我相信你!此時女孩已經傷心的流淚了

  男孩:我已經到她家門口了,不敢敲門!

  女孩擦了擦眼淚:不用怕,你是個好人,會有好報的!

  男孩:那你來開下門吧,我在你家門口!

  女孩不敢相信,趕緊跑去開門,看到他的那一刻傷心的淚水變成了感動

  男孩拿出手裡那束玫瑰花說:你姐姐在家嗎?

原了解密 → Spring AOP 實作動态資料源(讀寫分離),底層原理是什麼

  一般來講,讀寫分離無非兩種實作方式。第一種是依靠資料庫中間件(比如:MyCat),也就是說應用程式連接配接到中間件,中間件幫我們做讀寫分離;第二種是應用程式自己做讀寫分離,結合 Spring AOP 實作讀寫分離

  資料庫中間件的方式不做過多的闡述(誰讓你是配角!),有興趣的可以去檢視

    Mycat - 實作資料庫的讀寫分離與高可用

    Mycat - 高可用與負載均衡實作,滿滿的幹貨!

   spring內建mybatis實作mysql讀寫分離,簡單介紹了通過 Spring AOP 從應用程式層面實作讀寫分離;讀寫分離效果是達到了,可我們知道為什麼那麼做就能實作讀寫分離嗎 ?知道的請快點走開

原了解密 → Spring AOP 實作動态資料源(讀寫分離),底層原理是什麼

  接下來請好好欣賞我的表演

  我們逐個講解其中涉及的點,然後串起來了解讀寫分離的底層原理

    AOP:Aspect Oriented Program

    關于 Spring AOP,相信大家耳熟能詳,它是對 OOP 的一種補充,OOP 是縱向的,AOP 則是橫向的

    

原了解密 → Spring AOP 實作動态資料源(讀寫分離),底層原理是什麼

    如上圖所示,OOP 屬于一種縱向拓展,AOP 則是一種橫向拓展。AOP 依托于 OOP,将公共功能代碼抽象出來作為一個切面,減少重複代碼量,降低耦合

    AOP 的底層實作是動态代理,具體的表現形式粗略如下

原了解密 → Spring AOP 實作動态資料源(讀寫分離),底層原理是什麼

    對 Spring AOP 有個大緻了解了,我們就可以接着往下看了 

    無論是 Spring JDBC,還是 Hibernate,亦或是 MyBatis,其實都是對 JDBC 的封裝;對于JDBC,我們不要太熟,大體流程如下

原了解密 → Spring AOP 實作動态資料源(讀寫分離),底層原理是什麼

    然而,在實際應用中,我們往往不會直接使用 JDBC,而是使用 ORM,ORM 會封裝上述的流程,也就說我們不再需要關注了;MyBatis 使用步驟大緻如下

原了解密 → Spring AOP 實作動态資料源(讀寫分離),底層原理是什麼

    我們以 SpringBoot + pagehelper + Druid(ssm) 為例,來看看具體是怎麼擷取 Connection 對象的

原了解密 → Spring AOP 實作動态資料源(讀寫分離),底層原理是什麼

    可以看到,如果事務管理器中存在 Connection 對象,則直接傳回,否則從資料源中擷取傳回(同時也指派給了事務管理器);當取到 Connection 對象後,後續的流程大家就非常清楚了

    然而我們不需要關注 Connection 對象,隻需要關注資料源,為什麼呢 ? 因為我們的配置檔案中配置的是資料源而不是 Connection,是不是很有道理 ?

    如果我們需要在各層之間進行參數的傳遞,實作方式有哪些 ?

    最常見的方式可能就是方法參數,但還有一種容易忽略的方式:ThreadLocal,可以在目前線程内傳遞參數,減少方法的參數個數

    關于 ThreadLocal,有興趣的可以檢視:結合ThreadLocal來看spring事務源碼,感受下清泉般的洗滌!

  當我們熟悉上面的三點後,後面的就好了解了,接着往下看

    一個資料源隻能對應一個資料庫,如果我們有多個資料庫(一主多從),那麼就需要配置多個資料源,類似如下

原了解密 → Spring AOP 實作動态資料源(讀寫分離),底層原理是什麼
原了解密 → Spring AOP 實作動态資料源(讀寫分離),底層原理是什麼

View Code

    可是事務管理器中隻有一個資料源的引用

原了解密 → Spring AOP 實作動态資料源(讀寫分離),底層原理是什麼

    那怎麼對應我們配置檔案中的多個資料源呢 ?其實,我們可以自定義一個類 DynamicDataSource 來實作 DataSource,DynamicDataSource 中存儲我們配置的多資料源,然後将 DynamicDataSource 的執行個體配置給事務管理器;當從事務管理器擷取 Connection 對象的時候,會從 DynamicDataSource 執行個體擷取,然後再由 DynamicDataSource 根據 routeKey 路由到某個具體的資料源,從中擷取 Connection;大體流程如下

原了解密 → Spring AOP 實作動态資料源(讀寫分離),底層原理是什麼

    Spring 也考慮到了這一點,提供了一個抽象類:AbstractRoutingDataSource,DynamicDataSource 繼承它可以為我們省非常多的代碼

原了解密 → Spring AOP 實作動态資料源(讀寫分離),底層原理是什麼
原了解密 → Spring AOP 實作動态資料源(讀寫分離),底層原理是什麼

    配置檔案中增加如下配置

原了解密 → Spring AOP 實作動态資料源(讀寫分離),底層原理是什麼
原了解密 → Spring AOP 實作動态資料源(讀寫分離),底層原理是什麼

    但是問題又來了,這個 routeKey 怎麼處理,也就說 DynamicDataSource 怎麼知道用哪個資料源 ? AbstractRoutingDataSource 提供了一個方法: determineCurrentLookupKey 我們隻需要實作它,DynamicDataSource 就知道是使用哪個 lookupKey (routeKey 在 Spring 中的命名)了;determineCurrentLookupKey 具體該如何實作了,我們可以結合 ThreadLocal 來實作;整個流程大緻如下

原了解密 → Spring AOP 實作動态資料源(讀寫分離),底層原理是什麼

    一旦我們在切面中指定了 lookupKey,那麼後續就會使用 lookupKey 對應的資料源來操作資料庫了

  自此,相信大家已經明白了動态資料源的底層原理

  Spring AOP → 将我們指定的 lookupKey 放入 ThreadLocal

  ThreadLocal → 線程内共享 lookupKey

  DynamicDataSource → 對多資料源進行封裝,根據 ThreadLocal 中的 lookupKey 動态選擇具體的資料源

  如果我們對其中的某個環節不懂,可以試着删掉它,然後看這個流程能否正常串起來,這樣就能明白各個環節的作用了

  Springboot 版示例代碼:spring-boot-dynamic-DataSource

  Spring AOP 實作多資料源,是否與 Spring 事務沖突 ,若沖突了該如何解決 ?

  什麼是面向切面程式設計AOP?

  Spring AOP就是這麼簡單啦

繼續閱讀