Referencing a Prototype from a Singleton in Spring:
Sometimes in Spring, you need to create a one-time use instance that has state (a.k.a a prototype bean) from a Singleton object. Essentially, one would need to access a prototype for a number of cases, namely those where the Gang of Four Abstract Factory can be applied :
You have an object that requires complex construction
You have many potential implementations of an interface, and generic logic that applies to all of those implementations.
Spring's documentation for prototype scope and method injection lets you know that you can accomplish that goal in the following manner:
where your commandManager looks something like:
package fiona.apple; // no more Spring imports! `public abstract class CommandManager { public Object process(Object commandState) { // grab a new instance of the appropriate Command interface Command command = createCommand(); // set the state on the (hopefully brand new) Command instance command.setState(commandState); return command.execute(); } // okay... but where is the implementation of this method? protected abstract Command createCommand(); }
You have a generic business object/singleton (CommandManager) that need to create an implementation of an interface with state to perform some task.
I personally found it useful for a couple of scenario in a large scale website projects. Overall, this approach served me well when I needed it, and was pretty painless.
Constructive Criticism
While the "lookup-method" trick is definitely useful, it definitely doesn't feel right. Bob Lee criticised Spring for having to put method names in XML (although I can't find a reference to the specific entry in which he does it). I don't know if the criticism was meant for this specific instance, but the criticism definite applies. This definitely feels like you're coding in XML. Programming in XML isn't pretty. The XML configuration in Spring is getting the more and more complex, although for now, it doesn't get to complicated.
This coding through XML isn't purely a "feel" issue. What happens if you change the method name? Why should you have to wait until runtime to catch typos?
Spring 2.5 theoretical @LookupMethod
I don't think that the new Spring annotations solve the -> problem, but I assume that it could. Here's how it could look:
package fiona.apple; // no more Spring imports... except for spring annotations @Component public abstract class CommandManager { public Object process(Object commandState) { // grab a new instance of the appropriate Command interface Command command = createCommand(); // set the state on the (hopefully brand new) Command instance command.setState(commandState); return command.execute(); } @LookupMethod(beanName="command") protected abstract Command createCommand(); }
This has a lot of advantages: it's very terse and shows you all about how a class is used right along with the implementation of the class. The disadvantage here, is that you're adding dependencies on Spring via the annotations. Also, you can't configure different instances of the "Singleton" with different implementations of the prototype... (I'm not sure what to call the multi-Singleton... Multiton?)
Spring JavaConfig's approach
I've been thinking about and even working on Spring JavaConfig (SJC) for a while. Take a look at this SJC bugthat talks about lookup methods. The way you'd implement "lookup methods" in a java oriented environment is quite straight forward. The bean stays the same:
package fiona.apple; // no more Spring imports! public abstract class CommandManager { public Object process(Object commandState) { // grab a new instance of the appropriate Command interface Command command = createCommand(); // set the state on the (hopefully brand new) Command instance command.setState(commandState); return command.execute(); } // okay... but where is the implementation of this method? protected abstract Command createCommand(); }
The configuration code is surprisingly simple:
package fiona.apple; // a whole bunch of spring and business object imports @Configuration public class CommandManagerConfiguration { @Bean public CommandManager commandManager(){ return new CommandManager(){ protected Command createCommand(){ /* you can add your dependencies here, if you have any */ return new AsyncCommand(); } }; } }
A Java based configuration is, IMHO, a much more natural implementation than the XML approach. This is a surprisingly trivial implementation of a relatively complicated scenario.
The slickness here comes from writing simple Java code
SJC beyond prototypes
The prototype slickness lead me down a path that helped me shed the preconceived notions that came from XML-based development. I started thinking about where I could use java to make my application configuration process even better. Now, I definitely thought of some cool infrastructure stuff that I could add to Spring JavaConfig, but that's not the application configuration ingredients that I find most interesting.
The most interesting techniques a programmatic environment can add to application construction come from really simple day-to-day java code. For example, you can create conditional beans using a simple "if" statement. You can concatenate Lists and Maps. Those examples, plus other simple programming techniques that we've come to depend on as second nature, are now available. Spring doesn't dictate what I can do when constructing an application. You can now use Plain Old Java to configure your Plain Old Java Objects.
Some of the more esoteric techniques I thought of included 1) finding an easy hook that allows programmatic bean creation using Spring's underlying application configuration meta data objects, and 2) allowing users to hook in their own configuration Annotations.
Conclusions
I hope that this blog entry will be useful for two purposes:
Describe how and why Spring creates prototype objects within singleton beans
Give an idea about how Spring JavaConfig can help with
You'll see some fantastic things from Spring JavaConfig soon... In the mean time, there's definitely plenty of goodies that you can get out of traditional, and main-stream spring xml configuration and java annotations.
No comments:
Post a Comment