NIFI自定义开发

NIFI自定义开发

NIFI自定义开发组件的结果目标,是能够在NIFI主页Processor里面拖动出来可以使用自己设置的属性,以及自己操作的逻辑处理。NIFI自定义组件的开发,其实就是继承AbstractProcessor 类,实现其方法即可。
下面直接放上一个例子进行说明,以及各对象的使用用途说明。

自定义开发组件步骤

1、maven POM文件中引入nifi对应包;
2、resources目录下新建文件夹
META-INF.services
3、META-INF.services下新建一个File
org.apache.nifi.processor.Processor 存放自定义Processor组件的路径
在这里插入图片描述
4、新建Processor,初次创建建议从nifi源码中复制一个Processor过来,然后直接更改名字
5、创建属性PropertyDescriptor 配置;
6、创建结果状态码Relationship;
7、在onTrigger方法中,获取输入参数和上游传入FlowFile,进行逻辑处理后,返回新的FlowFile;
8、设置返回的结果状态码;如果多个结果需要返回不同的状态码,走不同的线路。nifi支持同时返回多个状态码并附带FlowFile内容。可参考源码里面的公共Processor。

目录

在这里插入图片描述

事例源码如下

此Class功能为提取JSON属性中某个属性值并返回,代码较少,比较简单

package com.leach.nifi.processor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.leach.nifi.common.LeachCommon;
import org.apache.commons.io.IOUtils;
import org.apache.nifi.annotation.behavior.InputRequirement;
import org.apache.nifi.annotation.behavior.SideEffectFree;
import org.apache.nifi.annotation.behavior.SupportsBatching;
import org.apache.nifi.annotation.behavior.WritesAttribute;
import org.apache.nifi.annotation.documentation.CapabilityDescription;
import org.apache.nifi.annotation.documentation.Tags;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.flowfile.FlowFile;
import org.apache.nifi.flowfile.attributes.CoreAttributes;
import org.apache.nifi.logging.ComponentLog;
import org.apache.nifi.processor.*;
import org.apache.nifi.processor.exception.ProcessException;
import org.apache.nifi.processor.io.StreamCallback;
import org.apache.nifi.processor.util.StandardValidators;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;

/**
* @title    
* @author   xiaobin.wang
* @create   2020/01/02
*/
//不需要关注上下文
@SideEffectFree
//支持批量
@SupportsBatching
//用于标记这个processor的标签,可以用于搜索
@Tags({ "leach","extract", "json", "attribute","key"})
// 声明允许输入
@InputRequirement(InputRequirement.Requirement.INPUT_ALLOWED)
//针对这个processor的注释
@CapabilityDescription("提取json中某个属性作为新的flowfile传递到下方")
@WritesAttribute(attribute = "mime.type", description = "Sets the mime type to application/json")
public class LeachExtractAttrFromJson extends AbstractProcessor {

    private List<PropertyDescriptor> properties;
    private Set<Relationship> relationships;

    public static final PropertyDescriptor ATTRIBUTE_NAME=new PropertyDescriptor.Builder()
            .name("ATTRIBUTE NAME")
            .required(true)
            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
            .description("json对象中的key键,如果提取嵌套中的key键,则使用英文“:”号分割。例:key:key1:key2。key键不允许存在于数组中,只允许存在于单个对象中")
            .build();
    public static final PropertyDescriptor RESULT_IS_JSON=new PropertyDescriptor.Builder()
            .name("RESULT IS JSON")
            .required(true)
            .description("结果是否格式化为json格式")
            .defaultValue("true")
            .allowableValues("true", "false")
            .build();

    public static final Relationship SUCCESS = new Relationship.Builder().name("success")
            .description("提取成功的flowfile内容标识").build();

    public static final Relationship REL_FAILURE = new Relationship.Builder().name("failure").description(
            "提取失败的flowfile内容标识")
            .build();

    @Override
    public void init(final ProcessorInitializationContext context) {
        ArrayList<PropertyDescriptor> properties = new ArrayList<>();
        properties.add(ATTRIBUTE_NAME);
        properties.add(RESULT_IS_JSON);
        // 防止多线程ADD
        this.properties = Collections.unmodifiableList(properties);
        Set<Relationship> relationships = new HashSet<>();
        relationships.add(SUCCESS);
        relationships.add(REL_FAILURE);
        // 防止多线程ADD
        this.relationships = Collections.unmodifiableSet(relationships);
    }


