Apache Avro-[2]-Rpc-Http和Netty两种方式

本文介绍 Avro 的基本类型与复杂类型,并通过 Http 和 Netty 方式演示 Avro RPC 的实现过程,包括定义消息结构、创建客户端和服务端等步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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方式

1.定义一个消息结构
message.avpr
定义了1种类型叫做message,有5个成员name、type、price、valid、content。还定义了1个消息服务叫做sendMessage,输入有一个参数,类型是message,返回message
{
    "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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值