Привет, мир, программа динамически изменяющего класс Classpath () Apache Nifi, дескриптор свойств не работает - PullRequest
2 голосов
/ 27 мая 2019

У меня есть процессор, который зависит от некоторых jar в качестве зависимости. Однако изменения делаются в банке зависимостей довольно часто. Поэтому я хочу иметь возможность указать путь к банке как свойство процессора и позволить nifi загружать банку каждый раз, когда я изменяю путь в свойстве и перезагружаю процессор. Предполагается, что это выполнимо, используя dynamicallyModifiesClasspath, как описано в этой статье . Однако я не могу этого сделать. Ниже приведен мой код программы hello world с использованием свойства dynamicallyModifiesClasspath:

(Ниже Djl обозначает «динамическую загрузку jar», случайный префикс, который я предположил назвать этой программой hello world.)

DjlDependencyClass.java

Это класс, от которого зависит мой процессор nifi, и я хочу динамически изменить его путь jar в моем процессоре nifi.

public class DjlDependencyClass {

    public static String getMessage()
    {
        return "DJL-DEPENDENCY VERSION-1";
    }
}

MyDjlProcessor.java

Это процессор nifi, который зависит от класса DjlDependencyClass.

import org.apache.nifi.annotation.lifecycle.OnScheduled;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.processor.exception.ProcessException;    
import org.apache.nifi.processor.AbstractProcessor;
import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.ProcessSession;
import org.apache.nifi.processor.ProcessorInitializationContext;
import org.apache.nifi.processor.Relationship;
import org.apache.nifi.processor.util.StandardValidators;

import com.mycompany.djldependency.DjlDependencyClass;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class MyDjlProcessor extends AbstractProcessor {

    public static final Relationship MY_RELATIONSHIP = new Relationship.Builder()
            .name("MY_RELATIONSHIP")
            .description("Example relationship")
            .build();

    public static final PropertyDescriptor pathToDjlDependencyJar = new PropertyDescriptor.Builder()
            .name("Djl Dependency JAR")
            .description("Djl Dependency JAR")
            .required(true)
            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
            .dynamicallyModifiesClasspath(true)
            .expressionLanguageSupported(true)
            .build();

    private List<PropertyDescriptor> descriptors;

    private Set<Relationship> relationships;

    @Override
    protected void init(final ProcessorInitializationContext context) {
        final List<PropertyDescriptor> descriptors = new ArrayList<PropertyDescriptor>();
        descriptors.add(pathToDjlDependencyJar);
        this.descriptors = Collections.unmodifiableList(descriptors);

        final Set<Relationship> relationships = new HashSet<Relationship>();
        relationships.add(MY_RELATIONSHIP);
        this.relationships = Collections.unmodifiableSet(relationships);
    }

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

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

    @OnScheduled
    public void onScheduled(final ProcessContext context) {

    }

    @Override
    public void onTrigger(final ProcessContext context, final ProcessSession session) throws ProcessException {
        System.out.println(DjlDependencyClass.getMessage());
    }
}

Вот как помечается зависимость внутри pom, чтобы иметь область видимости provided, чтобы jar зависимости не был встроен в nar:

   <dependency>
        <groupId>com.mycompany</groupId>
        <artifactId>djl-dependency</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <scope>provided </scope>
    </dependency>

Я тестирую этот процессор следующим образом:

enter image description here

Конфигурация процессора:

enter image description here

Я получаю следующее исключение:

2019-05-27 17:01:54,536 ERROR [Timer-Driven Process Thread-1] com.mycompany.djl.MyDjlProcessor MyDjlProcessor[id=f8fa5750-016a-1000-ecc3-c19732119332] MyDjlProcessor[id=f8fa5750-016a-1000-ecc3-c19732119332] failed to process due to java.lang.NoClassDefFoundError: com/mycompany/djldependency/DjlDependencyClass; rolling back session: {}
java.lang.NoClassDefFoundError: com/mycompany/djldependency/DjlDependencyClass
    at com.mycompany.djl.MyDjlProcessor.onTrigger(MyDjlProcessor.java:76)
    at org.apache.nifi.processor.AbstractProcessor.onTrigger(AbstractProcessor.java:27)
    at org.apache.nifi.controller.StandardProcessorNode.onTrigger(StandardProcessorNode.java:1122)
    at org.apache.nifi.controller.tasks.ContinuallyRunProcessorTask.call(ContinuallyRunProcessorTask.java:147)
    at org.apache.nifi.controller.tasks.ContinuallyRunProcessorTask.call(ContinuallyRunProcessorTask.java:47)
    at org.apache.nifi.controller.scheduling.TimerDrivenSchedulingAgent$1.run(TimerDrivenSchedulingAgent.java:128)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

Я здесь что-то делаю глупо?

Пожалуйста, скачайте оба проекта (nifi и jar зависимостей) здесь .

1 Ответ

0 голосов
/ 29 мая 2019

В документе API для PropertyDescriptor упоминается следующее примечание:

Если компонент содержит PropertyDescriptor, для которого dynamicicallyModifyClasspath установлен в значение true, компонент также должен быть аннотирован @RequiresInstanceClassloading, в противном случае компонентбудет считаться недействительным.

Я не уверен, что эта «недействительная» часть все еще остается в силе, но да, после обновления кода вашего процессора, чтобы пометить его как @RequiresInstanceClassloading, я смог получитьэто работает.

...