У меня есть процессор, который зависит от какой-то банки в качестве зависимости. Однако довольно часто вносятся изменения в банку зависимостей. Поэтому я хочу иметь возможность указать путь к банке как свойство процессора и позволить 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>
Я тестирую этот процессор следующим образом:
Конфигурация процессора:
Я получаю следующее исключение:
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 зависимостей) здесь.
На самом деле, я пытался указать оба. Я сохранил djl-dependency-0.0.1-SNAPSHOT.jar
в C:\Mahesh\delete\djl
. Затем сначала я попытался установить для свойства процессора значение C:\Mahesh\delete\djl
. Это не сработало. Затем я попытался установить свойство на C:\Mahesh\delete\djl\djl-dependency-0.0.1-SNAPSHOT.jar
. Все еще не работал.
@daggett какой-нибудь указатель, пожалуйста ?? Я пропустил что-нибудь глупое? Вы смогли запустить мой код?
Я просто знаю, что есть стандартные процессоры, которые используют эту функцию. Например: github.com/apache/nifi/blob/master/nifi-nar-bundles/…
Попробуйте динамическую загрузку класса вместо статической
Может быть проблема с путями к файлам в Windows, возможно, стоит поместить валидатор каталога или файла в дескриптор свойства (в зависимости от того, что вы указываете), чтобы убедиться, что NiFi думает, что что-то есть, прежде чем он даже доберется до загрузки класса
Вы отметили процессор знаком @RequiresInstanceClassloading
?
@daggett, что вы подразумеваете под «Попробуйте динамическую загрузку класса вместо статической»? Динамическая загрузка класса в Java выполняется с помощью Class.forName
, тогда как загрузка статического класса — это не что иное, как создание экземпляра с помощью оператора new
. Вы имеете в виду сделать этот элемент экземпляра свойства pathToDjlDependencyJar
, удалив модификатор static
?
@ Махеша999, точно. Но через classloader текущего класса. Или, может быть, через контекстный загрузчик классов... Я думаю, это сработает.
Любая ссылка (/объяснение), обсуждающая «загрузчик классов текущего класса» и «загрузчик классов контекста», пожалуйста... (Попытался запустить мой код на nifi 1.9.2, не сработало, раньше я был на 1.5.2)
В документе API для PropertyDescriptor
упоминается следующее примечание:
If a component contains a PropertyDescriptor where dynamicallyModifiesClasspath is set to true, the component must also be annotated with @RequiresInstanceClassloading, otherwise the component will be considered invalid.
Я не уверен, что эта «недопустимая» часть все еще верна, но да, после обновления кода вашего процессора, чтобы он был аннотирован @RequiresInstanceClassloading
, я смог заставить его работать.
Вы хотите сказать, что простое выполнение @RequiresInstanceClassLoading public class MyDjlProcessor extends AbstractProcessor { .. }
заставило его работать? Не работает для меня. Я использую NiFi версии 1.5.0. это может быть проблемой?
Вы уверены, что аннотация процессора с помощью @RequiresInstanceClassLoading
должна заставить его работать? Я только что упомянул стандартный процессор JoltTransformRecord
связанный от daggett в комментариях. Этот процессор не помечен @RequiresInstanceClassLoading
. Но, как вы заметили, документ говорит, что процессор должен быть помечен @RequiresInstanceClassLoading
. Эта версия специфична? Я на нифи 1.5.0.
Можете ли вы дать свои характеристики установки / среды?
Крайне извиняюсь за задержку ответа. Поделимся кодом с вами сегодня.
почему вы указываете каталог, а не банку в качестве значения параметра classpath? что у тебя в папке `...\djl`?