Note that there are some explanatory texts on larger screens.

plurals
  1. POIs it possible to guarantee the order in which @PostConstruct methods are invoked?
    primarykey
    data
    text
    <p>I have a system which is using Spring for dependency injection. I use annotation-based autowiring. The beans are discovered by component scanning, i.e. my context XML contains this:</p> <pre class="lang-XML prettyprint-override"><code>&lt;context:component-scan base-package="org.example"/&gt; </code></pre> <p>I have created a noddy example below to illustrate my problem.</p> <p>There is a <code>Zoo</code> which is a container for <code>Animal</code> objects. The developer of <code>Zoo</code> does not know which <code>Animal</code> objects will be contained whilst he is developing <code>Zoo</code>; the set of concrete <code>Animal</code> objects instantiated by Spring is known at compile-time, but there are various build profiles resulting in various sets of <code>Animal</code>s, and the code for <code>Zoo</code> must not change under these circumstances.</p> <p>The purpose of <code>Zoo</code> is to allow other parts of the system (illustrated here as <code>ZooPatron</code>) to access the set of <code>Animal</code> objects at runtime, without needing to depend explicitly on certain <code>Animal</code>s.</p> <p>Actually, the concrete <code>Animal</code> classes will all be contributed by various Maven artifacts. I want to be able to assemble a distribution of my project by simply depending on the various artifacts containing these concrete <code>Animal</code>s, and have everything autowire correctly at compile-time.</p> <p>I have attempted to solve this problem (unsuccessfully) by having the individual <code>Animal</code>s depend upon the <code>Zoo</code>, in order that they can call a registration method on the <code>Zoo</code> during <code>@PostConstruct</code>. This avoids the <code>Zoo</code> depending explicitly on an explicit list of <code>Animal</code>s.</p> <p>The problem with this approach is that the customers of <code>Zoo</code> wish to interact with it <strong>only when all the <code>Animal</code>s have registered</strong>. There is a finite set of <code>Animal</code>s which is known at compile-time, and the registration all happens during the Spring wiring phase of my lifecycle, so a subscription model should be unneccesary (i.e. I don't wish to add <code>Animal</code>s to the <code>Zoo</code> at runtime).</p> <p>Unfortunately, all the customers of <code>Zoo</code> simply depend upon <code>Zoo</code>. This is exactly the same relationship which the <code>Animal</code>s have with <code>Zoo</code>. Therefore, the <code>@PostConstruct</code> methods of the <code>Animal</code>s and <code>ZooPatron</code> are called in an arbitrary sequence. This is illustrated with the example code below - at the time <code>@PostConstruct</code> is invoked on <code>ZooPatron</code>, no <code>Animal</code>s have registered, it is some milliseconds later when they all register.</p> <p>So there are two types of dependency here, which I am struggling to express in Spring. The customers of <code>Zoo</code> only want to use it once all the <code>Animal</code>s are in it. (perhaps "Ark" would have been a better example...)</p> <p>My question is basically: what is the best way to solve this problem?</p> <pre class="lang-java prettyprint-override"><code>@Component public class Zoo { private Set&lt;Animal&gt; animals = new HashSet&lt;Animal&gt;(); public void register(Animal animal) { animals.add(animal); } public Collection&lt;Animal&gt; getAnimals() { return animals; } } public abstract class Animal { @Autowired private Zoo zoo; @SuppressWarnings("unused") @PostConstruct private void init() { zoo.register(this); } @Component public static class Giraffe extends Animal { } @Component public static class Monkey extends Animal { } @Component public static class Lion extends Animal { } @Component public static class Tiger extends Animal { } } public class ZooPatron { public ZooPatron(Zoo zoo) { System.out.println("There are " + zoo.getAnimals().size() + " different animals."); } } @Component public class Test { @Autowired private Zoo zoo; @SuppressWarnings("unused") @PostConstruct private void init() { new Thread(new Runnable() { private static final int ITERATIONS = 10; private static final int DELAY = 5; @Override public void run() { for (int i = 0; i&lt;ITERATIONS; i++) { new ZooPatron(zoo); try { Thread.sleep(DELAY); } catch (InterruptedException e) { // nop } } } }).start(); } } public class Main { public static void main(String... args) { new ClassPathXmlApplicationContext("/context.xml"); } } </code></pre> <p>Output:</p> <pre><code>There are 0 different animals. There are 3 different animals. There are 4 different animals. There are 4 different animals. ... etc </code></pre> <h1>Explanation of accepted solution</h1> <p>Basically the answer is: no, you cannot guarantee the order of <code>@PostConstruct</code> calls without either going "outside" Spring or modifying its behaviour.</p> <p>The real problem here was <em>not</em> that I wanted to sequence the <code>@PostConstruct</code> invocations, that was merely a <em>symptom</em> of the dependencies being expressed incorrectly.</p> <p>If the consumers of <code>Zoo</code> depend upon him, and <code>Zoo</code> in turn depends upon <code>Animal</code>s, everything works correctly. My mistake was that I didn't want <code>Zoo</code> to depend upon an explicit list of <code>Animal</code> subclasses, and therefore introduced this registration method. As pointed out in the answers, mixing a self-registration mechanism with dependency injection will never work without unnecessary complexity.</p> <p>The answer is to declare that <code>Zoo</code> is dependent upon a <em>collection</em> of <code>Animal</code>s, then allow Spring to populate the collection through auto-wiring.</p> <p>Thus, there is no hard list of collection members, they are discovered by Spring, but the dependencies are correctly expressed and therefore the <code>@PostConstruct</code> methods happen in the sequence I want.</p> <p>Thanks for the excellent answers.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload