protobuf和springboot的结合

protobuf的java example见:protobuf的java学习版

在那篇文章中我们也说了,protobuf仅用于一些对性能要求特别高的场景,缺点就是和传统的java编程还是有一些不耦合的地方,需要进行转换,导致了编程有些麻烦。

在这篇文章中,我们来看一下 protobuf如何和springboot进行结合:

  1. 新建一个maven的springboot工程,在这个工程的pom中加入依赖:
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java-util</artifactId>
            <version>3.10.0</version>
        </dependency>
        <dependency>
            <groupId>com.googlecode.protobuf-java-format</groupId>
            <artifactId>protobuf-java-format</artifactId>
            <version>1.4</version>
        </dependency>
  1. 本例子还是使用官方的 addressbook.proto 这个例子,对这个文件中的java输出包改成:
    option java_package = “com.champbay.blog.protobuf.model”;
    其他不变,然后在这个目录中运行:protoc –java_out=. addressbook.proto,将生成 com/champbay/blog/protobuf/model/AddressBookProtos.java

  2. 创建一个Configuration来加载 ProtobufHttpMessageConverter 的Bean

package com.champbay.blog.protobuf.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;

@Configuration
public class WebConfig {

    @Bean
    ProtobufHttpMessageConverter protobufHttpMessageConverter() {
        return new ProtobufHttpMessageConverter();
    }

}

此 ProtobufHttpMessageConverter 的作用是对 protobuf 进行 encode 和 decode

  1. 创建一个 Rest Controller:
package com.champbay.blog.protobuf.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.champbay.blog.protobuf.model.AddressBookProtos;
import com.champbay.blog.protobuf.model.AddressBookProtos.Person;

@Controller
public class TestController {

    @RequestMapping(value = "/test", consumes = "application/x-protobuf", produces = "application/x-protobuf")
    @ResponseBody
    public AddressBookProtos.Person getPersonProto(@RequestBody AddressBookProtos.Person person) {
        System.out.println("id: " + person.getId());
        System.out.println("name: " + person.getName());
        System.out.println("email: " + person.getEmail());

        //这个地方需要加入将protobuf的对象转换成普通的java pojo的方法 !

        Person.Builder builder = Person.newBuilder();
        builder.setId(2);
        builder.setName("myhello");
        builder.setEmail("myhello@aaa.com");

        return builder.build();
    }

}

从这个类中能看到需要加入将protobuf的对象转换成普通的java pojo的方法,这个方法可以参考: Protobuf与POJO的相互转化 – 通过Json,也能看出protobuf要想方便使用,这个道路还是比较难的,可谓是“鱼和熊掌不可兼得”

5,最后通过 HttpClient 来调用这个 rest。

具体可以见源代码:https://github.com/champbay/protobuf-springboot-test

protobuf的java学习版

protobuf 和 springboot 的相结合,可以参见另外一篇博文 《protobuf和springboot的结合》

protobuf 是 protocal buffers的简称,是google研发的一种数据传输格式。

我们常用的数据格式是json,或者xml,这2种都是文本型格式,特点是容易被人识别,非常容易编程,缺点是数据量有点大。

在有一些场景下,比如帧同步、各个应用之间的同步信息,这样的场景往往是并发高、发送/接收密集,假如用json来传输,那么性能上就会大受影响,所以能否有另外一种数据传输格式,能有效解决这个问题,这就是protobuf上场的原因,protobuf是采用字节流的方式进行传输,通过一些约定使得比json的传输量大为减少。

个人认为,为了使得各种方便,在绝大多数场景下都优先考虑json格式,因为protobuf的格式对于编程、维护都太麻烦 了。这大概就是为什么protobuf出来了这么多年,但是不流行的原因,因为可以用的场景太少太少。

官方自带的protobuf examples,里面融合了很多其他的语言,并且采用的方式用的是 make,不直观,于是我把这个examples中的java部分选出来单独做成一个工程:

  1. 在eclipse中,新建一个java的maven工程,在这个工程的pom中加入依赖:
<dependency>
  <groupId>com.google.protobuf</groupId>
  <artifactId>protobuf-java</artifactId>
  <version>3.10.0</version>
</dependency>
  1. https://github.com/protocolbuffers/protobuf/tree/master/examples 中,将 addressbook.proto 下载到该工程中。同时将AddPerson.java和ListPeople.java也下载到工程中。addressbook.proto这个文件是类的定义文件,不是像以前那样直接在java中写java类,而是先写这个定义文件,这个文件的规范见:https://developers.google.com/protocol-buffers/docs/proto3,也可以网上搜索protobuf的中文版规范(都是机器翻译的,勉强能看)。在这个规范中:除了空行和注释以外,syntax = “proto3″必须放在第一行。也就是说第一行可以是空行、注释,紧接着必须是 syntax = “proto3″。
  2. 接着需要有个工具将 addressbook.proto 转换成相应的 java 类,到 https://github.com/protocolbuffers/protobuf/releases 下载对应操作系统的转换工具,下载好后解压即可使用,比如我下载的 protoc-3.10.1-win64.zip 这个,解压好后,需要将路径加入到操作系统的 PATH 中以方便调用,测试一下:
    protoc –version #能显示版本号就表明可以使用
  3. 进入操作系统的console(linux是shell),进入addressbook.proto这个文件所在的文件夹,运行:protoc –java_out=. addressbook.proto,运行后将在当前目录下生成 com/example/tutorial/AddressBookProtos.java这个类,然后查看AddressBookProtos.java这个类,可以看到其中包含2个实体Bean:
com.example.tutorial.AddressBookProtos.AddressBook
com.example.tutorial.AddressBookProtos.Person

从中也可以间接知道,这种写法和传统的java写法有了很大的区别,所以这些就是protobu使用上非常难用的地方。
5. 可以运行 AddPerson.java 和 ListPeople.java 这两个类来看看 protobuf 是如何序列化和反序列化的。

这个工程的源代码见:https://github.com/champbay/protobuf-java-test