java 怎么使用protobuf库

java 怎么使用protobuf库,第1张

1.到http://code.google.com/p/protobuf/downloads/list ,选择其中的win版本下载,我选择的是protoc-2.4.1-win32.zip

2.下载一个protobuf-java-2.4.1.jar文件(注意,要与你刚才下的proto.exe版本相同)

然后就开始开发了。

步骤:

1.用记事本编写一个.proto文件:

}如:编写的是test.proto

package protobuf

option java_package = "com.sq.protobuf"

option java_outer_classname = "FirstProtobuf"

message testBuf {

required int32 ID = 1

required string Url = 2

}

将其放在与刚解压的protoc.exe同级目录中。

2.在cmd中,到protoc-2.4.1-win32文件夹下,

执行

E:\protoc-2.4.1-win32>protoc.exe --java_out=./ test.proto

则可以找到的一个生成的FirstProtobuf.java文件。

3.在MyEclipse中新建一个java project,建立包com.sq.protobuf,然后将刚才生成的FirstProtobuf.java文件放在其下面。

此时会报错,因为没有引入jar包,在package视图下,将protobuf-java-2.4.1.jar引入,即可解决问题。

4.建立测试文件:

package com.sq.protobuf.test

import java.io.ByteArrayInputStream

import java.io.InputStream

import java.sql.Blob

import java.sql.Connection

import java.sql.DriverManager

import java.sql.PreparedStatement

import java.sql.ResultSet

import java.sql.Statement

import com.google.protobuf.InvalidProtocolBufferException

import com.sq.protobuf.FirstProtobuf

public class Test {

public static void main(String[] args) {

//序列化过程

//FirstProtobuf是生成类的名字,即proto文件中的java_outer_classname

//testBuf是里面某个序列的名字,即proto文件中的message testBuf

FirstProtobuf.testBuf.Builder builder=FirstProtobuf.testBuf.newBuilder()

builder.setID(777)

builder.setUrl("shiqi")

//testBuf

FirstProtobuf.testBuf info=builder.build()

byte[] result = info.toByteArray()

String driver = "oracle.jdbc.driver.OracleDriver"

String url = "jdbc:oracle:thin:@10.64.59.12:1521/orcl"

String user = "parkingsystem"

String password = "parkingsystem"

try {

Class.forName(driver)

Connection conn = DriverManager.getConnection(url, user, password)

if(!conn.isClosed()){

System.out.println("Succeeded connecting to the Database!")

//此处只能使用prepareStatement

PreparedStatement ps = conn.prepareStatement("insert into test(id,test) values (1,?)")

//写入数据库,要把它改写为流的形式

ByteArrayInputStream stream = new ByteArrayInputStream(result)

ps.setBinaryStream(1,stream,stream.available())

Statement statement = conn.createStatement()

Blob blob = null

ps.execute()

////////////////上述完成将写入数据库的 *** 作,数据库中对应的字段的属性要设置为Blob

String sql = "select test from test"

ResultSet rs = statement.executeQuery(sql)

if(rs.next()){

blob = rs.getBlob("test")

}

byte[] s = blob.getBytes(1,(int)blob.length())

FirstProtobuf.testBuf testBuf = FirstProtobuf.testBuf.parseFrom(s)

System.out.println(testBuf)

conn.close()

}

}catch(Exception e) {

e.printStackTrace()

}

//反序列化过程

try {

FirstProtobuf.testBuf testBuf = FirstProtobuf.testBuf.parseFrom(result)

System.out.println(testBuf)

} catch (InvalidProtocolBufferException e) {

e.printStackTrace()

}

}

}

发现可以将其序列化,插入到数据库,并可以从数据库出取出后,反序列化,内容可以正常显示出来。

注意的就是2点:

1.不能用statement,否则无法插入blob类型的数据

2.为参数赋值时,要用

ByteArrayInputStream stream = new ByteArrayInputStream(result)

ps.setBinaryStream(1,stream,stream.available())

我使用protobuf,之前只是用于移动端的数据传输。当数据到了服务器需要进数据库时候就重新把数据取出来通过服务器端的数据模型存入数据库。并不会直接把protobuf对象放进数据库。利用protobuf存放数据没有问题,2进制数据流体积很小大可放心。

Protobuf 是经过深思熟虑的消息打包方案,它的默认序列化格式没有包含消息的长度与类型,自然有其道理。哪些情况下不需要在 protobuf 序列化得到的字节流中包含消息的长度和(或)类型?我能想到的答案有:

如果把消息写入文件,一个文件存一个消息,那么序列化结果中不需要包含长度和类型,因为从文件名和文件长度中可以得知消息的类型与长度。

如果把消息写入文件,一个文件存多个消息,那么序列化结果中不需要包含类型,因为文件名就代表了消息的类型。

如果把消息存入数据库(或者 NoSQL),以 VARBINARY 字段保存,那么序列化结果中不需要包含长度和类型,因为从字段名和字段长度中可以得知消息的类型与长度。

如果把消息以 UDP 方式发生给对方,而且对方一个 UDP port 只接收一种消息类型,那么序列化结果中不需要包含长度和类型,因为从 port 和 UDP packet 长度中可以得知消息的类型与长度。

如果把消息以 TCP 短连接方式发给对方,而且对方一个 TCP port 只接收一种消息类型,那么序列化结果中不需要包含长度和类型,因为从 port 和 TCP 字节流长度中可以得知消息的类型与长度。

如果把消息以 TCP 长连接方式发给对方,但是对方一个 TCP port 只接收一种消息类型,那么序列化结果中不需要包含类型,因为 port 代表了消息的类型。

如果采用 RPC 方式通信,那么只需要告诉对方 method name,对方自然能推断出 Request 和 Response 的消息类型,这些可以由 protoc 生成的 RPC stubs 自动搞定。

对于最后一点,比方说 sudoku.proto 定义为:

service SudokuService {

rpc Solve (SudokuRequest) returns (SudokuResponse)

}

那么 RPC method Sudoku.Solve 对应的请求和响应分别是 SudokuRequest 和 SudokuResponse。在发送 RPC 请求的时候,不需要包含 SudokuRequest 的类型,只需要发送 method name Sudoku.Solve,对方自知道应该按照 SudokuRequest 来解析(parse)请求。这个例子来自我的半成品项目 evproto。

对于上述这些情况,如果 protobuf 无条件地把长度和类型放到序列化的字节串中,只会浪费网络带宽和存储。可见 protobuf 默认不发送长度和类型是正确的决定。Protobuf 为消息格式的设计树立了典范,哪些该自己搞定,哪些留给外部系统去解决,这些都考虑得很清楚。

只有在使用 TCP 长连接,且在一个连接上传递不止一种消息的情况下(比方同时发 Heartbeat 和 Request/Response),才需要我前文提到的那种打包方案。(为什么要在一个连接上同时发 Heartbeat 和业务消息?请见陈硕《分布式系统的工程化开发方法》 p.51 心跳协议的设计。)这时候我们需要一个分发器 dispatcher,把不同类型的消息分给各个消息处理函数,这正是本文的主题之一。


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/sjk/9893394.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-03
下一篇2023-05-03

发表评论

登录后才能评论

评论列表(0条)

    保存