美文网首页
[翻译]squbs官网之19 资源解析

[翻译]squbs官网之19 资源解析

作者: 乐言笔记 | 来源:发表于2017-10-23 19:43 被阅读11次

    鉴于现实生活中极少的应用不使用外部资源,因此环境感知的资源解析称为应用程序基础结构的关键部分。squbs 通过 ResolverRegistry 提供资源解析, 并允许任何类型的资源通过名称和环境来解决。后者允许在生产、qa 和开发环境之间区分资源。

    资源解析的示例是 HTTP 端点、消息传递端点和数据库。所有这些都由一个单一的注册中心处理。

    依赖

    解析器位于squbs-ext。添加如下依赖:

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

    用法

    Resolver 基本用法是查找资源。需要提供一个类型, 因为注册表可以持有多种类型的资源, 如 HTTP 端点、消息端点或数据库连接。本文档中的示例中使用了类型 URI。查找调用,如下所示:

    // To resolve a resource for a specific environment.
    val resource: Option[URI] = ResolverRegistry(system).resolve[URI]("myservice", QA)
    

    ResolverRegistry

    ResolverRegistry是一个Akka扩展,遵循Akka扩展使用模式。它可以托管各种类型的资源解析器,因此必须提供资源类型(在注册时,将资源类型传递给注册器调用)。可以注册相同类型或多个类型的多个解析器。

    注册解析器

    有两种风格的API用于解析器的注册。一个是快捷 API,允许传入闭包或 lambda 作为解析器。闭包或者lambda的返回类型必须是Option[T]。另一个完整的API使用Resolver [T],T是资源类型。如下所示:

    // 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
        }
      }
    }
    
    // Then just register the instance
    ResolverRegistry(system).register[URI](new MyResolver)
    

    发现链

    资源发现遵循后进先出模型。最近注册的解析器优先于以前注册的解析器。ResolverRegistry 沿着链一个一个地遍历,直到有一个解析器与资源所给的类型兼容或者链已搜索到尽头(这种情况下,返回None)。

    类型兼容

    ResolverRegistry 在解析调用时检查请求的类型。如果注册的解析器的类型是请求类型的同一类型或子类型, 则该解析器将尝试按名称解析资源。

    由于JVM类型擦除,注册的类型的类型参数或者请求的类型的类型参数无法考虑。例如,一个注册类型java.util.List<String>会与解析调用的类型java.util.List<Int>相匹配,因为类型参数String或Int运行时擦除了。由于这个限制,非常不推荐含有类型参数的类型用于注册和查找。结果未定义——可能只是由于使用了错误的资源。

    为了简单起见,强烈建议不要使用类型层次结构。 所有注册的类型应该是不同的类型。

    资源解析

    与注册类似, 解析要求类型与注册类型兼容;已注册的类型必须是解析类型的相同或子类型。
    // To resolve a resource with Default environment.
    val resource: Option[URI] = ResolverRegistry(system).resolveURI

    // To resolve a resource for a specific environment.
    val resource: Option[URI] = ResolverRegistry(system).resolve[URI]("myservice", QA)

    注销解析器

    使用下面的API,通过名称注销。

    ResolverRegistry(system).unregister("MyResolver")
    

    并发注意事项

    解析器注册和注销调用应当在初始化时以非并发的方式。对于并发注册没有任何保障, 因此并发注册的结果是未定义的。在并发下注册或注销,你的解析器可能是注册的,也可能不是。

    但是, 解析调用是线程安全的, 可以同时访问, 而不受 ResolverRegistry 级别的限制。每个已注册的解析器都需要线程安全。

    相关文章

      网友评论

          本文标题:[翻译]squbs官网之19 资源解析

          本文链接:https://www.haomeiwen.com/subject/xsyauxtx.html