protobuf有效载荷大于JSON?

时间:2016-07-07 12:18:03

标签: java json protocol-buffers protostuff

我有一个对象是' Level'对象和我测试用Spring Boot Rest Controller以两种方式传输它们:

  1. 使用JSON,在Rest Controller中我使用类似的东西:

     @RequestMapping(value = "/api/v1/layers/{layername}", method =         RequestMethod.GET, produces = "application/json")
     public @ResponseBody List<Level>  query(@PathVariable String layername,
                   @RequestParam("northEastLat") Float northEastLat,
                   @RequestParam("northEastLng") Float northEastLng,
                   @RequestParam("northWestLat") Float northWestLat,
                   @RequestParam("northWestLng") Float northWestLng,
    
                   @RequestParam("southEastLat") Float southEastLat,
                   @RequestParam("southEastLng") Float southEastLng,
                   @RequestParam("southWestLat") Float southWestLat,
                   @RequestParam("southWestLng") Float southWestLng
    ) {
    
    List<Level> poligons=levelService.obtainLevels(layername,southWestLng,southWestLat,northWestLng,northWestLat,northEastLng,northEastLat,southEastLng,southEastLat);
    int i=1;
    for (Level p : poligons) {
    
        System.out.println("poligon" + i++ + " is:" + p.toString());
    }
    
    return poligons;
    }
    
  2. 使用Protostuff Protobuf格式,我使用类似的东西:

      @RequestMapping(value = "/api/v1/layers/{layername}", method = RequestMethod.GET,produces = "text/plain")
      public String query(@PathVariable String layername,
                    @RequestParam("northEastLat") Float northEastLat,
                    @RequestParam("northEastLng") Float northEastLng,
                    @RequestParam("northWestLat") Float northWestLat,
                    @RequestParam("northWestLng") Float northWestLng,
    
                    @RequestParam("southEastLat") Float southEastLat,
                    @RequestParam("southEastLng") Float southEastLng,
                    @RequestParam("southWestLat") Float southWestLat,
                    @RequestParam("southWestLng") Float southWestLng
      ) {
    
    
    List<Level> poligons=levelService.obtainLevels(layername,southWestLng,southWestLat,northWestLng,northWestLat,northEastLng,northEastLat,southEastLng,southEastLat);
    LevelList list = new LevelList(poligons);
    
    byte[] bytes;
    
    int i=1;
    for (Level p : poligons) {
    
        System.out.println("poligon" + i++ + " is:" + p.toString());
    }
    
    Schema<LevelList> schema = RuntimeSchema.getSchema(LevelList.class);
    LinkedBuffer buffer = LinkedBuffer.allocate();
    
    
    
    try
    {
        bytes = ProtostuffIOUtil.toByteArray(list, schema, buffer);
    }
    finally
    {
        buffer.clear();
    }
    
     return new String(bytes);
    }
    
  3. Level对象格式为: [{&#34; wkb_geometry&#34;:&#34; {&#34;类型&#34;:&#34;多边形&#34;&#34;坐标&#34;:[[[24.446822,45.34997] [24.706508,45.352485]]]}&#34;&#34; ID&#34; 199&#34;电平&#34;:&#34; 3&#34;&#34;类型&#34 ;日期null}

    Level对象是:

    @Entity(name = "Level")
    @Table(name="Level2G")
    @SecondaryTables({
        @SecondaryTable(name="Level3G"),
        @SecondaryTable(name="Level4G")
    })
    public class Level implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    // @Column(name = "wkb_geometry",columnDefinition="Geometry")
    //@Type(type = "org.hibernate.spatial.GeometryType")
    @Column(name="wkb_geometry")
    private /*Geometry */ String  wkb_geometry;
    
    @Id
    @Column(name="id")
    private Integer id;
    
    
    @Column(name="level")
    private String level;
    
    @Transient
    private String type;
    
    public Level() {
    }
    
    public Level(String  wkb_geometry, Integer id, String level) {
        this.wkb_geometry = wkb_geometry;
        this.id = id;
        this.level = level;
        this.type = "Feature";
    }
    
    public Level(String  wkb_geometry, Integer id, String level, String type) {
        this.wkb_geometry = wkb_geometry;
        this.id = id;
        this.level = level;
        this.type = type;
    }
    
    public Object getWkb_geometry() {
        return wkb_geometry;
    }
    
    public void setWkb_geometry(String  wkb_geometry) {
        this.wkb_geometry = wkb_geometry;
    }
    
    public Integer getId() {
        return id;
    }
    
    public void setId(Integer id) {
        this.id = id;
    }
    
    public String getLevel() {
        return level;
    }
    
    public void setLevel(String level) {
        this.level = level;
    }
    
    public String getType() {
        return type;
    }
    
    public void setType(String type) {
        this.type = type;
    }
    
    @Override
    public String toString() {
        return "Level{" +
                "wkb_geometry=" + wkb_geometry +
                ", id=" + id +
                ", level='" + level + '\'' +
                ", type='" + type + '\'' +
                '}';
    }
     }
    

    LevelList对象只是Level对象列表

    问题是,使用Protostuff,与JSON(3.7kb)相比,我获得了更大的有效载荷(26 kb)。为什么呢?

    对于第二个选项,我也尝试设置&#34; application / octet-stream&#34;直接返回字节但仍然是相同的结果。我还比较了JSON和protobuf的速度; protobuf具有更好的性能,即使有更大的有效载荷。知道为什么吗?

2 个答案:

答案 0 :(得分:1)

Protostuff和Protobuf不是一回事。 Protostuff是一个包装库,可以使用许多不同的序列化格式。它还支持您似乎正在使用的运行时模式生成。该运行时架构需要发送额外的元数据以及消息,以告知接收者消息的架构。我猜你所看到的大型消息主要来自这个运行时架构数据。

使用标准的Protobuf,架构不会随消息一起发送,因为假设发件人和收件人已经就编译到两个程序中的.proto文件提供的架构达成一致。如果您使用带有标准.proto文件的Protobuf,您会发现它生成的消息比JSON小得多。

答案 1 :(得分:0)

您的测试中至少有一个问题。

从字节数组到String的转换无效:

bytes = ProtostuffIOUtil.toByteArray(list, schema, buffer);
return new String(bytes);

String的构造函数将尝试将字节数组解析为UTF-8字符串(最可能;取决于您的语言环境设置),但根据定义给定的数据不是有效的UTF-8字符串。

如果您想进行更好的尺寸比较,您应该以下列形式编写测试:

LevelList source = testData();
byte[] jsonData = generateJson(source);
byte[] protobufData = generateProtobuf(source);
System.out.println("JSON=" + jsonData.size() + " Protobuf=" + protobufData.size());

这里的要点是让你的测试可以重现,以便其他人可以重复它。