五分钟为HTTP接口提供Java/Scala SDK

Case描述

我现在要使用yarn的两个接口,一个是application 列表,一个是根据appId获取这个app的详情。对应的接口大约如此:

http://[dns]/ws/v1/cluster/apps
http://[dns]/ws/v1/cluster/apps/{appId}

基于HttpClient的初级封装

基于HttpClient的一个典型封装如下:

public interface HttpTransportService {

    public SResponse post(Url url, Map data);

    public SResponse post(Url url, Map data, Map<String, String> headers);

    public SResponse post(final Url url, final Map data, final int timeout);

    public SResponse post(final Url url, final Map data, final Map<String, String> headers, final int timeout);

    public SResponse get(final Url url, final int timeout);

    public SResponse get(Url url);

    public SResponse get(Url url, Map<String, String> data);

    public SResponse get(final Url url, final Map<String, String> data, final int timeout);

    public SResponse put(Url url, Map data);

更详细的代码可以参看我以前的开源项目里的实现:HttpTransportService.java

然而这种使用比较原始,不直观。

大致使用方法如下:

SResponse  response = HttpTransportService.get(new Url("http://[dns]/ws/v1/cluster/apps/"+appId))
if(response.getStatus==200){
  //parse result like JSONObject.parse(response.getContent())
}else{
//blabla
}

所以一般如果提供了HTTP 接口的项目都会给你一个SDK,方便你做调用,帮你屏蔽掉HTTP的细节。

总体而言你有如下几种选择:

  1. 直接使用上面的封装
  2. 使用第三方SDK
  3. 自己再做一些封装,转化为普通的方法调用

第三种方案一般会是这样:

def app(appName:String):YarnApplication = {
// 实现http接口请求解析逻辑
}

虽然麻烦了些,但是调用者会比较幸福。

其实可以更简单

只要三步,就可以实现第三个方案:

  1. 定义一个接口
  2. 获取这个接口的引用
  3. 尽情使用

定义一个接口:

trait YarnController {

  @At(path = Array("/ws/v1/cluster/apps"), types = Array(RestRequest.Method.GET))
  def apps(@Param("states") states: String): java.util.List[HttpTransportService.SResponse]

  @At(path = Array("/ws/v1/cluster/apps/{appId}"), types = Array(RestRequest.Method.GET))
  def app(@Param("appId") appId: String): java.util.List[HttpTransportService.SResponse]

}

At 注解定义了 path路径以及Action Method。 方法参数决定了传递的参数。

对于同一个http接口,你也可以定义多个方法。比如,

trait YarnController {

  @At(path = Array("/ws/v1/cluster/apps"), types = Array(RestRequest.Method.GET))
  def apps(@Param("states") states: String): java.util.List[HttpTransportService.SResponse]

