性能-来自谷歌
FlatBuffers (binary) | Protocol Buffers LITE | Rapid JSON | FlatBuffers (JSON) | pugixml | Raw structs | |
---|---|---|---|---|---|---|
Decode + Traverse + Dealloc (1 million times, seconds) | 0.08 | 302 | 583 | 105 | 196 | 0.02 |
Decode / Traverse / Dealloc (breakdown) | 0 / 0.08 / 0 | 220 / 0.15 / 81 | 294 / 0.9 / 287 | 70 / 0.08 / 35 | 41 / 3.9 / 150 | 0 / 0.02 / 0 |
Encode (1 million times, seconds) | 3.2 | 185 | 650 | 169 | 273 | 0.15 |
Wire format size (normal / zlib, bytes) | 344 / 220 | 228 / 174 | 1475 / 322 | 1029 / 298 | 1137 / 341 | 312 / 187 |
Memory needed to store decoded wire (bytes / blocks) | 0 / 0 | 760 / 20 | 65689 / 4 | 328 / 1 | 34194 / 3 | 0 / 0 |
Transient memory allocated during decode (KB) | 0 | 1 | 131 | 4 | 34 | 0 |
Generated source code size (KB) | 4 | 61 | 0 | 4 | 0 | 0 |
Field access in handwritten traversal code | typed accessors | typed accessors | manual error checking | typed accessors | manual error checking | typed but no safety |
Library source code (KB) | 15 | some subset of 3800 | 87 | 43 | 327 | 0 |
定义一个结构schema
namespace io.flatbutterx.sample;
table ReposList {
repos : [Repo];
}
table Repo {
id : long;
name : string;
full_name : string;
owner : User;
html_url : string;
description : string;
}
table User {
login : string;
id : long;
}
root_type ReposList;
flatc -b -j schema.fbs进行编译。产生的文件如下
public final class User extends Table {
public static User getRootAsUser(ByteBuffer _bb) { return getRootAsUser(_bb, new User()); }
public static User getRootAsUser(ByteBuffer _bb, User obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; }
public User __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
public String login() { int o = __offset(4); return o != 0 ? __string(o + bb_pos) : null; }
public ByteBuffer loginAsByteBuffer() { return __vector_as_bytebuffer(4, 1); }
public ByteBuffer loginInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 4, 1); }
public long id() { int o = __offset(6); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
public static int createUser(FlatBufferBuilder builder,
int loginOffset,
long id) {
builder.startObject(2);
User.addId(builder, id);
User.addLogin(builder, loginOffset);
return User.endUser(builder);
}
public static void startUser(FlatBufferBuilder builder) { builder.startObject(2); }
public static void addLogin(FlatBufferBuilder builder, int loginOffset) { builder.addOffset(0, loginOffset, 0); }
public static void addId(FlatBufferBuilder builder, long id) { builder.addLong(1, id, 0L); }
public static int endUser(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
}
}
里面一堆方法
- getRootAsUser(ByteBuffer _bb), 这个作用是将byte数组产生User对象。
- createUser这个作用是是使用参数创建一个User对象。参数的第一个是builder,后面的是参数,要注意的是loginOffset需要builder createString之后在获取到offset在使用,比较麻烦,如果是数组的话,更麻烦
举个例子Weapon有个数组为weapons,通过下面的代码我们看下怎样进行赋值
int[] weaps = new int[2];
weaps[0] = Weapon.createWeapon(builder, weaponOneName, weaponOneDamage);
weaps[1] = Weapon.createWeapon(builder, weaponTwoName, weaponTwoDamage);
int weapons = Monster.createWeaponsVector(builder, weaps);
int orc = Monster.createMonster(builder, name, weapons);
builder.finish(orc);
首先需要创建一个数组,通过createWeapon创建单个元素的偏移,然后将偏移放入数组。 然后将数组作为输入createWeaponsVector获取数组的偏移,然后才能使用,比较麻烦? 想查看对象内容怎么办?都在数组里面,手写toString? #No
自动生成?
- 生成一个Java Bean对象
- Java Bean与FlatBuffer的相互转换,比如ORM之类的可以使用。
- Java Bean 与JSON的相互转换
public final class UserFB extends FlatBufferMapper<UserFB> {
public Long id;
public String login;
@Override
public UserFB parse(JsonParser jsonParser) throws IOException {
UserFB instance = new UserFB();
if (jsonParser.getCurrentToken() == null) {
jsonParser.nextToken();
}
if (jsonParser.getCurrentToken() != JsonToken.START_OBJECT) {
jsonParser.skipChildren();
return null;
}
while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
String fieldName = jsonParser.getCurrentName();
jsonParser.nextToken();
parseField(instance, fieldName, jsonParser);
jsonParser.skipChildren();
}
return instance;
}
@Override
public void parseField(UserFB instance, String fieldName, JsonParser jsonParser) throws
IOException {
if ("id".equals(fieldName)) {
instance.id = jsonParser.getCurrentToken() == JsonToken.VALUE_NULL ? null : Long.valueOf(jsonParser.getValueAsLong());
} else if ("login".equals(fieldName)) {
instance.login = jsonParser.getValueAsString(null);
}
}
@Override
public void serialize(UserFB object, JsonGenerator jsonGenerator, boolean writeStartAndEnd) throws
IOException {
if (writeStartAndEnd) {
jsonGenerator.writeStartObject();
}
if (object.id != null) {
jsonGenerator.writeNumberField("id", object.id);
}
if (object.login != null) {
jsonGenerator.writeStringField("login", object.login);
}
if (writeStartAndEnd) {
jsonGenerator.writeEndObject();
}
}
@Override
public ByteBuffer toFlatBuffer(UserFB object) throws IOException {
FlatBufferBuilder bufferBuilder = new FlatBufferBuilder();
int offset = toFlatBufferOffset(bufferBuilder);
bufferBuilder.finish(offset);
return bufferBuilder.dataBuffer();
}
@Override
public int toFlatBufferOffset(FlatBufferBuilder bufferBuilder) throws IOException {
return User.createUser(bufferBuilder,bufferBuilder.createString(this.login),this.id);
}
@Override
public UserFB flatBufferToBean(Object object) throws IOException {
User flatObj = (User) object;
this.id = flatObj.id();
this.login = flatObj.login();
return this;
}
}
- ByteBuffer toFlatBuffer(UserFB object) Java对象转换成FlatBuffer的字节流
- flatBufferToBean(Object object) 将FlatBuffer对象转换成JavaBean。
愉快的写代码吧,只要toFlatBuffer和flatBufferToBean就可以了。
神奇
只需要给生成的FlatBuffer添加一个注解就行了 @FlatBufferSrc
然后注解处理器会处理FlatBuffer,解析里面的字段,然后最终组合出来Java Bean对象,就跟上面你看到的那样
引入
注解处理器
annotationProcessor "o.flatbufferx:flatbufferx-compiler:last-version"
compile "io.flatbufferx:core:last-version"
last-version=1.0.0