I have a new Jakarta EE (Qurakus) application and some old code which has methods to register event listeners. I have made a wrapper for the event registry. Now I need some way to efficiently register a lot of event listeners. It looks something like this:
@ApplicationScoped
public class EventRegistry {
private Set<Listener<?>> listeners = Collections.synchronizedSet(new HashSet<>());
public void register(Listener l) {
}
public void unregister(Listener l) {
}
}
@ApplicationScoped
public class Listener1 implements Listener<MyEvent> {
@Override
public void onEvent(MyEvent e) {
}
}
So basically I need a way for the listeners to register. I thought about using a Jakarta EE event which I trigger in PostConstruct of the registry and listen to it in each listener which then registers itself. Is this a save way to do it? Or will the listener bean be destructed if not used through an Inject? Also is there generally a better way to execute an operation for specific beans (I have all the listeners in a single package).
A simple way to do exactly what you want would be the following:
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Instance;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@ApplicationScoped
public class EventRegistry {
private final Set<Listener<?>> listeners = Collections.synchronizedSet(new HashSet<>());
@Inject
void init(Instance<Listener<?>> listenerInstance) {
// check out the comments; for Quarkus you can inject all listeners as:
// @Inject @All List<Listener<?>> listeners
listenerInstance.forEach(listeners::add);
}
public void register(Listener l) { // maybe not even needed anymore
listeners.add(l);
}
}
You can ask CDI to do method injection; you can also ask it for an Instance
of a type (in this case your Listener
) and through the Instance
retrieve all implementations, as shown above. Methods annotated with @Inject
get called when injection happens on the instance and before any @PostConstruct
methods. You could do property injection (i.e. @Inject private Instance<Listener<?>> listenerInstance
), but you only need this object during the initialization of the EventRegistry
. There is no reason to keep it around in a property for any longer.
Since you are in CDI and CDI supports the observer pattern you could consider changing your implementation to use that facility, as suggested in another answer.