Thursday, May 19, 2011

Proton Changes

It turns out the old mechanism for injecting prototypes in proton collided with Spring's AOP infrastructure to produce some truly nasty results. Trying to do field injection on cglib-generated proxies turns out to be... truly impossible. Like, really impossible. The Lord Himself couldn't do it.

So.

Going back to the drawing board I tried to figure out another solution to my prototype-injection problem. After googling around a bit I came across this very interesting blog entry about using Spring lookup-methods to generate prototypes. Very interesting.

After thinking about it a little bit I was a bit put off by the use of abstract methods in this case. This seemed to be very intrusive to me; it would make such classes difficult to test and it would change the fundamental "meaning" of a class (abstract classes are meant to be subclassed) just to fulfill this one "implementation detail" requirement. It also occurred to me that this behavior was virtually a perfect use-case for AOP. So after playing around a bit I came upon something like:

@PrototypeGenerator
public Foo createFoo(String constructorParam) {
return new Foo(constructorParam);
}

The idea here was you simply create and implement such 'prototype factory' methods and tag them with a @PrototypeGenerator annotation. At runtime, in Spring, such method calls would be intercepted by a PrototypeGeneratorAdvice that would go to the Spring ApplicationContext and create these beans and also do constructor-arg injection.

Of course this fails miserably because when a (cglib-enhanced) methods calls methods on itself (through the this variable) these methods are not intercepted by the various AOP mechanisms without full-on bytecode weaving. Ugh. The way around this is to implement a XFactory class, a normal Spring bean that can be injected and annotated with the PrototypeGenerator annotations to your heart's content. Inject this into those beans that need to create prototypes and voila! you are good to go!

From a design perspective this is not so bad. The simple truth is that when a bean needs to construct a prototype this is an admission of a lack-of-knowledge (the best kind) ie the bean is saying 'I need to create an instance of Foo that has a well-known state but I don't have enough information to do so! I need a prototype I can just clone/new!'. So injecting a factory in this case makes sense and also ends up being very unobtrusive thanks to the magic of Spring AOP!

No comments:

Post a Comment