Jackson多态反序列化的使用

Posted yueguanghaidao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jackson多态反序列化的使用相关的知识,希望对你有一定的参考价值。

缘起

最近看Apache Druid的源代码(0.5很老的版本),印象最深的就是对Jackson的多态反序列化和注入的使用了,这里也属于自己的知识盲点,看着复杂的json直接反序列化为可用对象,直呼过瘾。所以一直想找个机会实践一下,这不需求就来了。

需求

我们的实时指标统计是通过Flink Steam SQL计算为维度、指标后后入Hbase,然后通过Phoenix SQL给前台展示。现在新接入Kylin数据源,需要兼容查询Kylin数据源。

看到这个需求,变化点在查询方式上,抽象出查询服务,提供多态支持,但各个指标查询需要的信息是不同的。如Kylin数据源需要查询的表名,聚合函数等,但Hbase数据源压根不需要这些信息,这时候就该Jackson多态反序列化出厂了。

实践

数据库新增querySpec字段,描述指标的个性化需求,如“type”:“rc”,“tableName”:“TASK_SNAPSHOT”,“fieldName”:“EVENTCODE”
“type”:“hbase”

看如下代码:

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

/**
 * Created by yihaibo on 2019-09-11.
 */
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, property = "type", defaultImpl = HbaseQuerySpec.class )
@JsonSubTypes(value = 
        @JsonSubTypes.Type(value = HbaseQuerySpec.class, name = "hbase"),
        @JsonSubTypes.Type(value = RcHttpQuerySpec.class, name = "rc")
)
public interface QuerySpec 
    String getMetricQueryServiceName();


/**
* hbase数据源个性化信息
*/
public class HbaseQuerySpec implements QuerySpec 
    @Override
    public String getMetricQueryServiceName() 
        return "hbaseQueryService";
    


/**
* kylin数据源个性化信息(已通过http服务化)
*/
public class RcHttpQuerySpec implements QuerySpec 
    @Getter
    @Setter
    @JsonProperty
    private String tableName;

    @Getter
    @Setter
    @JsonProperty
    private String fieldName;

    @Override
    @JsonIgnore
    public String getMetricQueryServiceName() 
        return "rcMetricQueryService";
    

我们看到新增了getMetricQueryServiceName方法,用于指定处理该数据源的service名称。

有了个性化参数,可以写查询服务了

public interface MetricQueryService 
   /**
     * 
     * @param dataQueryDTO  通用查询参数
     * @param querySpec  个性化配置信息
     * @return
     */
    List<Map<String,Object>> queryData(DataQueryDTO dataQueryDTO, QuerySpec querySpec);


  /**
     * 查询Hbase原始数据
     * */
@Service("hbaseQueryService")
public class HbaseMetricQueryService implements MetricQueryService 
    @Override
    public List<Map<String,Object>> queryData(DataQueryDTO dataQueryDTO, QuerySpec querySpec)
        ....
    

  /**
     * 查询kylin数据
     * */
@Service("rcMetricQueryService")
public class RcMetricQueryService implements MetricQueryService 
    @Override
    public List<Map<String, Object>> queryData(DataQueryDTO dataQueryDTO, QuerySpec querySpec) 
        RcHttpQuerySpec rcHttpQuerySpec = (RcHttpQuerySpec)querySpec;
        ...
 

反序列化querySpec,获取服务名称,然后通过spring获取到该service bean,传递处理参数

QuerySpec querySpec = JsonUtil.decode(querySpec, QuerySpec.class);
String serviceName = querySpec.getMetricQueryServiceName();
MetricQueryService metricQueryService = CtxUtil.getBean(serviceName, MetricQueryService.class);
List<Map<String,Object>> data = metricQueryService.queryData(dataQueryDTO, querySpec);
@Component
@Slf4j
public class CtxUtil implements ApplicationContextAware 

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException 
        applicationContext = ctx;
        log.info("init ctx ok");
    

    public static <T> T getBean(Class<T> clazz) 
        return applicationContext.getBean(clazz);
    

    public static <T> T getBean(String name, Class<T> clazz) 
        return applicationContext.getBean(name, clazz);
    

反思

Jackson多态反序列化的确是开发力气,可以去掉不少if else样例代码,精简配置。但感觉用Jackson注入还是不太合适,Jackson对象还是作为POJO比较合适,逻辑层还是service层或单独bo去处理,需要注入可以用spring或guice,职则方面,方便test case。

最近在研究Apache Druid,主要学习一些分布式处理知识,以及想看下列式存储到底是如何做的。实时OLAP的确用处多多,Apache Kylin也在扩展实时处理,期待两着的碰撞与融合。

以上是关于Jackson多态反序列化的使用的主要内容,如果未能解决你的问题,请参考以下文章

jackson-- JsonTypeInfo多态反序列化

基于唯一属性的存在用 Jackson 反序列化多态类型

Jackson 多态序列化生成不正确的类名

返回类型为标记接口时使用 Jackson 进行多态序列化

JSON Jackson - 使用自定义序列化程序序列化多态类时的异常

使用 Jackson 自定义反序列化:扩展默认反序列化器