    @Override
    public void onTrigger(ProcessContext processContext, ProcessSession processSession) throws ProcessException {
        final ComponentLog logger =getLogger();
        FlowFile flowFile = processSession.get();
        if (flowFile == null) {
            logger.error("FlowFile is null", new Object[] {});
            return;
        }
        final String keys_name = processContext.getProperty(ATTRIBUTE_NAME).getValue();
        final String is_json = processContext.getProperty(RESULT_IS_JSON).getValue();
        String[] keys=keys_name.split(":");

        try {
            flowFile = processSession.write(flowFile, new StreamCallback() {
                @Override
                public void process(InputStream rcdIn, OutputStream rcdOut) throws IOException {
                    String json = IOUtils.toString(rcdIn,"utf-8");
                    JSONObject sourceTmp = JSON.parseObject(json);
                    List<String> list=new ArrayList<>();
                    Collections.addAll(list,keys);
                    Object val= LeachCommon.extractAttrVal(list,sourceTmp);
                    if("true".equalsIgnoreCase(is_json)){
                        val=JSONObject.parseObject(String.valueOf(val),Object.class);
                    }
                    //根据key获取值
                    rcdOut.write(JSON.toJSONString(val).getBytes());
                }
            });
            flowFile = processSession.putAttribute(flowFile, CoreAttributes.MIME_TYPE.key(), "application/json");
            flowFile = processSession.putAttribute(flowFile, "inputProcessor", this.getIdentifier());
            flowFile = processSession.putAttribute(flowFile, "relationship", "success");
            flowFile = processSession.putAttribute(flowFile, "level", "INFO");
            processSession.transfer(flowFile, SUCCESS);
        } catch (final Exception pe) {
            logger.error("从json中提取属性失败 {}  due to {}; transferring to failure",
                    new Object[] { flowFile, pe });
            flowFile = processSession.putAttribute(flowFile, "inputProcessor", this.getIdentifier());
            flowFile = processSession.putAttribute(flowFile, "relationship", "failure");
            flowFile = processSession.putAttribute(flowFile, "level", "ERROR");
            processSession.transfer(flowFile, REL_FAILURE);
            return;
        }
    }

    @Override
    public Set<Relationship> getRelationships() {
        return relationships;
    }

    @Override
    public List<PropertyDescriptor> getSupportedPropertyDescriptors() {
        return properties;
    }

编辑Resources文件

在org.apache.nifi.processor.Processor 文件中增加此Class的路径
在这里插入图片描述

POM文件

<modelVersion>4.0.0</modelVersion>

<groupId>com.leach.nifi</groupId>
<artifactId>leach_nifi</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>nar</packaging>
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <nifi.version>1.11.3</nifi.version>
 </properties>
  
<dependency>
      <groupId>org.apache.nifi</groupId>
      <artifactId>nifi-api</artifactId>
      <version>${nifi.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.nifi</groupId>
      <artifactId>nifi-processor-utils</artifactId>
      <version>${nifi.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.nifi</groupId>
      <artifactId>nifi-utils</artifactId>
      <version>${nifi.version}</version>
    </dependency>
     <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.62</version>
    </dependency>
     <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.1.6.RELEASE</version>
 </dependency>
	
<build>
   <plugins>
     <plugin>
       <groupId>org.apache.nifi</groupId>
       <artifactId>nifi-nar-maven-plugin</artifactId>
       <version>1.3.1</version>
       <extensions>true</extensions>
     </plugin>
     <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-surefire-plugin</artifactId>
       <version>3.0.0-M4</version>
     </plugin>
   </plugins>
 </build>

代码说明

AbstractProcessor:自定义开发nifi插件包,继承此类
PropertyDescriptor:此对象为nifi插件前端供用户进行配置的属性设置
例下图中属性,对应前端组件情形
在这里插入图片描述
在这里插入图片描述
PropertyDescriptor.addValidator:此参数为验证前端输入的数据是否符合此设置格式,所有的验证方式参考源码中StandardValidators类
PropertyDescriptor.allowableValues:此参数设置后,前端将变成下拉框选择样式;
Relationship:此对象为插件执行后,返回的结果状态关系,一般设置两个即可,一个成功一个失败;有特殊情况,可自行增加设置。需要注意,每个Processor执行后,所有的结果必须配置一个结果状态。
在这里插入图片描述
init:此方法目的是将此类中的属性和状态码组装起来返回给前端插件,每增加一个属性,都需要增加进去。固定

onTrigger:此方法为插件执行后,触发的事件执行器,组件的所有逻辑及数据处理均在此方法里面;
ProcessContext:此对象中包含前端传入的所有参数信息;
ProcessSession:此对象包含上游传入进此插件的所有Flowfile内容,最终返回给前端的FlowFile也是存放进此对象之中的

打包项目

文件开发完毕、配置文件添加成功后,进行打包:IDEA中maven package
在这里插入图片描述
打包后,会在你项目的target里面看到一个nar包
在这里插入图片描述

更新nifi服务

将此nar包复制到你的nifi服务器上,nifi根目录下extensions文件夹下,然后重启nifi服务器即可;
需要注意:如果插件包有错误,则可能不会显示;开发过程中如果发现插件包中某个功能或属性一直不生效,则基本都是代码有问题,可在启动时候跟踪日志文件即可。
本地调试自定义组件,参考:https://blog.csdn.net/u011291276/article/details/107213599

重启

重启后,即可在Processor里面看到自己开发的插件包
在这里插入图片描述

备注

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值