前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Apache Avro 入门

Apache Avro 入门

作者头像
CoderJed
发布2018-09-13 10:31:35
2.8K0
发布2018-09-13 10:31:35
举报
文章被收录于专栏:Jed的技术阶梯

1. 简介

Apache Avro(以下简称 Avro)是一种与编程语言无关的序列化格式。Doug Cutting 创建了这个项目,目的是提供一种共享数据文件的方式。

Avro 数据通过与语言无关的 schema 来定义。schema 通过 JSON 来描述,数据被序列化成二进制文件或 JSON 文件,不过一般会使用二进制文件。Avro 在读写文件时需要用到 schema,schema 一般会被内嵌在数据文件里。

Avro 有一个很有意思的特性是,当负责写消息的应用程序使用了新的 schema,负责读消息的应用程序可以继续处理消息而无需做任何改动。

到写本篇博客的时间为止,avro的最新版本为1.8.2

2. 创建 maven 工程

(1) 加入 avro 依赖

代码语言:javascript
复制
<dependency>
  <groupId>org.apache.avro</groupId>
  <artifactId>avro</artifactId>
  <version>1.8.2</version>
</dependency>

(2) 加入 avro 插件的依赖

代码语言:javascript
复制
<plugin>
  <groupId>org.apache.avro</groupId>
  <artifactId>avro-maven-plugin</artifactId>
  <version>1.8.2</version>
  <executions>
    <execution>
      <phase>generate-sources</phase>
      <goals>
        <goal>schema</goal>
      </goals>
      <configuration>
        <sourceDirectory>${project.basedir}/src/main/avro/</sourceDirectory>
        <outputDirectory>${project.basedir}/src/main/java/</outputDirectory>
      </configuration>
    </execution>
  </executions>
</plugin>
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <source>1.6</source>
    <target>1.6</target>
  </configuration>
</plugin>

以上是官网列出的 avro 插件的依赖,其中提供了 maven 的编译插件,该插件使用JDK1.6版本来编译代码,我在这里改为了1.8,因为我的JDK版本是1.8

代码语言:javascript
复制
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <source>1.8</source>
    <target>1.8</target>
  </configuration>
</plugin>

在引入这个插件后,在 pom.xml 中会有编译错误(错误原因我也不清楚),选择忽略即可

选择忽略之后,在 pom 中会自动生成以下配置来说明 pom 文件已经忽略了 avro 插件引起的错误

代码语言:javascript
复制
<pluginManagement>
    <plugins>
        <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
        <plugin>
            <groupId>org.eclipse.m2e</groupId>
            <artifactId>lifecycle-mapping</artifactId>
            <version>1.0.0</version>
            <configuration>
                <lifecycleMappingMetadata>
                    <pluginExecutions>
                        <pluginExecution>
                            <pluginExecutionFilter>
                                <groupId>org.apache.avro</groupId>
                                <artifactId>avro-maven-plugin</artifactId>
                                <versionRange>[1.8.2,)</versionRange>
                                <goals>
                                    <goal>schema</goal>
                                </goals>
                            </pluginExecutionFilter>
                            <action>
                                <ignore></ignore>
                            </action>
                        </pluginExecution>
                    </pluginExecutions>
                </lifecycleMappingMetadata>
            </configuration>
        </plugin>
    </plugins>
</pluginManagement>

以上错误是在 Eclipse 中创建 avro 的 maven 项目时才会出现,在 IDEA 中就不会出现这种情况。

(3) 更新 maven 工程

作了以上修改后,发现 maven 项目上有报错,但 pom 中并没有错误:

在项目上右键更新maven项目即可:

3. 使用 avro

(1) 通过生成代码的方式使用 avro

<1> 定义 schema 文件

注意在 avro 插件的依赖中定义的两个路径

代码语言:javascript
复制
<configuration>
    <sourceDirectory>${project.basedir}/src/main/avro/</sourceDirectory>
    <outputDirectory>${project.basedir}/src/main/java/</outputDirectory>
