我有一個使用Spring進行依賴注入的系統。我使用基於註釋的自動裝配。是否可以保證@PostConstruct方法被調用的順序?
<context:component-scan base-package="org.example"/>
我創建低於諾迪的例子來說明我的問題:將豆由組件掃描,即我的上下文XML包含此發現。
有一個Zoo
其是用於Animal
對象的容器。 Zoo
的開發人員不知道在開發Zoo
時將包含哪些對象;由Spring實例化的具體對象Animal
在編譯時是已知的,但是存在各種構建配置文件,導致各種各樣的Animal
s集合,並且Zoo
的代碼在這些情況下不得改變。
的Zoo
的目的是允許系統(這裏示出爲ZooPatron
)的其他部分訪問組在運行時Animal
的對象,而不需要對某些Animal
小號明確依賴。
實際上,具體的Animal
類將全部由各種Maven工件提供。我希望能夠通過簡單地取決於包含這些具體Animal
的各種工件來組裝我的項目的分佈,並且在編譯時自動裝配所有東西。
我已經嘗試通過具有單個Animal
小號取決於Zoo
,爲了使它們能在@PostConstruct
呼籲Zoo
註冊方法來解決這個問題(失敗)。這避免了Zoo
明確取決於明確的Animal
列表。
這種方法的問題是,Zoo
客戶希望與它交互只有當所有的Animal
■找註冊。有一個編譯時已知的有限的Animal
s,並且註冊全部發生在我生命週期的Spring配線階段,所以訂閱模型應該是不必要的(即,我不希望將Animal
添加到運行時爲Zoo
)。
很抱歉,所有Zoo
的顧客只需依據Zoo
。這與Animal
s與Zoo
的關係完全一樣。因此,以任意順序調用Animal
和ZooPatron
的@PostConstruct
方法。下面的示例代碼說明了這一點 - 在上調用@PostConstruct
時,沒有Animal
已經註冊,它們都在幾毫秒後註冊。
所以這裏有兩種類型的依賴關係,我在春天很難表達。 Zoo
的客戶只有在所有Animal
都在其中時才使用它。 (也許「方舟」本來就是一個更好的例子......)
我的問題基本上是:什麼是解決這個問題的最好方法?
@Component
public class Zoo {
private Set<Animal> animals = new HashSet<Animal>();
public void register(Animal animal) {
animals.add(animal);
}
public Collection<Animal> 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<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");
}
}
輸出:
There are 0 different animals.
There are 3 different animals.
There are 4 different animals.
There are 4 different animals.
... etc
接受的解決方案的說明
基本上答案是:不,你不能保證@PostConstruct
調用的順序沒有任何正在進行的「外部」 Spring或修改其行爲。
這裏真正的問題是不,我想測序@PostConstruct
調用,這僅僅是一個症狀的依賴關係被表達不正確。
如果Zoo
消費者依賴於他,Zoo
又取決於Animal
S,一切正常。我的錯誤是我不希望Zoo
依賴於Animal
子類的明確列表,因此引入了此註冊方法。正如答案中指出的那樣,將自注冊機制與依賴注入混合在一起將不會有不必要的複雜性。
答案是聲明Zoo
是依賴於Animal
的集合S,然後讓春天來填充通過自動裝配的集合。
因此,集合成員的無硬名單,它們被發現的春天,但依賴關係正確表達,因此@PostConstruct
方法我想要的順序發生。
感謝您的優秀答案。
好吧,我只檢查速度非常快......但我認爲長頸鹿,猴子,獅子和tiget也應該有@PostConstuct。爲什麼靜態? – Cygnusx1
那些具體的動物不需要PostConstruct,它們的抽象父類的PostConstruct方法被Spring正確調用。 –