Cougar is able to notify listeners that it has started up. This is useful for services or components which should not start to interact with external entities until Cougar is up and running.
The notification happens once Cougar receives a Spring onApplicationEvent()
event. This means that Cougar’s
“start up” mechanism is intended for components which can’t or shouldn’t be started up as part of Spring’s context
initialisation. Note that Cougar itself doesn’t start accepting connections until all listeners have been notified.
The requirements are simply:
a component needs to be notified when Cougar has started up (typically it shouldn’t “start” until Cougar has started)
a component may need to be notified only after other components are notified (ie. it should be possible to specify dependencies)
it is desirable to be able to invoke an arbitrary method on a POJO instead of the POJO having to implement a listener
interface. (viz. Spring’s depends-on
bean attribute).
It is worth drawing a distinction between “initialising” and “starting” components. Spring describes the init-method
functionality as a way of doing a bit of work to set up the bean’s state, after all properties have been set by Spring. You
could see this as being different to how we often use the functionality to “start” a component (particularly components which
fire off their own threads, or start interacting with external components).
You should include a maven dependency on cougar-core-impl
(no, that’s not ideal…).
Say you have a bean named “myBean” with a method “startMe” that should be invoked after Cougar has started up. The wiring would be:
<bean parent="cougar.core.GateRegisterer">
<constructor-arg>
<bean parent="cougar.core.GateListener">
<property name="bean" ref="myBean"/>
<property name="method" value="startMe"/>
</bean>
</constructor-arg>
</bean>
Note that the above bean is anonymous (and that the parent bean is a prototype).
If you use Spring’s p-namespace (section 3.3.2.6.2 of the manual), this simplifies to:
<bean parent="cougar.core.GateRegisterer">
<constructor-arg>
<bean parent="cougar.core.GateListener" p:bean-ref="myBean" p:method="startMe"/>
</constructor-arg>
</bean>
If you wanted to register another bean which should only be started after myBean
, you would use a depends-on
tag, with the two declarations being:
<bean id="myBeanRegisterer" parent="cougar.core.GateRegisterer">
<constructor-arg>
<bean parent="cougar.core.GateListener" p:bean-ref="myBean" p:method="startMe"/>
</constructor-arg>
</bean>
...
<bean parent="cougar.core.GateRegisterer" depends-on="myBeanRegisterer">
<constructor-arg>
<bean parent="cougar.core.GateListener" p:bean-ref="yetAnotherBean" p:method="anInitMethod"/>
</constructor-arg>
</bean>
Notes: 1. yes, GateRegisterer is not a pretty name. Suggestions for improvements welcome. 2. GateRegisterer can take a list of Listeners.
The above examples make use of pre-defined abstract beans for registering listeners. This section shows what’s under the hood.
You register GateListener
instances with a CougarStartingGate
. The only CougarStartingGate
bean in Cougar’s
Spring context is cougar.core.RequestProcessor
. You could implement the GateListener
interface and you could
programmatically register yourself with the CougarStartingGate
, but the GateRegisterer
and GateListenerAdapter
classes allow you to keep things decoupled.
You could declare your own GateListener
and GateRegisterer
beans from scratch, but as with the example above,
it’s easier to use the abstract beans cougar.core.GateRegisterer
and cougar.core.GateListener
, which are
defined in config file conf/cougar-core-spring.xml
in project cougar-core-impl
. They take care of the basics
(specifying the starting gate, and marking the beans as prototypes to keep them from polluting the context).
The GateRegisterer
(com.betfair.cougar.core.api.GateRegisterer
) simply has a constructor with signature
public GateRegisterer(CougarStartingGate gate, GateListener... listeners) {
// validate and register listeners with gate
}
The class is stateless.
The GateListenerAdapter
is a convenience implementation of GateListener
, intended to mimic and provide the
decoupling benefits of Spring’s init-method
functionality. You specify two properties: “bean” - the object to start,
and “method” - the name of the method to be invoked. The given method is invoked on the given bean when the listener is called.
Using GateListenerAdapter
means your client code doesn’t need to implement the GateListener
interface, reducing
your component’s dependency on Cougar.