  @At(path = Array("/ws/v1/cluster/apps"), types = Array(RestRequest.Method.GET))
  def runningApps(@Param("states") states: String="running"): java.util.List[HttpTransportService.SResponse]

}

这样你直接调用runningApps 就可以拿到特定状态的应用,而无需传递参数。如果参数较多,你还可以指定哪些参数不传,哪些传。

接着初始化 YarnController,获得对象的引用,代码如下:

val yarnRestClient: YarnController =
AggregateRestClient.buildIfPresent[YarnController]
(hostAndPort,
firstMeetProxyStrategy,
RestClient.transportService)
  • hostAndPort 是yarn的地址
  • firstMeetProxyStrategy 指定如果后端有多个实例时的访问策略
  • RestClient.transportService 就是我上面的最基础的封装HttpTransportService

理论上后面两个参数可以不用传递

这个时候你就可以直接使用获得的YarnController对象了。具体使用方式如下:

val result:java.util.List[HttpTransportService.SResponse] = yarnRestClient.apps()

上面就是你要做的所有工作,系统自动帮你实现了HTTP调用。

我希望返回结果是一个Bean

前面的放回结果是个List[SResponse]对象。我希望它是个Bean对象。所以我定义一个Bean类:

class YarnApplication(val id: String,
                            var user: String,
                            var name: String,
                            var queue: String,
                            var state: String,
                            var finalStatus: String,
                            var progress: Long,
                            var trackingUI: String,
                            var trackingUrl: String,
                            var diagnostics: String,
                            var clusterId: Long,
                            var applicationType: String,
                            var applicationTags: String,
                            var startedTime: Long,
                            var finishedTime: Long,
                            var elapsedTime: Long,
                            var amContainerLogs: String,
                            var amHostHttpAddress: String,
                            var allocatedMB: Long,
                            var allocatedVCores: Long,
                            var runningContainers: Long,
                            var memorySeconds: Long,
                            var vcoreSeconds: Long,
                            var preemptedResourceMB: Long,
                            var preemptedResourceVCores: Long,
                            var numNonAMContainerPreempted: Long,
                            var numAMContainerPreempted: Long)

然后引入一个隐式转换

import ..... SReponseConvertor ._
val result:Map[Map[String,List[YarnApplication]]]= yarnRestClient.apps().extract[Map[Map[String,List[YarnApplication]]]]

result("apps")("app") //这样就能拿到List[YarnApplication]

SReponseConvertor 给List[SReponse]对象添加了一个新的extract 方法。当然前提是List[SReponse] 里是一个JSON格式的数据。

因为yarn的接口返回的格式比较诡异,嵌套了两层,第一层是apps,第二层是app,第三层才是具体的List对象。所以有了上面的复杂形态。那我如何简化呢?每次调用都这么搞,太复杂了。

那么自己实现一个隐式转换就行了,定义一个YarnControllerE类,

object YarnControllerE {
  implicit def mapSResponseToObject(response: java.util.List[HttpTransportService.SResponse]): SResponseEnhance = {
    new SResponseEnhance(response)
  }
}

import scala.collection.JavaConversions._

class SResponseEnhance(x: java.util.List[HttpTransportService.SResponse]) {

  private def extract[T](res: String)(implicit manifest: Manifest[T]): T = {
    if (x == null || x.isEmpty || x(0).getStatus != 200) {
      return null.asInstanceOf[T]
    }
    implicit val formats = SJSon.DefaultFormats
    SJSon.parse(res).extract[T]
  }

  def list(): List[YarnApplication] = {
    val item = extract[Map[String, Map[String, List[YarnApplication]]]](x(0).getContent)
    return item("apps")("app")
  }

现在你可以很帅气这样调用了:

import ..... YarnControllerE ._
val result: List[YarnApplication] = yarnRestClient.apps().list

这样我们就可以像RPC一样访问一个HTTP接口了。

背后的机制

核心代码其实是这个:

val yarnRestClient: YarnController =
AggregateRestClient.buildIfPresent[YarnController]
(hostAndPort,
firstMeetProxyStrategy,
RestClient.transportService)

AggregateRestClient 会帮你把YarnController 自动实现了。实现的机制很简单就是 JDK 的 Proxy机制。具体源码可以参看:AggrateRestClient.scala以及RestClientProxy.java

时间: 2024-11-09 00:16:16

五分钟为HTTP接口提供Java/Scala SDK的相关文章

五分钟卖道具赚第一桶金开心农场首日赚8千元

徐城 从默默无闻到嫁入豪门,"开心农场"这款风靡国内社交网站的Social Game引起了各方的关注.相比一年前一战成名的辉煌时刻,游戏开发商.五分钟公司COO徐城如今沉默了很多,尤其是在与腾讯的"特殊合作"一事上. 一份来自香港MainFirst证券有限公司的投资报告中,"开心农场能够提升利润率.腾讯一次性斥资数百万元购买了这款游戏,因此不存在收入分成问题"的描述,外界解读为腾讯买断了"开心农场"的全部运营权. 徐城否认了这

五分钟徐城从成名到沉默

从默默无闻到嫁入豪门,"开心农场"这款风靡国内社交网站的Social G am e引起了各方的关注.相比一年前一战成名的辉煌时刻,游戏开发商.五分钟公司CO O徐城如今沉默了很多,尤其是在与腾讯的"特殊合作"一事上. 一份来自香港M ainFirst证券有限公司的投资报告中,"开心农场能够提升利润率.腾讯一次性斥资数百万元购买了这款游戏,因此不存在收入分成问题"的描述,外界解读为腾讯买断了"开心农场"的全部运营权. 徐城否认了

在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口

