Avro的模式主要由JSON对象来表示,Avro支持8种基本类型(Primitive Type)和6种复杂类型(Complex Type:records、enums、arrays、maps、unions 和fixed),基本类型可以由JSON字符串来表示。
Avro支持两种序列化编码方式:二进制编码和JSON编码,使用二进制编码会高效序列化,并且序列化后得到的结果会比较小。
基本类型:
null: no value
boolean: a binary value
int: 32-bit signed integer
long: 64-bit signed integer
float: single precision (32-bit) IEEE 754 floating-point number
double: double precision (64-bit) IEEE 754 floating-point number
bytes: sequence of 8-bit unsigned bytes
string: unicode character sequence
参考:http://blog.youkuaiyun.com/zhu_tianwei/article/details/44042955,感谢分享
一、Http方式
{
"namespace": "com.learn.PpcHttp",
"protocol": "messageProtocol",
"doc": "This is a message.",
"name": "Message",
"types": [
{"name":"message", "type":"record",
"fields":[
{"name":"name", "type":"string"},
{"name":"type", "type":"int"},
{"name":"price", "type":"double"},
{"name":"valid", "type":"boolean"},
{"name":"content", "type":"string"}
]
}
],
"messages": {
"sendMessage":{
"doc" : "message test",
"request" :[{"name":"message","type":"message" }],
"response" :"message"
}
}
}
2.定义协议解析工具
/协议解析工具类
//message.avpr
//其中定义了1种类型叫做message,
// 有5个成员name、type、price、valid、content。
// 还定义了1个消息服务叫做sendMessage,输入有一个参数,类型是message,返回message。
public class Utils {
public static Protocol getProtocol() {
Protocol protocol = null;
try {
URL url = Utils.class.getClassLoader().getResource("./RpcHttpRes/message.avpr");
protocol = Protocol.parse(new File(url.getPath()));
} catch (IOException e) {
e.printStackTrace();
}
return protocol;
}
public static void main(String[] args) {
Protocol protocol = getProtocol();
System.out.println(protocol);
//{"protocol":"messageProtocol","namespace":"com.learn.PpcHttp",
// "doc":"This is a message.","name":"Message",
// "types":[{"type":"record","name":"message",
// "fields":[{"name":"name","type":"string"},{"name":"type","type":"int"},
// {"name":"price","type":"double"},{"name":"valid","type":"boolean"},
// {"name":"content","type":"string"}]}],
// "messages":{"sendMessage":{"doc":"message test",
// "request":[{"name":"message","type":"message"}],"response":"message"}}}
}
}
3.定义Client
public class Client {
private Protocol protocol = null;
private String host = null;
private int port = 0;
private int count = 0;
public Client(Protocol protocol, String host, int port, int count) {
this.protocol = protocol;
this.host = host;
this.port = port;
this.count = count;
}
public long sendMessage() throws Exception {
GenericRecord requestData = new GenericData.Record(protocol.getType("message"));
requestData.put("name", "香梨");
requestData.put("type", 36);
requestData.put("price", 5.6);
requestData.put("valid", true);
requestData.put("content", "价钱便宜");
// 初始化请求数据
GenericRecord request = new GenericData.Record(protocol.getMessages().get("sendMessage").getRequest());
request.put("message", requestData);
Transceiver t = new HttpTransceiver(new URL("http://" + host + ":" + port));
GenericRequestor requestor = new GenericRequestor(protocol, t);
long start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
Object result = requestor.request("sendMessage", request);
if (result instanceof GenericData.Record) {
GenericData.Record record = (GenericData.Record) result;
System.out.println(record);
}
}
long end = System.currentTimeMillis();
System.out.println((end - start)+"ms");
return end - start;
}
public long run() {
long res = 0;
try {
res = sendMessage();
} catch (Exception e) {
e.printStackTrace();
}
return res;
}
public static void main(String[] args) throws Exception {
new Client(Utils.getProtocol(), "127.0.0.1", 9090, 5).run();
}
}
//{"name": "苹果", "type": 100, "price": 4.6, "valid": true, "content": "最新上架货物"}
//{"name": "苹果", "type": 100, "price": 4.6, "valid": true, "content": "最新上架货物"}
//{"name": "苹果", "type": 100, "price": 4.6, "valid": true, "content": "最新上架货物"}
//{"name": "苹果", "type": 100, "price": 4.6, "valid": true, "content": "最新上架货物"}
//{"name": "苹果", "type": 100, "price": 4.6, "valid": true, "content": "最新上架货物"}
//377ms
4.定义Server
public class Server extends GenericResponder {
private Protocol protocol = null;
private int port;
public Server(Protocol protocol, int port) {
super(protocol);
this.protocol = protocol;
this.port = port;
}
@Override
public Object respond(Protocol.Message message, Object request) throws Exception {
GenericRecord req = (GenericRecord) request;
GenericRecord reMessage = null;
if (message.getName().equals("sendMessage")) {
GenericRecord msg = (GenericRecord)req.get("message");
System.out.print("接收到数据:");
System.out.println(msg);
//取得返回值的类型
reMessage = new GenericData.Record(protocol.getType("message"));
//直接构造回复
reMessage.put("name", "苹果");
reMessage.put("type", 100);
reMessage.put("price", 4.6);
reMessage.put("valid", true);
reMessage.put("content", "最新上架货物");
}
return reMessage;
}
public void run() {
try {
HttpServer server = new HttpServer(this, port);
server.start();
server.join();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Server(Utils.getProtocol(), 9090).run();
}
}
// 接收到数据:{"name": "香梨", "type": 36, "price": 5.6, "valid": true, "content": "价钱便宜"}
// 接收到数据:{"name": "香梨", "type": 36, "price": 5.6, "valid": true, "content": "价钱便宜"}
// 接收到数据:{"name": "香梨", "type": 36, "price": 5.6, "valid": true, "content": "价钱便宜"}
// 接收到数据:{"name": "香梨", "type": 36, "price": 5.6, "valid": true, "content": "价钱便宜"}
// 接收到数据:{"name": "香梨", "type": 36, "price": 5.6, "valid": true, "content": "价钱便宜"}
二、Netty方式+如何应用接口实现协议
参考:https://github.com/pzx888/avro-rpc-demo
Message.avsc,参考:http://blog.youkuaiyun.com/hjw199089/article/details/78801890,生成Message类
{
"name ": "Message ",
"namespace ": "com.learn.proto ",
"type ": "record "
"fields ": [
{
"name ": "to ",
"type ": "string "
},
{
"name ": "from ",
"type ": "string "
},
{
"name ": "body ",
"type ": "string "
}
],
}
定义Mail接口协议
@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\":\"com.learn.proto\",\"types\":[{\"type\":\"record\",\"name\":\"Message\",\"fields\":[{\"name\":\"to\",\"type\":\"string\"},{\"name\":\"from\",\"type\":\"string\"},{\"name\":\"body\",\"type\":\"string\"}]}],\"messages\":{\"send\":{\"request\":[{\"name\":\"message\",\"type\":\"Message\"}],\"response\":\"string\"}}}");
CharSequence send(Message message) throws org.apache.avro.AvroRemoteException;
@SuppressWarnings("all")
public interface Callback extends Mail {
public static final org.apache.avro.Protocol PROTOCOL = Mail.PROTOCOL;
void send(Message message, org.apache.avro.ipc.Callback<CharSequence> callback) throws java.io.IOException;
}
}
定义测试App,启动Server,启动Client
public class MailMain {
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: <to> <from> <body>");
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();
}
}
//设置运行参数 hjw_1 hjw_2 "this is message"
//Server started
//Client built, got proxy
//Calling proxy.send with message: {"to": "hjw_1", "from": "hjw_2", "body": "this is message"}
//Sending message
//Result: Sending message to hjw_1 from hjw_2 with body this is message