-
'Weak' Dependencies
I currently have a observer type pattern which I need to represent in my spring XML configuration. Originally I did this like this:
Code:
<bean id="listener" scope="singleton"/>
<bean id="teller" lazy-init="false" scope="singleton">
<property name="listener" value="listener" />
</bean>
This meant that whenever I retrieved a (well, the) listener, there was already a teller attached to it (and already telling it things).
The problem is now that I want lots of tellers/listeners, so they cannot be singletons any more. I really need a configuration which says on the 'listener' bean that it has a 'weak' dependency on the 'teller' bean - i.e. instantiate it afterwards with the original 'listener' bean as the dependency.
Of course I could code the 'listener' to automatically lookup a 'teller' and attach itself to it, but of course I'd rather inject this.
Is this possible? Am I going about this the wrong way?
Thanks
_jpg_
-
Couldn't you just simply make both beans as 'prototype' and when retrieving a 'listener' you'll have a new Listener attached to a new Teller ?
-
I think you may be looking for something like this:
Code:
<bean id="teller" class="sandbox.Teller"/>
<bean id="listener" scope="prototype"
factory-bean="teller" factory-method="addListener" />
<bean id="observer1" class="sandbox.ObservantBean">
<property name="listener" ref="listener"/>
</bean>
<bean id="observer2" class="sandbox.ObservantBean">
<property name="listener" ref="listener"/>
</bean>
<bean id="observer3" class="sandbox.ObservantBean">
<property name="listener" ref="listener"/>
</bean>
Where teller has a factory method to generate listeners bound to it:
Code:
public class Teller {
private List listeners = new ArrayList();
public void tellAll(String s){
for( int i = 0; i < listeners.size(); i++ )
((Listener) listeners.get(i)).tellMe(s);
}
public synchronized Listener addListener(){
Listener listener = new Listener();
listener.setMyNum(listeners.size());
this.listeners.add(listener);
System.out.println("Number of Listeners: " + listeners.size());
return listener;
}
}
Then invoking the following
Code:
Teller teller = (Teller) ctx.getBean("teller");
teller.tellAll("Hello, World");
results in
Code:
Number of Listeners: 1
Number of Listeners: 2
Number of Listeners: 3
Listener 0: Hello, World
Listener 1: Hello, World
Listener 2: Hello, World
-
You can inject the listener into all your beans and then call the addListener method with an initialization callback method. A BeanPostProcessor however might be a cleaner solution.
http://www.springframework.org/docs/...itializingbean
http://www.springframework.org/docs/...-extension-bpp
-
Andrei,
I can't simply mark both as prototype because the listener has no direct dependency on the teller, so the teller will not be created.
jstehler,
I don't want to do this because (a) I have an arbitrary number of teller/listeners so can't put them in my xml file like this and (b) I don't want to hardcode the addListener method to create a specific implementation on a Listener.
---
Instead what I have decided to do is to create a DependentBeanFactoryFactory (or similar) which will provide beans which are actually dependencies of other beans. This means that it will create a 'teller' bean, then return it's 'listener', meaning that both will be scoped as prototypes and both will be created by a creation request for either. Does this sound like a reasonable solution? Are there any better ones?
_jpg_