 在上两篇文章中,我们介绍了如何为Android系统的硬件编写驱动程序,包括如何在Linux内核空间实现内核驱动程序和在用户空间实现硬件抽象层接口.实现这两者的目的是为了向更上一层提供硬件访问接口,即为Android的Application Frameworks层提供硬件服务.我们知道,Android系统的应用程序是用Java语言编写的,而硬件驱动程序是用C语言来实现的,那么,Java接口如何去访问C接口呢?众所周知,Java提供了JNI方法调用,同样,在Android系统中,Java应用程序通

Ubuntu中为Android HAL编写JNI方法提供JAVA访问硬件服务接口_Android

 在上两篇文章中,我们介绍了如何为Android系统的硬件编写驱动程序,包括如何在Linux内核空间实现内核驱动程序和在用户空间实现硬件抽象层接口.实现这两者的目的是为了向更上一层提供硬件访问接口,即为Android的Application Frameworks层提供硬件服务.我们知道,Android系统的应用程序是用Java语言编写的,而硬件驱动程序是用C语言来实现的,那么,Java接口如何去访问C接口呢?众所周知,Java提供了JNI方法调用,同样,在Android系统中,Java应用程序通

Ubuntu中为Android HAL编写JNI方法提供JAVA访问硬件服务接口

在上两篇文章中,我们介绍了如何为Android系统的硬件编写驱动程序,包括如何在Linux内核空间实现内核驱动程序和在用户空间实现硬件抽象层接口.实现这两者的目的是为了向更上一层提供硬件访问接口,即为Android的Application Frameworks层提供硬件服务.我们知道,Android系统的应用程序是用Java语言编写的,而硬件驱动程序是用C语言来实现的,那么,Java接口如何去访问C接口呢?众所周知,Java提供了JNI方法调用,同样,在Android系统中,Java应用程序通过

五分钟快速打造美观实用的线上个人简历网站

  本文要介绍的 Resumator 能让你快速在在线制作个人简历.Resumator 建立起来的个人页面非常美观.大方,而且没有太多复杂流程,你需要做的是依照网站提供的字段进行填写,最终就能产生属于你的在线页面专属网址.不妨来试一试 Resumator 背后是由一家名为 Qwilr 的公司所提供,Qwilr 主要营运的项目为简单建立网页服务,结合易用性和所见即所得等编辑功能,用户能在在线制作出具有美感且动态的网页效果. 从无到有建立一个在线名片并不是很容易,有了 Resumator 交互式在线

如何编写属于自己的Java / Scala的调试器

译者:赖辉强  原文地址 在本帖中,我们将探讨Java和Scala的调试器是如何编写和工作的:系统自带的调试器,例如:Windows中的WinDbg或者是Linux/Unix中的gdb,会获取操作系统直接提供给他们的链接入口来启动,从而指导和操作外部程序的状态.工作在操作系统顶部抽象层的Java虚拟机对字节码的调试有独立的处理架构. 这个调试的框架和APIs具有全开源.文档化.可扩展的特点,这意味着你可以轻松毫无顾忌的编写自己的调试器.该框架当前的设计由两大部分构成-JDWP协议和JVMTI A

微信公众号图片上传-微信公众号上传多媒体文件接口用JAVA怎么实现

问题描述 微信公众号上传多媒体文件接口用JAVA怎么实现 根据图片的描述是通过发送https请求上传图片.微信公众号提供的文档是通过curl命令来实现发送https post请求,但是我现在的程序是通过java程序来发送https post请求.以下是我的3个问题: 1.既然是发送https post请求上传图片,java应该也可以实现,我只实现过java https post的简单请求,没有实现过java https post图片上传.有大神能帮帮我吗? 2.既然微信公众号文档上说是通过cur

利用PAPI接口监测Java程序的硬件执行特征

简介:PAPI 是一组用于访问处理器硬件性能计数器的本地接口,利用这一接口对 Java 程序的硬件执 行特征进行监测将有助于在计算机系统的硬件层上发现程序性能问题的根源所在.本文介绍了 PAPI 的重 要概念及其常用接口,分析了将其应用于 Java 程序性能测评的要点和难点,提出一种基于 JVMTI 接口 的方法实现了利用 PAPI 接口监测 Java 程序的运行时硬件执行特征. PAPI 接口概览 在计算机系统的硬件层对 Java 程序的性能进行测评与分析,有助于发现程序 性能问题的根源所在.