“家家泉”完成近亿元B轮融资,沣途资本领投
06-17
前言 之前有一篇文章讲了Java的Gson、FastJson等解析json的常用类。与Python的json模块相比,繁琐的部分是需要定义各种实体类。
那么,有没有一种方法可以在Java中自动定义实体类呢?数据访问是我的大数据工作的一部分。固定长度、csv 和 json 是一些更常见的数据格式。
通常我使用Flume来完成数据访问。我根据对端数据源配置源,在数据源上配置Interceptor,通道设置为kafka(一般是内存,所以放在kafka中进行流计算)。
Sink被设置为等待后续调度和存储的文件。 Flume提供的Source、Channel、Sink基本可以满足日常需求,并且可以通过conf配置轻松使用。
Interceptor往往需要自己开发封装,放在Flume的lib中,然后在conf配置中绑定到source,这样数据在进入通道之前就可以进行处理。随着访问的Json数据越来越多,每次访问json格式时,都必须定义一个实体类,然后定义一个Interceptor来将Json解析为CSV。
然后有一天我在想是否可以开发一个兼容Json的Interceptor。通过在配置文件中配置字段名,就会自动生成实体类,然后将实体类自动引入到Gson中解析json数据。
当javassist说到自动生成类时,让我想起了2006年自学Java时学到的javassist类。javassist提供了动态生成类的功能。
接下来我们看看如何使用javassist创建类。代码语言:xml copy
这个类就是CtClass,它是一个编译时类,编译时类文件。下一步是查看如何创建 CtClass 对象。
从注释来看,CtClass是从ClassPool中获取的。 ClassPoolClassPool是一个存储JVM加载的类的容器。
我们通常使用ClassPool.getDefault()来获取CLASSPATH类。代码语言:java copy ClassPool pool = ClassPool.getDefault();CtClass ctClass = pool.get("java.lang.String");System.out.println(ctClass);让我们获取 String 的 CtClass。
可以看到,String字段被封装成CtMethod类型,构造函数被封装成CTConstructor,同样的字段被封装成CtField。构建实体类下一步就是构建json数据对应的实体类。
通过调用CtPool的makeClass()方法,您可以创建一个新的空CtClass,然后添加字段和方法。 Flume主要是从外部配置参数,然后通过脚本启动,所以我通过参数配置json实体类的字段名。
日常开发中比较常见的json主要格式有两种:简单类型,每个字段对应一个简单类型。对于复杂类型,某些字段对应于自定义类数据或列表。
这里我们首先描述如何构建一个简单类型的实体类。制定规范,首先要根据要处理的数据定制规范。
代码语言:java Copy String json = "{\"name\": \"Tom\", \"age\": \"10\", \"time\": \"\" }";String className = "A";String fields = "name,age,time";String Connector = "|";代码中,json为要处理的json数据,className、fields、connector为传入的外部参数,分别是代表要创建的类。名称、字段和 toString 方法连接器。
构造ctClass 根据上面提到的方法,初始化ctClass后,需要添加字段和toString。代码语言:java copy public static CtClassgenerateClass(String className, String fields, String Connector) throws CannotCompileException { ClassPool pool = ClassPool.getDefault(); // 初始化 CtClas CtClass ctClass = pool.makeClass(className); for (String field: fields.split(",")) { // 添加字段 ctClass.addField(CtField.make("private String " + field + ";", ctClass)); } // 添加 toString 方法 ctClass.addMethod(CtMethod.make ("public String toString() { String result = " + fields.replace(",", "+ \"" + Connector + "\" +") + ";返回结果;}", ctClass)); return ctClass ;}通过ctClass.addField添加字段,参数类型为CtField,可以直接通过CtField.make构建。
拆分后,遍历传入的字段,将字段直接添加到ctClass中。这里我直接默认为String类型。
如果想做成其他类型,可以准确指定传入参数的数据类型。因为结果将以csv格式输出,所以必须在最后添加toString方法来定义输出格式。
您可以使用 addMethod 直接添加 toString 方法。连接器是每个字段的分隔符。
通过替换 fields.replace,将姓名、年龄和时间替换为姓名+“|” + 年龄 + “|” + time,用于构建 toString 代码。最后返回完成的ctClass。
loadClass以Gson为例。调用fromJson解析json字符串时,第一个参数是json字符串,第二个参数是Class对象。
如何通过CtClass获取Class,首先想到的肯定是类加载器ClassLoader。 Class源码注释中也提供了这个方法。
JVM使用ClassLoder.defineClass将编译后的类文件以字节形式加载并构建为Class对象。 Ctclass中的toBytecode可以将ctClass转换为class文件。
所以这里我们定义一个loadClass方法来生成Class。代码语言:java copy public static Class loadClass(CtClass ctClass, String className) { Class c = null;字节 [] 字节类;尝试 { byteClass = ctClass.toBytecode(); // 反射 Class> clazz = Class.forName( "java.lang.ClassLoader");方法defineClass = clazz.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);定义Class.setAccessible(true); c = (Class ) DefineClass.invoke(ClassLoader.getSystemClassLoader(), className, byteClass, 0, byteClass.length); } catch (Exception e) { e.printStackTrace(); } return c;} 因为ClassLoder.defineClass是一个非公共方法,所以我们只能通过反射来调用这个方法,最终生成一个类对象。
这样Gson需要的Class参数也生成了,现在我们可以测试一下了。解析json来测试上面定义的json: 代码语言:java Copy String json = "{\"name\": \"Tom\", \"age\": \"10\", \"time\": \ "\" }";字符串类名 = "A";字符串字段 = "姓名、年龄、时间";字符串连接器 = "|";CtClass ctClass =generateClass(类名, 字段, 连接器);Gson gson = new Gson( ) ;Object o = gson.fromJson(json, loadClass(ctClass, className));System.out.println(o);结果输出:将json替换为其他字段进行测试: 代码语言:java Copy String json = "{ \" a\": \"11\", \"b\": \"10\", \"c\": \"22\", \"d\": \"22\"}";字符串类名 = "A";字符串字段 = "a,b,c,d,e";字符串连接器 = ",";CtClass ctClass =generateClass(类名, 字段, 连接器);Gson gson = new Gson();Object o = gson.fromJson(json, loadClass(ctClass, className));System.out.println(o);结果输出:经测试,可以实现简单类型json的配置解析。
结论关于复杂类型json解析和配置解析,也可以稍后再写。我在开发列表类型的json解析类时,使用javassist遇到了编译时的问题。
我稍后再研究。当然,我是2018年开始使用flume的,不仅仅是一些数据访问,还有大数据量的应用场景。
本人有使用flume从Kafka转HDFS超过1亿条记录/天(存储T/天)的实践,所以还是有一定经验的,对flume感兴趣的可以一起学习!我正在参加第五期腾讯科技创造特训营有奖征文比赛。
版权声明:本文内容由互联网用户自发贡献,本站不拥有所有权,不承担相关法律责任。如果发现本站有涉嫌抄袭的内容,欢迎发送邮件 举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。
标签:
相关文章
06-17
06-17
06-18
06-18
06-17
06-17
06-18
06-18
最新文章
【玩转GPU】ControlNet初学者生存指南
【实战】获取小程序中用户的城市信息(附源码)
包雪雪简单介绍Vue.js:开学
Go进阶:使用Gin框架简单实现服务端渲染
线程池介绍及实际案例分享
JMeter 注释 18 - JMeter 常用配置组件介绍
基于Sentry的大数据权限解决方案
【云+社区年度征文集】GPE监控介绍及使用