5

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?

papiomytoglou
  • 53
  • 1
  • 4
  • I may be missing something, but why wouldn't you just add the `@Observes @Initialized` to `C` class to force `C` to start up. – John Ament Sep 23 '17 at 01:00
  • That's a good point, but ideally I would like the beans instantiation to respect the direction of the dependency chain. With your solution the C bean could end up being instantiated with no guarantee of the A and B beans having also been instantiated.. – papiomytoglou Sep 25 '17 at 07:37
  • That's tight coupling, which is one of the goals against DI. – John Ament Sep 25 '17 at 11:52

1 Answers1

4

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

Siliarus
  • 6,393
  • 1
  • 14
  • 30
  • 1
    Is there a reason to prefer the extension solution instead of the `@Observes @Initialized` one I quoted above? – papiomytoglou Sep 25 '17 at 11:39
  • 1
    Well, extension does not create any boilerplate on your beans. And it is one ultimate place to solve this instead of putting it to every bean where you might need this - this should add on to maintainability. Other than that I'd say there won't be any major difference. – Siliarus Sep 25 '17 at 12:06