Dropwizard 和 Protocol Buffers 的例子

Dropwizard and Protocol Buffers by example

请注意:虽然这个问题特别提到了Dropwizard,但我相信有Jersey/JAX-RS经验的人应该能够回答这个问题,正如我想象的那样,Dropwizard 只是在幕后遵循 Jersey/JAX-RS 约定。


我有一个 Dropwizard 服务,reds/writes 在 JSON 中运行得很好。

我现在想将其切换为 read/write 二进制数据(以最小化网络带宽)。我看到有 Dropwizard-Protobuf lib 但我对在 Dropwizard 中实现二进制序列化有一些担忧。

首先,这是我当前(JSON 中心)代码中的重要内容:

// Groovy pseudo-code

// Domain entity/POJO
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
class Fizz {
    @JsonProperty
    String name

    @JsonProperty
    boolean isBuzz    
}

// The Dropwizard app entry point
class FizzService extends Application<FizzConfiguration> {
    @Override
    void run(FizzConfiguration fizzCfg, Environment env) throws Exception {
        // ... lots of stuff

        env.jersey().register(new FizzService())
    }
}

// JAX-RS resource with a sample GET endpoint
@Path(value = "/fizz")
@Produces(MediaType.APPLICATION_JSON)
class FizzResource {
    @GET
    @Path("/{id}")
    Fizz getFizzById(@PathParam("id") int id) {
        // Look up a 'Fizz' in a DB and return it.
        lookupFizzinDB(id)
    }
}

因此,如您所见,GET /fizz 端点需要一个 JSON 请求实体,其中包含一个名为 id 且类型为 int 的元素。它 returns 与提供的 id.

相匹配的 Fizz 响应实体

我想通过 Google Protocol Buffers.

将其从 JSON 切换为二进制

根据 Dropwizard-Protobuf 文档,这就像将其添加到我的 FizzService#run(...) 方法一样简单:

environment.jersey().register(new ProtocolBufferMessageBodyProvider())

问题是目前我的整个应用程序连接到 serialize/deserialize to/from JSON。我的 Fizz class 上的 @JsonProperty 注释对 Dropwizard 有意义。 FizzResource 上的 @Produces(MediaType.APPLICATION_JSON) 注释也起着关键作用。我担心制作我的 Dropwizard 应用程序 read/write protobuf 生成的二进制文件不像文档中发布的 1-liner 那样容易。

我没有和这个图书馆结婚。如果有人有任何在 Dropwizard 应用程序中将 REST 端点设置为 accept/receive protobuf 生成的二进制文件的经验,我所关心的只是一个有效的、高效的解决方案。想法?

你说得对,它不像单线那么容易。您需要让 protobuf 生成代码才能工作。查看 Protocol Buffers Documentation。您首先需要有一个使用 protobuf 编译器编译的 proto 文件,它会为您生成代码。此生成的代码是您用来构建 domain/model objects 的代码。来自 Dropwizard 的 protobuf 提供程序使用此编译代码。无论您是否使用 Dropwizard 提供程序,您仍然需要使用生成的代码。见上文link."How do I start"部分。

生成代码后,在您的资源方法中,生成的 class/type 是您需要 return 以便提供程序能够对其进行序列化的内容。您还需要在资源方法或资源 class 上设置 @Produces("application/x-protobuf")@Produces(ProtocolBufferMediaType.APPLICATION_PROTOBUF),以便 Jersey 知道如何找到媒体类型的提供者。

您可以同时支持 application/jsonapplication/x-protobuf,因为您可以在 @Produces 中拥有不止一种媒体类型。只需使用语法 @Produces({ .. , .. }).

但这还不是全部。由于您将需要 return 两种不同的类型,即 JSON 的简单 POJO 或 Protobuf 的生成类型,您将需要检查资源方法中的 header

@Produces({"application/json", "application/x-protobuf"})
public Response getFoo(@Context HttpHeaders headers) {
    List<MediaType> accepts = headers.getAcceptableMediaTypes();
    if (accepts.contains(MediaType.APPLICATION_JSON_TYPE) {
        return Response.ok(new Foo());
    } else if (accepts.contains(ProtocolBufferMediaType.APPLICATION_PROTOBUF_TYPE) {
        return Reponse.ok(new ProtoBufFoo());
    } else {
        // default
        return Response.ok(new Foo());
    }
}

或者你可以有两种不同的方法,每种方法一种

@Produces("application/json")
public Response getFooJson() {
    return Response.ok(new Foo());
}

@Produces("application/x-protobuf")
public Response getFooProto() {
    return Response.ok(new ProtoBufFoo());
}

无论客户端发送什么作为它的Accept header,这就是将被发送出去的类型。例如 Accept: application/jsonAccept: application/x-protobuf

另请参阅: