Dropwizard和Protocol Buffers by example

时间:2015-09-10 20:20:29

标签: jersey jax-rs protocol-buffers dropwizard binary-serialization

请注意:虽然这个问题特别提到了Dropwizard,但我相信任何有Jersey / JAX-RS经验的人应该能够回答这个问题,就像我想象的Dropwizard只是遵循Jersey / JAX-RS惯例。

我有一个Dropwizard服务,可以用JSON进行红色/写入并且工作得非常好。

我现在想把它切换到读/写二进制数据(以最小化网络带宽)。我看到有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的{​​{1}}类型的元素。它返回与提供的int匹配的Fizz响应实体。

我想通过Google Protocol Buffers将其从JSON切换为二进制。

根据Dropwizard-Protobuf文档,这就像添加到我的id方法一样简单:

FizzService#run(...)

问题是目前我的整个应用程序都连接到JSON的序列化/反序列化。我的environment.jersey().register(new ProtocolBufferMessageBodyProvider()) 类上的@JsonProperty注释对Dropwizard有意义。 Fizz上的@Produces(MediaType.APPLICATION_JSON)注释也起着至关重要的作用。我担心让我的Dropwizard应用程序读/写protobuf生成的二进制文件并不像文档中发布的1-liner一样简单。

我没跟这个图书馆结婚。如果有人在Dropwizard应用程序中设置REST端点以接受/接收protobuf生成的二进制文件的经验,我所关心的只是一个有效的解决方案。想法?

1 个答案:

答案 0 :(得分:5)

你是对的,它不像一个班轮那么容易。您需要让protobuf生成代码才能正常工作。查看Protocol Buffers Documentation。首先需要一个使用protobuf编译器编译的proto文件,它会为您生成代码。生成的代码就是您用来构建域/模型对象的代码。 Dropwizard的protobuf提供程序可以处理这个编译过的代码。无论您是否使用Dropwizard提供程序,您仍然需要使用生成的代码。请参阅上面链接中的“我如何开始”部分。

获得生成的代码之后,在资源方法中,生成的类/类型是您需要返回的内容,供提供程序能够序列化它。您还需要在资源方法或资源类上使用@Produces("application/x-protobuf")@Produces(ProtocolBufferMediaType.APPLICATION_PROTOBUF),因此Jersey知道如何查找媒体类型的提供程序。

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

但并非如此。由于您需要返回两种不同的类型,即简单的JJ POJO或Protobuf的生成类型,您需要检查资源方法中的标题

@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标头,这都是将被发送出去的类型。例如Accept: application/jsonAccept: application/x-protobuf

另见: