这种跨语言的数据序列化框架有很多,AVRO并不是最知名,最好用的,为什么会选择他呢?因为他是Hadoop的一个子项目,就犹如Spring mvc和Spring一样。
特点:
1.数据结构丰富。
2.快速可压缩的二进制形式。 常见的压缩算法:HUFFMAN编码(哈夫曼编码)。
3.可以实现RPC
4.依赖于模式(schema),是用json格式来表示的。如果是想利用avro实现序列化或rpc通 信,需要遵守schema的格式要求
1.数据结构
具有丰富的数据结构类型。8种基本数据类型以及6种复杂类型
基本数据类型
1. null ->表示没有值
2. boolean ->表示一个二级制布尔值
3. int ->表示32位有符号整数
4. long ->64位有符号整数
5. float ->32位单精度浮点数
6. double ->64位双精度浮点数
7. bytes ->8位无符号字节
8. string ->注意是小写 表示字符序列
复杂数据
目前只记住一个常用的就可以了
record:
{“namespace”:”avro.domain”,
“type”:”record”,
“name”:”Student”,
“fields”:[
{“name”:”username”,”type”:”string”}, {“name”:”age”,”type”:[“int”,”null”]}
]
}
namespace:指定包名
type:record 序列化类型
name:指定类名
fields:指定类的字段名
下面实现一下序列化:
maven 坐标如下:
这里还有一个插件,要右键pom.xml-run as->Maven generate-sources
会将写的模板文件生成对应的类。
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<compiler-plugin.version>2.3.2</compiler-plugin.version>
<avro.version>1.7.5</avro.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.6.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.avro</groupId>
<artifactId>avro</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.apache.avro</groupId>
<artifactId>avro-ipc</artifactId>
<version>1.7.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.avro</groupId>
<artifactId>avro-maven-plugin</artifactId>
<version>1.7.5</version>
<executions>
<execution>
<id>schemas</id>
<phase>generate-sources</phase>
<goals>
<goal>schema</goal>
<goal>protocol</goal>
<goal>idl-protocol</goal>
</goals>
<configuration>
<sourceDirectory>${project.basedir}/src/main/avro/</sourceDirectory>
<outputDirectory>${project.basedir}/src/main/java/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
pom文件会报错,不用管,将错误提醒关掉即可。
实例如下:
1.根据avro的插件要求,更改maven工程结构,需要创建一个source源目录src\main\avro
2.根据avro的模式要求,创建模式文件(放在src\main\avro下)
1.在src\main\avro下创建模式文件student.avsc(该文件格式就是avro的存放数据的格式文件)
模式文件如下:
{"namespace":"avro.pojo",
"type":"record",
"name":"Student",
"fields":[
{"name":"username","type":"string"},
{"name":"age","type":["int","null"]}
]
}
序列化
public void testWrite() throws Exception{
//创建序列化类
DatumWriter<Student> dw = new SpecificDatumWriter<Student>();
DataFileWriter<Student> dfw = new DataFileWriter<Student>(dw);
//创建2个需要序列化的对象
Student stu1 = new Student("帅比", 25);
Student stu2 = new Student("美女", 18);
//创建序列化目标文件1.txt
dfw.create(stu1.getSchema(), new File ("1.txt"));
//写入stu1
dfw.append(stu1);
//写入stu2
dfw.append(stu2);
//写入完毕
dfw.close();
}
反序列化
public void testRead() throws Exception{
//创建反序列化类
DatumReader<Student> dr = new SpecificDatumReader<Student>();
DataFileReader<Student> dfr = new DataFileReader<Student>(new File ("1.txt"), dr);
//反序列化并输出
while(dfr.hasNext()){
Student stu = dfr.next();
System.out.println(stu);
}
}
这里输出的是json格式:
{“username”: “帅比”, “age”: 25}
{“username”: “美女”, “age”: 18}
Avro实现RPC(Remote Procedure Call)
场景:一个客户端,一个服务端(创建两个avro工程)。客户端向服务端发送数据,服务端根 据算法算出结果,返回给客户端。
假定客户端传值后,服务器做加法后传回。
实现步骤
1.创建两个maven工程
2.引入pom文件
3.更改maven工程结构(src/main/avro)
4.创建模式文件(协议文件) src/main/avro/AddService.avdl(注意这里的格式是协议文件的格式后缀,上面的是模式文件)
@namespace("avro.service")
protocol AddService{
int add(int x,int y);
}
右键pom.xml-run as->Maven generate-sources,生成接口类。
两个项目都要有
客户端:
首先创建实现类:
addserverImpl
public class AddServerImpl implements AddService{
@Override
public int add(int x, int y) throws AvroRemoteException {
return x+y;
}
}
主类:
public class server {
public static void main(String[] args) {
/*指定监听端口号,和处理的实现类对象
* 第一个参数 SpecificResponder 中第一个参数是接口类,第二个是实现对象
*/
NettyServer server = new NettyServer(
new SpecificResponder(AddService.class,
new AddServerImpl()),
new InetSocketAddress(6666));
}
}
客户端:
public class client {
public static void main(String[] args) throws Exception {
//指定服务器ip及端口
NettyTransceiver nt = new NettyTransceiver(new InetSocketAddress("127.0.0.1", 6666));
//从服务器获取实现类
AddService proxy = SpecificRequestor.getClient(AddService.class, nt);
int result = proxy.add(1, 5);
System.out.println(result);
}
}
先启动服务端,后启动客户端,输出6;
传输对象案例:
客户端将Student对象传给服务器。
1.将student.avsc拷贝到client下的src/main/avro
2.修改AddService.avdl
@namespace("avro.service")
protocol AddService{
import schema "student.avsc";
int add(int a,int b);
void sendStudent(avro.pojo.Student stu);
}
重新Pom run as一下。
服务器端实现类增加方法
//注意,返回值是Void,这个是格式,返回Null就可以了。
public Void sendStudent(Student stu) throws AvroRemoteException {
System.out.println("服务器端接收:"+stu);
return null;
}
修改客户端类添加
Student stu = new Student("jack",23);
proxy.sendStudent(stu);
再次运行即可。