Apache Avro 是一个序列化系统,提供如下功能:
1.丰富的数据结构
2.压缩的、快速的、二进制数据格式
3.存储持久化数据的容器文件
4.RPC功能
5.可以简单实现与动态语言的集成
特点:
Avro在数据读写过程中都利用基于JSON格式的Schemas,因而不用在序列化时对每个数据都要加一个类型等头部信息,从而使序列化保持快而小。并且因为数据加上对应的schema是自描述的,这样也可以促进在动态、脚本语言中的使用。
二、示例
示例参考【 https://github.com/phunt/avro-rpc-quickstart】
本示例利用Mail协议简单模拟一个远程服务,Avro将利用这个服务来发送消息
1.编辑avpr协议文件
{"namespace": "example.proto", (1) "protocol": "Mail", (2) "types": [ (3) {"name": "Message", "type": "record", "fields": [ {"name": "to", "type": "string"}, {"name": "from", "type": "string"}, {"name": "body", "type": "string"} ] } ], "messages": { (4) "send": { "request": [{"name": "message", "type": "Message"}], "response": "string" } } }
(1)定义命名空间
(2)定义协议名称
(3)定义类型信息
(4)定义rpc Messages
2.编写pom文件
4.0.0 example.qs avro-rpc-quickstart jar 1.8.1-SNAPSHOT avro-rpc-quickstart http://maven.apache.org UTF-8 3.5 1.8.1 junit junit 4.10 test org.slf4j slf4j-simple 1.6.4 compile org.apache.avro avro ${avro.version} org.apache.avro avro-ipc ${avro.version} org.apache.maven.plugins maven-compiler-plugin ${compiler-plugin.version} org.apache.avro avro-maven-plugin ${avro.version} schemas generate-sources schema protocol idl-protocol ${project.basedir}/src/main/avro/ ${project.basedir}/src/main/java/
3.在项目目录下执行 mvn compile ,执行结束后生成 Mail.java 和Message.java文件
4.编写测试程序
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package example; import java.io.IOException; import java.net.InetSocketAddress; import org.apache.avro.ipc.NettyServer; import org.apache.avro.ipc.NettyTransceiver; import org.apache.avro.ipc.Server; import org.apache.avro.ipc.specific.SpecificRequestor; import org.apache.avro.ipc.specific.SpecificResponder; import org.apache.avro.util.Utf8; import example.proto.Mail; import example.proto.Message; /** * Start a server, attach a client, and send a message. */ public class Main { public static class MailImpl implements Mail { // in this simple example just return details of the message public Utf8 send(Message message) { System.out.println("Sending message"); return new Utf8("Sending message to " + message.getTo().toString() + " from " + message.getFrom().toString() + " with body " + message.getBody().toString()); } } private static Server server; private static void startServer() throws IOException { server = new NettyServer(new SpecificResponder(Mail.class, new MailImpl()), new InetSocketAddress(65111)); // the server implements the Mail protocol (MailImpl) } public static void main(String[] args) throws IOException { if (args.length != 3) { System.out.println("Usage:"); System.exit(1); } System.out.println("Starting server"); // usually this would be another app, but for simplicity startServer(); System.out.println("Server started"); NettyTransceiver client = new NettyTransceiver(new InetSocketAddress(65111)); // client code - attach to the server and send a message Mail proxy = (Mail) SpecificRequestor.getClient(Mail.class, client); System.out.println("Client built, got proxy"); // fill in the Message record and send it Message message = new Message(); message.setTo(new Utf8(args[0])); message.setFrom(new Utf8(args[1])); message.setBody(new Utf8(args[2])); System.out.println("Calling proxy.send with message: " + message.toString()); System.out.println("Result: " + proxy.send(message)); // cleanup client.close(); server.close(); } }
5.执行测试,出入参数 tianjin beijing hello
执行结果
Client built, got proxy Calling proxy.send with message: {"to": "tianjin", "from": "beijing", "body": "hello"} Sending message Result: Sending message to tianjin from beijing with body hello
6.工程代码参考附件
* 当数据类型是 Map
默认情况下,avpr文件中数据类型是string时,利用avro-maven-plugin生成的数据类型是CharSequence,比如:
{"namespace": "example.proto", "protocol": "Mail", "messages": { "send": { "request": [{"name": "jobId", "type": "string"},{"name": "message", "type": {"type":"map","values":"string"}}], "response": "string" } } }
默认生成的类文件:
/** * Autogenerated by Avro * * DO NOT EDIT DIRECTLY */ package example.proto; @SuppressWarnings("all") @org.apache.avro.specific.AvroGenerated public interface Mail { public static final org.apache.avro.Protocol PROTOCOL = org.apache.avro.Protocol.parse("{\"protocol\":\"Mail\",\"namespace\":\"example.proto\",\"types\":[],\"messages\":{\"send\":{\"request\":[{\"name\":\"jobId\",\"type\":\"string\"},{\"name\":\"message\",\"type\":{\"type\":\"map\",\"values\":\"string\"}}],\"response\":\"string\"}}}"); /** */ java.lang.CharSequence send(java.lang.CharSequence jobId, java.util.Mapmessage) throws org.apache.avro.AvroRemoteException; @SuppressWarnings("all") public interface Callback extends Mail { public static final org.apache.avro.Protocol PROTOCOL = example.proto.Mail.PROTOCOL; /** * @throws java.io.IOException The async call could not be completed. */ void send(java.lang.CharSequence jobId, java.util.Map message, org.apache.avro.ipc.Callback callback) throws java.io.IOException; } }
如果我们想在程序中使用String类型时,需要在avro-maven-plugin 中加入
org.apache.avro avro-maven-plugin ${avro.version} String
此时生成的Java文件
/** * Autogenerated by Avro * * DO NOT EDIT DIRECTLY */ package example.proto; @SuppressWarnings("all") @org.apache.avro.specific.AvroGenerated public interface Mail { public static final org.apache.avro.Protocol PROTOCOL = org.apache.avro.Protocol.parse("{\"protocol\":\"Mail\",\"namespace\":\"example.proto\",\"types\":[],\"messages\":{\"send\":{\"request\":[{\"name\":\"jobId\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}},{\"name\":\"message\",\"type\":{\"type\":\"map\",\"values\":{\"type\":\"string\",\"avro.java.string\":\"String\"},\"avro.java.string\":\"String\"}}],\"response\":{\"type\":\"string\",\"avro.java.string\":\"String\"}}}}"); /** */ java.lang.String send(java.lang.String jobId, java.util.Mapmessage) throws org.apache.avro.AvroRemoteException; @SuppressWarnings("all") public interface Callback extends Mail { public static final org.apache.avro.Protocol PROTOCOL = example.proto.Mail.PROTOCOL; /** * @throws java.io.IOException The async call could not be completed. */ void send(java.lang.String jobId, java.util.Map message, org.apache.avro.ipc.Callback callback) throws java.io.IOException; } }