squbs-23. 資源解決方案

原文地址:Resource Resolution

鑒于很少-如果存在-真實的生活應用可以不依賴外部資源工作,環境識別資源解決方案成為應用基礎設施的一個關鍵部分。squbs通過ResolverRegistry提供資源解決方案,并允許任何類型的資源通過名稱解決,環境指的是在開發環境、測試環境、研發環境下使用不同的資源。

依賴

這個解析器在 squbs-ext。在你的build.sbt或scala構建文件中加入以下依賴:

"org.squbs" %% "squbs-ext" % squbsVersion

用法

Resolver的基礎用法來發現資源。類型由注冊表生產,可以擁有多種類型的資源。在我們的例子中,我們使用 URI類型在本篇文檔中。查找調用如下所示:

Scala
//在指定的環境下處理資源
val resource: Option[URI] = ResolverRegistry(system).resolve[URI]("myservice", QA)

Java
//在指定的環境下處理資源
val resource: Optional<URI> = ResolverRegistry.get(system).resolve(URI.class, "myservice", QA.value());

ResolverRegistry

ResolverRegistry是一個Akka的擴展,并在Scala和Java中遵循Akka擴展使用模式。它可以托管各種類型的資源解釋器,因此通過將它傳遞給register調用在注冊時提供資源類型。同類型或不同類型的多個解釋器可以被注冊。

發現鏈

資源發現遵循后進后出模型。最近注冊的解釋器優先于先前注冊的。ResolverRegistry逐一走鏈直到有一個解釋器兼容該類型并生產資源,或者將鏈走完。在那種情況下,這個注冊表將返回None在Scala API中,在Java API中返回Optional.empty()

類型兼容

在調用 resolve 時, ResolverRegistry 檢查請求類型。如果這個注冊的解釋器的類型與請求類型是同類型或自類型,這個解釋器(resolver )將被用于嘗試通過名稱解釋該資源。

由于JVM類型擦除,注冊類型參數或請求類型不計算在內。舉個例子,一個注冊類型 java.util.ArrayList<String>可能被resolve調用匹配上java.util.List<Int>,因為StringInt 類型在運行時被擦除了。因為這個限制,使用參數類型來注冊和查找通常不建議使用。結果是未定義的-你可能獲得一個錯誤的資源。

簡單的來說,這里不建議使用類型的層次結構。所有注冊的類型應該是唯一類型。

注冊解釋器

這里有兩套解釋器注冊的API風格。一個是一個快捷的API通過傳遞一個閉包/lambda作為解釋器。這個閉包 /lambda返回 Option[T]類型在Scala中,Optional<T>在Java中。另一個,完全的API使用 Resolver[T]在Scala中,AbstractResolver<T>在Java中。T為資源類型。參見如下:

Scala
// To register a new resolver for type URI using a closure. Note the return
// type of the closure must be `Option[T]` or in this case `Option[URI]`
ResolverRegistry(system).register[URI]("MyResolver") { (svc, env) =>
  (svc, env) match {
    case ("myservice", QA) => Some(URI.create("http://myservice.qa.mydomain.com"))
    case ("myservice", Default) => Some(URI.create("http://myservice.mydomain.com"))
    case ("myservice2", QA) => Some(URI.create("http://myservice2.qa.mydomain.com"))
    case ("myservice2", Default) => Some(URI.create("http://myservice2.mydomain.com"))
    case _ => None
  }
}

// To register a new resolver for type URI by extending the `Resolver` trait
class MyResolver extends Resolver[URI] {
  def name: String = "MyResolver"
  
  def resolve(svc: String, env: Environment = Default): Option[URI] = {
    (svc, env) match {
      case ("myservice", QA) => Some(URI.create("http://myservice.qa.mydomain.com"))
      case ("myservice", Default) => Some(URI.create("http://myservice.mydomain.com"))
      case ("myservice2", QA) => Some(URI.create("http://myservice2.qa.mydomain.com"))
      case ("myservice2", Default) => Some(URI.create("http://myservice2.mydomain.com"))
      case _ => None
    }
  }
}

//然后只需要注冊解釋器
ResolverRegistry(system).register[URI](new MyResolver)
Java
// To register a new resolver for type URI using a lambda. Note the return
// type of the lambda must be `Optional<T>` or in this case `Optional<URI>`
ResolverRegistry.get(system).register("MyResolver", (svc, env) -> {
    if ("myservice".equals(svc)) {
        if (QA.value().equals(env)) {
          return Optional.of(URI.create("http://myservice.qa.mydomain.com"));
        } else {
          return Optional.of(URI.create("http://myservice.mydomain.com"));
        }
    } else if ("myservice2".equals(svc)) {
        if (QA.value().equals(env)) {
          return Optional.of(URI.create("http://myservice2.qa.mydomain.com"));
        } else {
          return Optional.of(URI.create("http://myservice2.mydomain.com"));
        }    
    } else {
        return Optional.empty();
    }
});

// To register a new resolver for type URI by extending an abstract class
public class MyResolver extends AbstractResolver<URI> {
    @Override
    public String name() {
        return "MyResolver";
    }
    
    @Override
    public Optional<URI> resolve(String svc, Environment env) {
        if ("myservice".equals(svc)) {
            if (QA.value().equals(env)) {
                return Optional.of(URI.create("http://myservice.qa.mydomain.com"));
            } else {
                return Optional.of(URI.create("http://myservice.mydomain.com"));
            }
        } else if ("myservice2".equals(svc)) {
            if (QA.value().equals(env)) {
                return Optional.of(URI.create("http://myservice2.qa.mydomain.com"));
            } else {
                return Optional.of(URI.create("http://myservice2.mydomain.com"));
            }    
        } else {
            return Optional.empty();
        }
    }
}

// Then register MyResolver.
ResolverRegistry.get(system).register(URI.class, new MyResolver());

解釋資源(Resolving for a Resource)

類似于注冊,解決方案需要一個類型兼容注冊類型;注冊類型必須相同或為解決類型的子類。

Scala
// To resolve a resource with `Default` environment.
val resource: Option[URI] = ResolverRegistry(system).resolve[URI]("myservice")

// To resolve a resource for a specific environment.
val resource: Option[URI] = ResolverRegistry(system).resolve[URI]("myservice", QA)
Java
val resource: Optional<URI> = ResolverRegistry.get(system).resolve(URI.class, "myservice", QA.value());

取消注冊解析器

取消注冊解析器通過名稱使用以下API完成

Scala
ResolverRegistry(system).unregister("MyResolver")
Java
ResolverRegistry.get(system).unregister("MyResolver");

并發考慮

注冊解析器和取消注冊解析器以非并發方式完成,在初始化時間。這里沒有對并發注冊進行保護,因此并發注冊的結果是未定義的。你的解釋器可能,亦或是不可能在一個并發注冊解析器上注冊或取消注冊。

然而,在ResolverRegistry級別上,Resolve調用是線程安全的并且可以無限次的并發訪問。每個注冊解釋器需要線程安全。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,836評論 6 540
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,275評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,904評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,633評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,368評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,736評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,740評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,919評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,481評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,235評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,427評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,968評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,656評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,055評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,348評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,160評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,380評論 2 379

推薦閱讀更多精彩內容