</configuration>

该配置的意思是,根据/src/main/avro/下的schema文件,生成对应的类文件到/src/main/java/下,所以我们先创建一个资源文件夹/src/main/avro

然后再在该资源文件夹下创建 schema 文件,这里定义一个简单的schema文件user.avsc,注意,后缀一定是avsc,其中的内容如下:

代码语言:javascript
复制
{
    "namespace": "com.avro.example",
    "type": "record",
    "name": "User",
    "fields": [
        {"name": "name", "type": "string"},
        {"name": "favorite_number",  "type": ["int", "null"]},
        {"name": "favorite_color", "type": ["string", "null"]}
    ]
}
  • namespace:定义了根据 schema 文件生成的类的包名
  • type:固定写法
  • name:生成的类的名称
  • fields:定义了生成的类中的属性的名称和类型,其中"type": ["int", "null"]的意思是,favorite_number 这个属性是int类型,但可以为null

avro 支持的类型有null、boolean、int、long、float、double、bytes、string这些基本类型和record、enum、array、map、union、fixed这些复杂类型,关于复杂类型可以参考官网的说明:http://avro.apache.org/docs/current/spec.html#schema_complex,本文只是一个入门

<2> 生成 User 类

在编译程序之前,项目中是没有com.avro.example.User这个类的:

在运行 maven build compile 后,就生成这个类:

<3> 序列化

代码语言:javascript
复制
package com.avro.serializer;

import java.io.File;
import java.io.IOException;

import org.apache.avro.file.DataFileWriter;
import org.apache.avro.io.DatumWriter;
import org.apache.avro.specific.SpecificDatumWriter;

import com.avro.example.User;

/**
 * @Title AvroSerializerTest.java 
 * @Description 使用 avro 对 com.avro.example.User 类的对象进行序列化
 * @Author YangYunhe
 * @Date 2018-06-21 15:42:02
 */
public class AvroSerializerTest {
    
    public static void main(String[] args) throws IOException {
        
        User user1 = new User();
        user1.setName("Tom");
        user1.setFavoriteNumber(7);
        
        User user2 = new User("Jack", 15, "red");
        
        User user3 = User.newBuilder()
                .setName("Harry")
                .setFavoriteNumber(1)
                .setFavoriteColor("green")
                .build();
        
        DatumWriter<User> userDatumWriter = new SpecificDatumWriter<>(User.class);
        DataFileWriter<User> dataFileWriter = new DataFileWriter<User>(userDatumWriter);
        dataFileWriter.create(user1.getSchema(), new File("users.avro"));
        dataFileWriter.append(user1);
        dataFileWriter.append(user2);
        dataFileWriter.append(user3);
        dataFileWriter.close();
        
    }

}

运行以上程序,就会把这3个User对象经过 avro 序列化后写到了项目根目录下的"user.avro"文件中:

<4> 反序列化

代码语言:javascript
复制
package com.avro.deserializer;

import java.io.File;
import java.io.IOException;

import org.apache.avro.file.DataFileReader;
import org.apache.avro.io.DatumReader;
import org.apache.avro.specific.SpecificDatumReader;

import com.avro.example.User;

/**
 * @Title AvroDeSerializerTest.java 
 * @Description 解析 avro 序列化后的对象
 * @Author YangYunhe
 * @Date 2018-06-21 15:58:10
 */
public class AvroDeSerializerTest {
    
    public static void main(String[] args) throws IOException {
        
        DatumReader<User> userDatumReader = new SpecificDatumReader<User>(User.class);
        DataFileReader<User> dataFileReader = new DataFileReader<User>(new File("users.avro"), userDatumReader);
        User user = null;
        while (dataFileReader.hasNext()) {
            user = dataFileReader.next(user);
            System.out.println(user);
        }
    }
}

