Jakarta CDI force bean construction/register legacy event listeners

56 Views Asked by At

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).

2

There are 2 best solutions below

2
Nikos Paraskevopoulos On BEST ANSWER

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.

0
Ebuzer Taha KANAT On