Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clean solution for eager CDI bean instantiation

Tags:

Imagine the following simplified DI model:

@ApplicationScoped
public class A {

    private B b;

    @Inject
    public A(B b) {
        this.B = b;
    }

}

@ApplicationScoped
public class B {

    private C c;

    @Inject
    public B(C c) {
        this.C = c;
    }

}

@ApplicationScoped
public class C {

    @PostConstruct
    public void start() {
        // processing that should begin on startup
    }

}

Suppose I want C#start to be called on deployment completion. The pattern that is generally suggested online is the one presented here but that solution: 1) adds too much boilerplate, 2) adds a new text file for the extension, 3) resorts to the cheat of using toString solely to trigger the B proxy to instantiate the actual B bean underneath which will in turn trigger the C proxy etc.

Since CDI 1.1, adding the following method to A is also a solution:

public void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
   B.toString();
}

This solves the first two problems described above but I still need to call a dummy method on B so that the instantiation/injection chain is triggered and ends up calling the @PostConstruct annotated method of C.

Am I missing a cleaner solution to this problem? Does CDI 2.0 address this?

like image 801
papiomytoglou Avatar asked Sep 22 '17 09:09

papiomytoglou


1 Answers

There is no option you could select for eager initialization, you have to choose some "workaround". CDI does not define whether bean init should be lazy or eager and since lazy makes more sense most of the time, Weld went that way.

Your best bet is something similar to what the article you mentioned suggested. E.g. set up an extension, cherry pick the beans you want to have eagerly initialized and initialize them plus call a (harmless) method on them.

Obviously, this will only make sense for few beans in your deployment (app scoped ones at most I think) so there won't be much, if any, overhead. There is some extra boilerplate but it's not like you have to write that many lines to make this work.

To make it nicer, you can have all your beans implement a dummy interface with default ping() method and call that method from the extension - just so that you avoid calling toString().

like image 191
Siliarus Avatar answered Oct 11 '22 13:10

Siliarus