是否可以异步触发NamedBean中的事件并等待所有消费者(观察者)完成?消费者(观察者)应该异步运行,但如果所有事件都已完成,则应该完成该事件。
e.g。我有3个Beans(1个Bean可以激活事件,2个可以观察事件)。
触发事件的Bean:
@Named
@Stateless
public class TestExecuter implements Serializable {
@Inject
@MyEvent
private Event<QueryTO> myEvent;
public void run() {
QueryTO queryTO = new QueryTO(null, null);
FilterQualifier[] qualifiers = new FilterQualifier[3];
qualifiers[0] = new FilterQualifier(TestA.FILTER_ID);
qualifiers[1] = new FilterQualifier(TestB.FILTER_ID);
System.out.println("Fire event");
myEvent.select(qualifiers).fire(queryTO);
//wait till observers are finished
System.out.println("Event finished");
}
}
观察
的Bean 1@Named
@Stateless
public class TestA implements Serializable {
public static final String FILTER_ID = "TestA";
public void generateFilterQueryEvent(
@Observes @Filter(FILTER_ID) @MyEvent QueryTO queryTo) {
System.out.println("TestA called");
try {
Thread.sleep(3000);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
System.out.println("TestA finished");
}
}
观察
的Bean 2@Named
@Stateless
public class TestB implements Serializable {
public static final String FILTER_ID = "TestB";
public void generateFilterQueryEvent(
@Observes @Filter(FILTER_ID) @MyEvent QueryTO queryTo) {
System.out.println("TestB called");
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
System.out.println("TestB finished");
}
}
预期结果:两个bean同时执行代码,3秒后事件结束并且事件结束。目前它执行TestA
,然后执行TestB
,所以我必须等待5秒。
答案 0 :(得分:1)
AFAIK it's not supported by CDI虽然您可以使用自定义AsyncEvent
类来解决它,该类获取观察者并在单独的线程中调用它们。这是一个概念证明示例:
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.ObserverMethod;
import javax.enterprise.util.AnnotationLiteral;
import javax.inject.Inject;
public class AsyncEvent<T> {
private static final AnnotationLiteral<Any> ANY =
new AnnotationLiteral<Any>() {
};
@Inject
private BeanManager beanManager;
private ExecutorService executorService;
public AsyncEvent() {
}
@PostConstruct
public void init() {
executorService = Executors.newFixedThreadPool(5);
}
@PreDestroy
public void shutdown() {
try {
executorService.shutdown();
final boolean terminated = executorService.awaitTermination(10, TimeUnit.SECONDS);
if (!terminated) {
throw new RuntimeException("awaitTermination timeout");
}
} catch (final InterruptedException ie) {
throw new RuntimeException(ie);
}
}
public void fire(final T event) {
fire(event, ANY);
}
public void fire(final T event, final Annotation... qualifiers) {
final Set<ObserverMethod<? super T>> observers = beanManager.resolveObserverMethods(event, qualifiers);
final Set<Callable<Void>> tasks = createCallablesForObservers(event, observers);
invokeAll(tasks);
}
private Set<Callable<Void>> createCallablesForObservers(final T event,
final Set<ObserverMethod<? super T>> observers) {
final Set<Callable<Void>> tasks = new HashSet<Callable<Void>>();
for (final ObserverMethod<? super T> observer: observers) {
final Callable<Void> callable = createCallable(event, observer);
tasks.add(callable);
}
return tasks;
}
private Callable<Void> createCallable(final T event,
final ObserverMethod<? super T> observer) {
final Callable<Void> callable = new Callable<Void>() {
@Override
public Void call() {
observer.notify(event);
return null;
}
};
return callable;
}
private void invokeAll(final Set<Callable<Void>> tasks) {
try {
executorService.invokeAll(tasks);
} catch (final InterruptedException e) {
throw new RuntimeException(e);
}
}
}
用法:
private static final AnnotationLiteral<Updated> UPDATED = new AnnotationLiteral<Updated>() {
};
@Inject
private AsyncEvent<Document> event;
public void run() {
System.out.println("Fire event");
final Document document = new Document("test event");
event.fire(document);
event.fire(document, UPDATED);
...
}