日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CobarClient源码分析

發布時間:2025/3/14 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CobarClient源码分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

CobarClient是阿里巴巴公司開發一個的開源的、基于iBatis和Spring的分布式數據庫訪問層。為了支持iBatis,Spring框架提供了一個SqlMapClientTemplate,通過模板模式簡化了在Spring框架中對于iBatis中的使用。而CobarClient則繼承了SqlMapClientTemplate,提供了CobarSqlMapClientTemplate給應用使用。CobarSqlMapClientTemplate和SqlMapClientTemplate繼承關系如下:

CobarSqlMapClientTemplate持有的眾多屬性中,比較重要的有cobarDataSourceService(提供多數據源的管理服務)、router(Sql路由接口的實現)、concurrentRequestProcessor(Sql并發執行的命令類),下面就從路由規則到最終的Sql執行來分析一下CobarClient的原理。

  • 路由規則的生成與執行。
  • 根據CobarClient的文檔,CobarClient一共提供了四種路由規則:

    • NamespaceShardingRule:針對iBatis中Sql Map定義的,屬于某一個NameSpace的Sql語句執行某一個路由規則,根據路由的結果選擇一個或者多個數據分區。
    • Namespace(Only)Rule:針對iBatis中Sql Map定義的,屬于某一個NameSpace的Sql語句無差別的將Sql語句路由到一個或者多個數據分區。
    • SqlActionShardingRule:針對iBatis中Sql Map定義的某一個Sql Id對應的Sql語句,執行某一個路由規則,根據路由的結果選擇一個或者多個數據分區。
    • SqlAction(Only)Rule:針對iBatis中Sql Map定義的某一個Sql Id對應的Sql語句,無差別的將這個語句路由到一個或者多個數據分區。

    ?

    ?

    在CobarClient中這四個路由規則,分別對應四個具體的實現類,而這四個實現類,都實現了IRoutingRule這個接口,繼承關系如下所示:

    在4種路由規則分別具體對應的實現類中,都實現了isDefinedAt(IBatisRoutingFact routingFact)這個方法,這個方法實現的功能判斷現在要執行的Sql語句是不是可以匹配當前的路由規則實例。這個方法的參數,routingFact的類型是IBatisRoutingFact,代表的是一個路由上下文信息:

    public class IBatisRoutingFact {   private String action; // SQL identity   private Object argument; // the argument of SQL action } 舉個例子,看看IBatisNamespaceRule類中isDefinedAt方法的實現如下: public boolean isDefinedAt(IBatisRoutingFact routingFact) {   Validate.notNull(routingFact);   String namespace = StringUtils.substringBeforeLast(routingFact.getAction(), ".");   return StringUtils.equals(namespace, getTypePattern()); }

    實際完成的工作很簡單,就是看看當前的Sql Id的NameSpace是否和規則定義的NameSpace一致,如果一致,表示使用該路由規則。清楚了路由規則的實現之后,那么這么多路由規則又是怎么匯總到CobarSqlMapClientTemplate中的呢?根據CobarClient文檔中的說明:

    默認情況下, CobarClientInternalRouter將接收4組不同類型的路由規則, 但路由規則的類型對于用戶來說實際上是不必要的, 所以, 為了避免用戶過多的糾纏于CobarClientInternalRouter的實現細節, 我們給出了針對CobarClientInternalRouter配置的一個Spring的FactoryBean實現, 以幫助簡化CobarClientInternalRouter的配置, 該FactoryBean實現類為com.alibaba.cobar.client.router.config.CobarInteralRouterXmlFactoryBean。CobarInteralRouterXmlFactoryBean將根據指定的xml形式的配置文件中的內容, 自動構建不同類型的路由規則, 然后注入到它將最終返回的CobarClientInternalRouter實例之上。 而讀取, 解析配置信息, 并構建不同類型路由規則等 “瑣事” 將完全對用戶透明。

    一個典型的路由規則文件可能如下

    <rules> <rule> <namespace>com.alibaba.cobar.client.entity.Follower</namespace> <shards>partition1</shards> </rule> <rule> <sqlmap>com.alibaba.cobar.client.entity.Follower.create</sqlmap> <shards>p1, p2</shards> </rule> <rule> <sqlmap>com.alibaba.cobar.client.entity.Follower.create</sqlmap> <shardingExpression>id&gt;10000 and id&lt; 20000</shardingExpression> <shards>p1, p2</shards> </rule> <rule> <namespace>com.alibaba.cobar.client.entity.Follower</namespace> <shardingExpression>id&gt;10000 and id&lt; 20000</shardingExpression> <shards>p1, p2</shards> </rule> </rules> 解析了完所有的路由規則配置文件之后,CobarClientInternalRouter類的實例將持有一個List,該List的定義如下: private List<Set<IRoutingRule<IBatisRoutingFact, List<String>>>> ruleSequences

    實際上,這個List只有4個元素,每一個元素是一個集合,分別對應之前提到的四種路由規則。而每個集合中的元素都是一個具體的規則實現類。當具體執行一個Sql語句之前,CobarSqlMapClientTemplate通過它持有的CobarClientInternalRouter實例的doRoute方法來實現具體的路由規則選擇,可見CobarClientInternalRouter實際上充當了一個門面(Facade)的作用,匯總了所有的路由信息,而且CobarSqlMapClientTemplate是一個更高層的門面。
    ?? 在doRoute方法中,有兩層循環,第一層循環,遍歷ruleSequence這個List,第二層循環遍歷List中每個Set

    for (Set<IRoutingRule<IBatisRoutingFact, List<String>>> ruleSet : getRuleSequences()) {   ruleToUse = searchMatchedRuleAgainst(ruleSet, routingFact); if (ruleToUse != null) {   break; } } 在searchMatchedRuleAgainst方法中,執行第二次遍歷 for (IRoutingRule<IBatisRoutingFact, List<String>> rule : rules) {   if (rule.isDefinedAt(routingFact)) {   return rule; } }

    在這里最終調用之前提到的isDefinedAt方法,兩次遍歷了ruleSequence之后,將獲得一個Map,
    SortedMap<String, DataSource> resultMap 表示的這次Sql語句執行需要用對應的數據源。

    2.Sql的執行
    ?? 當CobarSqlMapClientTemplate通過CobarClientInternalRouter獲取到了本次Sql執行對應的數據源之后,將進入到Sql執行的階段。在Spring框架中,提供了一個接口SqlMapClientCallback接口,CobarSqlMapClientTemplate在每一次執行Sql語句之前,都會生成一個SqlMapClientCallback的內部類,該內部類實現了SqlMapClientCallback接口中定義的回調函數,doInSqlMapClient。例如,在某一次查詢語句之前,對應的內部類可能是:

    callback = new SqlMapClientCallback() {   public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {    return executor.queryForList(statementName, parameterObject,skipResults, maxResults); } };

    具體到Sql語句的執行,CobarClient命令模式結合回調函數的方式來實現,標準的命令模式結構圖如下:

    在CobarSqlMapClientTemplate中,擔任ConcreteCommand角色的是IConcurrentRequestProcessor,它的執行方法為:

    List<Object> process(List<ConcurrentRequest> requests)

    不同的是,為了支持Sql并行執行,這里傳入的不是單個的request,而是由多個ConcurrentRequest類型的request組成的List(這里的ConcurrentRequest可以看成命令模式的中的Receiver),不同的是在ConcurrentRequest類中是通過多線程加調用SqlMapClientCallback中的回調函數的方式來實現命令模式中Receiver的action方法的。在IConcurrentRequestProcessor調用process方法之后,會通過多線程的方式來執行SqlMapClientCallback中的回調函數,

    request.getExecutor().submit(new Callable<Object>() { public Object call() throws Exception { try { return executeWith(connection, action); } finally { latch.countDown(); } } } )

    executeWith中connection具體的數據源的連接,action就是之前提到的匿名內部類,在executeWith方法中,會調用這個內部的回調函數:

    protected Object executeWith(Connection connection, SqlMapClientCallback action) { SqlMapSession session = getSqlMapClient().openSession(); try { try { session.setUserConnection(connection); } catch (SQLException e) { throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", e); } try { return action.doInSqlMapClient(session); } catch (SQLException ex) { throw new SQLErrorCodeSQLExceptionTranslator().translate("SqlMapClient operation", null, ex); } } finally { session.close(); } }

    當執行完SqlMapClientCallback中的doInSqlMapClient方法之后,CobarSqlMapClientTemplate還會對多個Sql語句執行獲取的結果進行簡單的合并之后在返回給應用程序,至此,整個Sql的分布式數據庫執行才算結束。

    3. 一點體會
    CobarClient擴展了Spring提供的SqlMapClientTemplate,在Sql執行之前根據數據路由規則獲取了真正要執行的數據分區,在Sql執行之后在進行結果集的簡單合并,最終實現了分布式數據庫的數據路由功能,但是CorBarClient不是沒有缺點

  • 數據合并功能的羸弱:CobarClient并沒有引入Sql語句的解析,對于數據的合并是在應用層做的,而且現在只能支持簡單的合并,當應用程序有比較復雜的結果集處理要求的時候,例如order by,group by等,需要自己去實現merge類,而且由于沒有Sql語句的解析,即使實現了,也很難做到通用。
  • 路由算法的效率:根據CobarClient的文檔:
    ???????? 我們可以根據情況提供不同的ICobarRouter實現類, 比如Cobar Client默認提供的com.alibaba.cobar.client.router.CobarClientInternalRouter和 om.alibaba.cobar.client.router.DefaultCobarClientInternalRouter, 或者如果路由規則數量很多, 為了保證性能, 也可以實現基于Rete等算法的實現類等. 沒有特殊需求的情況下,我們默認采用CobarClientInternalRouter作為CobarSqlMapClientTemplate使用的 默認Router實現. 但用戶也可以根據情況選用DefaultCobarClientInternalRouter, 二者的使用是類似的。DefaultCobarClientInternalRouter在CobarClientInternalRouter的基礎 上, 對路由規則的匹配進行了分組優化, 通過配置時期的復雜度換取運行時期的簡單高效。 如果規則很多的話,可以考慮使用DefaultCobarClientInternalRouter。
    ??????? 之前代碼分析的CobarClientInternalRouter的doRoute實現,在兩層的循環中,如果有n個具體的路由規則,那么最壞的情況,要執行n次路由判斷,算法的效率是O(n)。文檔說DefaultCobarClientInternalRouter的doRoute實現效率更高(但是DefaultCobarClientInternalRouter的doRoute方法沒有用到cache,而CobarClientInternalRouter用到了),但實際上只是對于ruleSequences根據Namespace做了分組,那么當有n個路由規則,m個namespace的時候,算法的效率是O(n/m)。由于在每個sql語句執行之前,都需要執行doRoute方法來路由,所以如果用HashMap來保存Sql Id和路由規則的對應關系,算法的效率將提高到O(1),這樣算法的時間消耗不會隨著路由規則的增多而增長。
  • 路由規則的設計和解析:路由規則的解析,CobarClient使用的XStream這個開源的包,這樣的話,當路由規則文件要新增結點或者某個結點要新增屬性的時候,XStream并不能做到很靈活。此外,CobarInteralRouterXmlFactoryBean中根據路由規則解析文件的時候,基本上都是用if else的語句來做判斷的,這是一種代碼的壞味道。此外,根據之前路由規則的繼承圖可以看到,在具體的路由規則實現類之上,還有三個抽象的路由規則類,我推倒是CobarClient的設計者剛開始的時候,是為了以后的路由規則能夠擴展,但是他最后發現四種規則就能涵蓋一切情況,但是沒有對代碼進行必要的重構。
  • 代碼的風格:這是一個小問題,但是確實很影響代碼的理解。例如在iBatis語境中默認的Sql Id到了IBatisRoutingFact就變成
    private String action了。Rule文件中的namespace到了具體的規則類之中,就變成了private String typePatten。這種情況充斥于整個代碼之中,于是最后你能發現,ICobarRouter的默認實現類是CobarClientInternalRouter而不是DefaultCobarClientInternalRouter。
  • 瑕不掩瑜,如果需要一個輕量級的,支持分布式數據庫的數據訪問層框架,并且應用不需要對于查詢的結果集做過于復雜的排序聚會等操作,CobarClient是一個不錯的選擇。

    轉載于:https://www.cnblogs.com/javanerd/p/3551831.html

    總結

    以上是生活随笔為你收集整理的CobarClient源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。