本系列之1: 简介
本系列之2: API服务开发
本系列之3: RSON序列化格式
本系列之4: RPC调度原理
本系列之5: NIO实现原理
本系列之6: 客户端动态代理原理
本系列之7: 注解处理器(APT)原理👈
本文介绍Rayson框架使用APT(Annotation-Processing-Tool )来抽取API元数据的原理.
概述
前文曾经讲过,Rayson框架使用Java接口定义API协议,如下面例子定义了一个API协议:
@Service
public interface SimpleProtocol extends Protocol {
/**
* Echo received message.
*
* @param msg The message to be echo.
* @return Return the given message.
*/
@TestAnnotation("test annotaiton")
public String echo(String msg) throws IOException, RpcException;
/**
* Echo received message.
*
* @param msg The message to be echo.
* @return Return the given message.
*/
public byte[] echo2(byte[] msg) throws IOException, RpcException;
}
我们知道,Java的接口被编译成class文件时候,方法(Method)参数的名字默认是丢失掉的。如上面的方法#echo(String msg)
,在编程成class的时候,唯一参数的名字msg
就被擦除了。这样就导致Rayson框架无法识别协议所定义的API的参数名。
为了弥补这个问题,Rayson框架使用了Java的APT(Annotation Processing Tool)来在编译时对API协议进行预处理。
因为APT只能处理添加特定注解的Java类,因此接口SimpleProtocol
添加了注解@org.rayson.api.annotation.Service
,来告知APT需要处理这个接口。
Rayson APT 放在rayson.api
库中,开发者只需要在API开发项目中引入了该库,就能在使用javac
编译项目的时候对定义API协议的Java接口执行Rayson APT的预处理。
最后,Rayson APT对于Rayson框架来说是可选的,也就是说开发者定义的API协议,即使没有经过Rayson APT的处理仍然是可以工作的。不过这种情况下就会缺少API协议的元数据,使得开发出来的API有一定的使用限制,例如只能使用动态参数名来调用API。
预处理过程
下面我们以上文的示例协议为例,说明Rayson APT所做的预处理。
- 为方法参数添加注解来为参数添加运行时的名称。
上文的接口经过这一步骤的处理,其源代码相当于下面代码所示:
@Service
public interface SimpleProtocol extends Protocol {
@TestAnnotation("test annotaiton")
public String echo(@SerializedName("msg") String msg) throws IOException, RpcException;
public byte[] echo2(@SerializedName("msg") byte[] msg) throws IOException, RpcException;
}
其中,注解@org.rayson.api.annotation.SerializedName
被自动添加于每个方法参数,用来为参数指定运行时名称。
- 生成JSON格式的描述文件,用于存储协议的元数据。Rayson框架会在启动服务时候加载这些元数据。
上文的接口,经过这一步骤的处理,会在跟编译后Java类所在的同一目录下,生成一个文件SimpleProtocol$rayson$proto.json
,其内容如下所示:
{
"version": "1.0",
"name": "org.rayson.demo.simple.api.SimpleProtocol",
"comment": "",
"methods": [
{
"name": "echo2",
"comment": " @return Return the given message.\r\n",
"returnType": "byte[]",
"returnComment": null,
"annotations": [
],
"parameters": [
{
"name": "msg",
"index": 0,
"comment": null
}
]
},
{
"name": "echo",
"comment": " @return Return the given message.\r\n",
"returnType": "java.lang.String",
"returnComment": null,
"annotations": [
"@org.rayson.demo.simple.api.TestAnnotation(\"test annotaiton\")"
],
"parameters": [
{
"name": "msg",
"index": 0,
"comment": null
}
]
}
]
}
- 拷贝协议接口的Java源代码文件,跟编译后的Java类放在同一目录下。这些源代码会被Rayson作为API服务的定义文件使用。
代码原理
Rayson APT主要使用了JAVA的APT来实现,其源代码放在Rayson的子项目rayson.api
中的org.rayson.apt
包下,其代码原理在此不再赘述,请参考Rayson APT源代码。