Avro RPC 之 Protocol 定義和程式碼生成

devos發表於2014-03-17

摘自http://avro.apache.org/docs/current/spec.html#Protocol+Declaration,1.7.6版

Protocol Declaration

Avro protocols describe RPC interfaces. Like schemas, they are defined with JSON text.

A protocol is a JSON object with the following attributes:

  • protocol, a string, the name of the protocol (required);
  • namespace, an optional string that qualifies the name;
  • doc, an optional string describing this protocol;
  • types, an optional list of definitions of named types (records, enums, fixed and errors). An error definition is just like a record definition except it uses "error" instead of "record". Note that forward references to named types are not permitted.
  • messages, an optional JSON object whose keys are message names and whose values are objects whose attributes are described below. No two messages may have the same name.

The name and namespace qualification rules defined for schema objects apply to protocols as well.

Avro protocol 描述了RPC介面,和schema一樣,用JSON定義。

一個protocol是一個JSON物件,有以下的屬性:

  • protocol,必需,這個protocol的名字
  • namespace, 可選,用來qualify protocol的名字
  • doc, 可選,描述這個protocol
  • types, 可選,定義named types的列表(records, enums, fixed, errors)。error的定義和record一樣,除了它使用error,而不是record. 注意named type不能進行forward reference. (注:就是定義了一些型別,然後給每個型別起個名字)
  • messages, 可選,是一個JSON物件。它的key是message name, values是JSON 物件, 下邊會講這個JSON物件的屬性。message不能有相同的名字。

用於schema object的命名規則和namespace qualification規則同樣適用於protocol

Messages

A message has attributes:

  • doc, an optional description of the message,
  • request, a list of named, typed parameter schemas (this has the same form as the fields of a record declaration);
  • response schema;
  • an optional union of declared error schemas. The effective union has "string" prepended to the declared union, to permit transmission of undeclared "system" errors. For example, if the declared error union is ["AccessError"], then the effective union is ["string", "AccessError"]. When no errors are declared, the effective error union is ["string"]. Errors are serialized using the effective union; however, a protocol's JSON declaration contains only the declared union.
  • an optional one-way boolean parameter.

A request parameter list is processed equivalently to an anonymous record. Since record field lists may vary between reader and writer, request parameters may also differ between the caller and responder, and such differences are resolved in the same manner as record field differences.

The one-way parameter may only be true when the response type is "null" and no errors are listed.

 message有以下屬性:

  • doc, 可選,對訊息的說明
  • request,  一個引數列表,其中的引數擁有名字和型別(和record中的field的定義格式一樣)  。(注:即需要說明引數的名字和型別)
     "request": [{"name": "greeting", "type": "Greeting" }]
  • response的schema 
    "response": "Greeting",
  • error, 用一個declared union來描述,可選。之所以叫"delcared" union,是因為實際上隱式地附加了一個String到這個union中,這樣沒有宣告的"system error" 也可以傳輸了。例如,declared error union是["AccessError"],effective union就是["String", "AccessError"]。如果沒有宣告error, effective error union就是["string"]。錯誤 被用effective union序列化。但是這個protocol的JSON形式的定義裡就只用寫declared union了。
  • one-way 布林型別引數,可選

請求的引數列表就和匿名record一樣處理。因為record field列表在reader和writer間可以不同,request 引數在caller和responder之間也可以不同,這樣的不同和record field不同採用同樣的方式處理。

當response 型別是null,並且沒有列出error時,one-way parameter只能是true.

 

 

Sample Protocol

For example, one may define a simple HelloWorld protocol with:

{
  "namespace": "com.acme",
  "protocol": "HelloWorld",
  "doc": "Protocol Greetings",

  "types": [
    {"name": "Greeting", "type": "record", "fields": [
      {"name": "message", "type": "string"}]},
    {"name": "Curse", "type": "error", "fields": [
      {"name": "message", "type": "string"}]}
  ],

  "messages": {
    "hello": {
      "doc": "Say hello.",
      "request": [{"name": "greeting", "type": "Greeting" }],
      "response": "Greeting",
      "errors": ["Curse"]
    }
  }
}
        

 

 總結:搞了這麼多,這個protocol的定義實際上就是定義了一些用於RPC的方法,不過在定義方法時要宣告方法的引數名、引數型別、返回型別、異常啥的。這些方法要定義於一個介面,所以還要說明這個介面的名字(在上邊的例子中是HelloWorld).

生成對應的java程式碼

把上邊的protocol寫上一個HelloWorld.avpr中,然後執行java -jar avro-tools- 1.7.6.jar compile protocol HelloWorld.avpr /target/java 就會得到三個檔案

  • Curse.java. public class Curse extends org.apache.avro.specific.SpecificExceptionBase implements org.apache.avro.specific.SpecificRecord 這個就是上邊定義的error,這個類是一個異常。
  • Greeting.java.public class Greeting extends org.apache.avro.specific.SpecificRecordBase implements org.apache.avro.specific.SpecificRecord 這個就是引數型別,被生成為一個類,它是一個record型別。
  • HelloWorld.java 
/**
 * Autogenerated by Avro
 * 
 * DO NOT EDIT DIRECTLY
 */
package com.acme;

@SuppressWarnings("all")
/** Protocol Greetings */
@org.apache.avro.specific.AvroGenerated
public interface HelloWorld {
  public static final org.apache.avro.Protocol PROTOCOL = org.apache.avro.Protocol.parse("{\"protocol\":\"HelloWorld\",\"namespace\":\"com.acme\",\"doc\":\"Protocol Greetings\",\"types\":[{\"type\":\"record\",\"name\":\"Greeting\",\"fields\":[{\"name\":\"message\",\"type\":\"string\"}]},{\"type\":\"error\",\"name\":\"Curse\",\"fields\":[{\"name\":\"message\",\"type\":\"string\"}]}],\"messages\":{\"hello\":{\"doc\":\"Say hello.\",\"request\":[{\"name\":\"greeting\",\"type\":\"Greeting\"}],\"response\":\"Greeting\",\"errors\":[\"Curse\"]}}}");
  /** Say hello. */
  com.acme.Greeting hello(com.acme.Greeting greeting) throws org.apache.avro.AvroRemoteException, com.acme.Curse;

  @SuppressWarnings("all")
  /** Protocol Greetings */
  public interface Callback extends HelloWorld {
    public static final org.apache.avro.Protocol PROTOCOL = com.acme.HelloWorld.PROTOCOL;
    /** Say hello. */
    void hello(com.acme.Greeting greeting, org.apache.avro.ipc.Callback<com.acme.Greeting> callback) throws java.io.IOException;
  }
}

  它是一個介面,定義了一個叫hello的方法,就是前邊給message起的名字。它的引數和返回型別、丟擲的異常都符合對應procotol的宣告。doc被轉換為了對應於方法和類的註釋。

 

相關文章