程序运行结果为:
{"name": "Tom", "favorite_number": 7, "favorite_color": null}
{"name": "Jack", "favorite_number": 15, "favorite_color": "red"}
{"name": "Harry", "favorite_number": 1, "favorite_color": "green"}

(2) 通过不生成代码的方式使用 avro

<1> 序列化

代码语言:javascript
复制
package com.avro.serializer;

import java.io.File;
import java.io.IOException;

import org.apache.avro.Schema;
import org.apache.avro.file.DataFileWriter;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericDatumWriter;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.DatumWriter;

import com.avro.deserializer.AvroDeSerializerWithoutCodeGenerationTest;

/**
 * @Title AvroSerializerWithoutCodeGenerationTest.java 
 * @Description 通过不生成代码的方式使用avro序列化User对象
 * @Author YangYunhe
 * @Date 2018-06-21 16:04:13
 */
public class AvroSerializerWithoutCodeGenerationTest {
    
    public static void main(String[] args) throws IOException {
        
        String avscFilePath = 
                AvroDeSerializerWithoutCodeGenerationTest.class.getClassLoader().getResource("user.avsc").getPath();
        Schema schema = new Schema.Parser().parse(new File(avscFilePath));
        
        GenericRecord user1 = new GenericData.Record(schema);
        user1.put("name", "Tony");
        user1.put("favorite_number", 18);

        GenericRecord user2 = new GenericData.Record(schema);
        user2.put("name", "Ben");
        user2.put("favorite_number", 3);
        user2.put("favorite_color", "red");
        
        File file = new File("user2.avro");
        DatumWriter<GenericRecord> datumWriter = new GenericDatumWriter<GenericRecord>(schema);
        DataFileWriter<GenericRecord> dataFileWriter = new DataFileWriter<GenericRecord>(datumWriter);
        dataFileWriter.create(schema, file);
        dataFileWriter.append(user1);
        dataFileWriter.append(user2);
        dataFileWriter.close();
    }
}

<2> 反序列化

代码语言:javascript
复制
package com.avro.deserializer;

import java.io.File;
import java.io.IOException;

import org.apache.avro.Schema;
import org.apache.avro.file.DataFileReader;
import org.apache.avro.generic.GenericDatumReader;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.DatumReader;

/**
 * @Title AvroDeSerializerWithoutCodeGenerationTest.java 
 * @Description 通过不生成代码的方式使用avro反序列化
 * @Author YangYunhe
 * @Date 2018-06-21 16:07:44
 */
public class AvroDeSerializerWithoutCodeGenerationTest {
    
    public static void main(String[] args) throws IOException {
        String avscFilePath = 
                AvroDeSerializerWithoutCodeGenerationTest.class.getClassLoader().getResource("user.avsc").getPath();
        Schema schema = new Schema.Parser().parse(new File(avscFilePath));
        File file = new File("user2.avro");
        DatumReader<GenericRecord> datumReader = new GenericDatumReader<GenericRecord>(schema);
        DataFileReader<GenericRecord> dataFileReader = new DataFileReader<GenericRecord>(file, datumReader);
        GenericRecord user = null;
        while (dataFileReader.hasNext()) {
            user = dataFileReader.next(user);
            System.out.println(user);
        }
    }
}

程序运行结果:
{"name": "Tony", "favorite_number": 18, "favorite_color": null}
{"name": "Ben", "favorite_number": 3, "favorite_color": "red"}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.06.21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 简介
  • 2. 创建 maven 工程
    • (1) 加入 avro 依赖
      • (2) 加入 avro 插件的依赖
        • (3) 更新 maven 工程
        • 3. 使用 avro
          • (1) 通过生成代码的方式使用 avro
            • <1> 定义 schema 文件
            • <2> 生成 User 类
            • <3> 序列化
            • <4> 反序列化
          • (2) 通过不生成代码的方式使用 avro
            • <1> 序列化
            • <2> 反序列化
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档