I have a Spring webapp running on Java 5. This is was my applicationContext.xml file:
<bean id="child1" class="foo.ChildOne" />
<bean id="child2" class="foo.ChildTwo" />
<bean id="main" class="foo.Main">
<property name="childrenList">
<list value-type="foo.IChildren">
<ref bean="child1" />
<ref bean="child2" />
</list>
</property>
</bean>
Both ChildOne
and ChildTwo
classes implement the IChildren
interface. And in my Main
class, I have defined a childrenList
which gets populated with child1
and child2
beans. Easy, right?
But in the future, there might be no child1
, and instead, we will maybe have a child81
based on another unknown class. And it still has to work without touching the current code or XML files, only through configuration. This child81
would be defined on its own applicationContext file (in a JAR), and we will list the bean names in a database field (child2,child81,etc
).
I guess that's not a good design pattern; most likely it's a terrible, horrible, painful, you-better-run-while-you-can design, which will haunt me in the years to come. But I didn't define it, and I can't change it, so please lets assume it's OK for the purpose of this question.
Instead of injecting the beans myself using the applicationContext.xml, I have to retrieve them somehow, in runtime. I can't use autowiring either, because I don't know what class the beans are, all I know is all of their classes implement IChildren
.
So I have made my main bean class ApplicationContextAware
and I have added this method:
public void loadChildren() {
if (childrenList == null) {
childrenList = new LinkedList<IChildren>();
for (String name : theListOfBeanNames) {
childrenList.add((IChildren) context.getBean(name));
}
}
}
It works alright; each bean is defined in its own applicationContext, and then I retrieve them by name. But... when do I call loadChildren()
? So far, I'm doing it in the first line of each one of my methods. Since there is a null-check, it will initialize the list only once. But surely, there must be an easier/cleaner/better way of doing this?
I don't think I can just use the init-method="loadChildren"
property in my applicationContext, because then it would fail if my main bean is being loaded before all the children have been... and I can't control the loading order. Or can I?
This is from my web.xml file:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/application-context/applicationContext-*.xml
,classpath*:WEB-INF/application-context/applicationContext-children.xml
</param-value>
</context-param>
(We use the "classpath* notation" to load every applicationContext-children.xml file from within the JARs). If I invert the order and place the children XML before the main ones, would it ensure they will be loaded in that specific order? No matter what version of what application server we use?
I've also seen a @PostConstruct
annotation which would be useful if I could add it to my loadChildren
method. But when would it be called then? I've read that it's after the injections have been done, but... only for the current bean, right? It doesn't ensure that all the other beans are already loaded?
Is there any other option?