Spring config for parameterised, non-static factory methods
I recently discovered a nice way of using beans defined in your spring config as factories in the definition of other beans.
Its great, for example, when you want a factory that has non-static factory methods, or that relies on a bunch of other dependencies, or you want to instrument beans via some service which is itself a bean (this is what I was doing when I made this discovery). Here's how it looks..
A factory class whose factory-method is non-static and requires parameters:
package com.sjl;
class Factory {
private DependencyA depA;
public Factory(DependencyA aDepA) {
depA = aDepA;
}
public ResultType newInstance(DependencyB aDepB) {
ResultType _result = ..; // use the deps to cook up result
return _result;
}
}
.. and a Spring XML config:
<bean id="depA" class="com.sjl.DependencyA"/>
<bean id="depB" class="com.sjl.DependencyB"/>
<bean id="factory" class="com.sjl.Factory">
<constructor-arg ref="depA"/>
</bean>
<bean id="result" class="com.sjl.ResultType"
factory-bean="factory" factory-method="newInstance">
<constructor-arg ref="depB"/>
</bean>
So what we have here is an instance of Factory
, created with a dependency (depA), on which we invoke a non-static method with arguments to create our ResultType
.
The bit that surprised me was the use of <constructor-arg>
elements to define the parameters to pass to the factory method.
Instrumentation
If you followed any of my recent posts you'll know that I've been playing with dynamic proxies to create services that automagically decorate objects with instrumented versions.
As an example, in this post I showed an InstumentationService
which adds timing around method invocations.
I wanted to instrument several (about 8 actually) of my beans via a service that adds health monitoring, where the healthiness of a service is measured as a ratio of successful method invocations to unsuccessful ones (that throw exceptions).
The interface for instrumenting objects for health-monitoring looks like this:
interface HealthServiceInstrumenter {
public <T> T instrument(T aT);
}
So what I needed from Spring is:
- to create the instance of my
HealthServiceInstrumenter
, - to create the instances of various different
T
to pass through theHealthServiceInstrumenter
, and - the tricky part - to get spring to create the instrumented bean of type
T
by passing the original bean through the instrumenter.
Here's what the spring wiring looks like for that:
<bean id="health-instrumenter" class="com.sjl.HealthInstrumentationService"/>
<bean id="uninstrumented-bean-A" class="com.sjl.BeanA"
autowire-candidate="false"/>
<bean id="bean-A" class="com.sjl.BeanA"
factory-bean="health-instrumenter"
factory-method="instrument">
<constructor-arg ref="uninstrumented-bean-A"/>
</bean>
<bean id="uninstrumented-bean-B" class="com.sjl.BeanB"
autowire-candidate="false"/>
<bean id="bean-B" class="com.sjl.BeanB"
factory-bean="health-instrumenter"
factory-method="instrument">
<constructor-arg ref="uninstrumented-bean-B"/>
</bean>
blog comments powered by Disqus