Showing posts with label spring. Show all posts
Showing posts with label spring. Show all posts

Wednesday, October 2, 2013

Spring: Force a bean to be the first to initialize

Spring provides the "depends-on" bean attribute to control bean initialization order.  Unfortunately, there are some rare cases where you really want to run some code before the application context initializes.  An example scenario might involve messing around with the thread class loader before something like "PropertiesPlaceholderConfigurer" has a chance to initialize.

There are a number of ways to go about this, but the easiest might be through implementing a PriorityOrdered BeanFactoryPostProcessor.  After all spring beans are defined, spring calls all BeanFactoryPostProcessor s defined in the application context.  Post processors that implement PriorityOrdered, and have the highest precedence are called first.

To execute some code before any other spring beans or processors have a chance to initialize, one can therefore use something like the following:
        
/**
 * An example spring pre-initializer.  Referncing this class as a bean in an 
 * application context will cause it to be the first executed PostProcessor 
 * after all beans in the application context are defined.
 */
public class PreInitializer implements BeanFactoryPostProcessor, PriorityOrdered {
 @Override
 public int getOrder() {
  return Ordered.HIGHEST_PRECEDENCE;
 }
 @Override
 public void postProcessBeanFactory(
   ConfigurableListableBeanFactory beanFactory) throws BeansException {
  /* put initialization code here */
 }
}

This is an easy hack to perform initialization tasks that might affect the application context before anything else - including property resolution has a chance to run.

Friday, September 9, 2011

First Project in Central Maven Repository - spring-event-router

I've started a few open source java projects built with maven before, but have always ended up using a private repository to host binaries.  One project of note was the CampusEAI portlet-archetype.  Though under a GPLv3 licence, the CampusEAI repository was not publicly accessible until very recently.  I am delighted that CampusEAI appears to have opened up their previously closed maven repository to the world.  The CampusEAI portlet-archetype is an exciting project that deserves a post of its own and is now publicly available at http://svn.campuseai.org/site/portlet-archetype/

Unfortunately, the CampusEAI repository has not been publicly accessible for almost a year after I left the company.  Noticing this, I have committed to publishing any future OSS Java work into the central maven repository.

I've been working a bit with Spring Framework ApplicationEvents at work and thought it would be neat to write a simple dispatch mechanism by which listeners could subscribe to specific types of events without tons of instanceof operations.  I saw a couple of posts on velocityreviews that contained snippets of code tackling similar issues.  There's even a google code proejct over at http://code.google.com/p/spring-custom-annotations/ that attempts to solve a similar problem with their "@EventListener" annotation.  That project appears to no longer be maintained and has some warnings against usage in production code.  In light of this, I decided to hack up some code myself and try out google code's new git source control as well as using Sonatype to publish my first artifacts into the Central Maven repository.

I put together a tiny library called "spring-event-router" hosted over at http://code.google.com/p/spring-event-router/ and followed the Sonatype OSS Maven Repository Usage Guide to try and publish my binaries to the Central Maven Repository.  Setting up a project with Sonatype was a (necessarily) manual process but it only took around 24h to get my first binaries into the repository.  The gist of the ordeal is creating a JIRA issue and having Sonatype review your project to validate some requirements before granting you the ability to stage and publish your artifact.  Once your artifact has been published, a secondary review is performed; upon completion any releases into the Sonatype repository are synced with Central on an hourly basis without further Sonatype oversight.

Though admittedly a very simplistic project, I was very happy with the ease of being able to use "mvn release:prepare; mvn release:perform" to publish artifacts into the central maven repository.  The binaries are available here and should resolve as valid dependencies for any maven project without the need of a custom section! 

Monday, March 29, 2010

My attempt at Spring MVC custom annotations

While working on a simple project using SpringMVC, I stumbled upon the need to access a request or session attribute directly from within a controller method. I needed to bypass the binder and just access a request attribute set by a filter. This is obviously easy enough to do:

@RequestMapping
public String view(WebRequest request){
...
request.getAttribute("someAttribute", WebRequest.SCOPE_REQUEST);
...
}

Given modern mocking frameworks like Mockito and spring's own test libraries, it's easy enough to mock a WebRequest or even an HttpServletRequest. But I am pedantic, so I decided to see if I could create my own @RequestAttribute annotation instead! Ideally, I figured I'd be able to create a new annotation representing new behaviour without touching any of the spring source code.

An initial cursory look over AnnotationMethodHandlerAdapter did not reveal any clean hooks, so I decided to go with an aspect.

First Approach - Aspects



At first, I tried creating a pointcut around HandlerMethodInvoker#resolveHandlerArguments. At this point I discussed my plan with coworker and friend Martin Snyman, who quickly pointed out that it might be simpler to write the pointcut to intercept @RequestMapping annotated controller classes instead.

Starting out, my original pointcut looked like this:

@Around("execution(@org.springframework.web.bind.annotation.RequestMapping * *(..))")

This worked well enough, but it created unncessary proxies. The pointcut picked up the execution of all methods annotated with @RequestMapping - or worse.

What I really needed was to pick up execution of all methods annotated with @RequestMapping that had at least one parameter annotated with my special annotation - "@RequestAttribute". This turned out to be difficult. I could not for the life of me figure out how to write a pointcut that picked up annotated parameters rather than matching annotations on the actual classes of passed parameters. After a couple of stabs during the weekend, I found a blog post that discussed the issue I was facing in some detail. With that, I was able to write the following pointcut:

@Around("execution(@org.springframework.web.bind.annotation.RequestMapping * *.*(..,@o.c.RequestAttribute (*),..))")

I wrote a supporting interface to allow my aspect to support any number of annotations:

public interface ArgumentModifyingAnnotationBehavior<T extends Annotation> {
public Object getArgumentValue(Object argumentValue, T annotation);
}

The actual aspect then looked something like this:

protected final Map<Class<Annotation>, ArgumentModifyingAnnotationBehavior<Annotation>> annotationRegistry = new ConcurrentHashMap<Class<Annotation>, ArgumentModifyingAnnotationBehavior<Annotation>>();
...
@Around("execution(@org.springframework.web.bind.annotation.RequestMapping * *.*(..,@o.c.RequestAttribute (*),..))")
private Object resolveHandlerArguments(ProceedingJoinPoint pjp)
throws Throwable {
MethodSignature sig = (MethodSignature) pjp.getSignature();
Annotation[][] annotations = sig.getMethod().getParameterAnnotations();
Object[] arguments = pjp.getArgs();
if (annotations != null) {
/* iterate arguments */
for (int argumentIndex = 0; argumentIndex < annotations.length; argumentIndex++) {
Annotation[] argumentAnnotations = annotations[argumentIndex];
if (argumentAnnotations != null) {
for (int annoationIndex = 0; annoationIndex < argumentAnnotations.length; annoationIndex++) {
Annotation argumentAnnotation = argumentAnnotations[annoationIndex];
ArgumentModifyingAnnotationBehavior behavior = annotationRegistry
.get(argumentAnnotation.annotationType());
if (behavior != null) {
arguments[argumentIndex] = behavior
.getArgumentValue(arguments[argumentIndex],
argumentAnnotation);
}
}
}
}
}
return pjp.proceed(arguments);
}

I was very proud of myself. Then disaster struck...

@RequestMapping
public String view(@RequestAttribute("stringAttribute") String stringAttribute){...

worked like a champ.

@RequestMapping
public String view(@RequestAttribute("objectAttribute") java.util.Map objectAttribute){...

however, grenaded. My annotation worked great with concrete types but blew up when it was used to annotate interfaces or abstract classes.

Second Approach - WebArgumentResolvers



Debugging revealed that HandlerMethodInvoker was attempting to resolve "objectAttribute" to a model attribute and actually attempted to instantiate java.util.Map.

Debugging also revealed the curious new WebArgumentResolver class. By this point, I've spent hours of my time writing and debugging my awesome aspect only to find that HandlerMethodInvoker actually *did* have a hook for allowing custom behaviour using a WebArgumentResolvers!

A little bit more digging revealed that one can actually register any number of WebArgumentResolvers with the AnnotationMethodHandlerAdapter, which would pass these on through to the HandlerMethodInvoker

After 8+ hours of screwing around with my Aspect, I found I could actually achieve what I needed to do without the creation of any proxies with this:

public class RequestAttributeCustomArgumentResolver implements WebArgumentResolver {
public static @interface RequestAttribute {
String value() default "";
}
public Object resolveArgument(MethodParameter methodParameter,
NativeWebRequest webRequest) throws Exception {
RequestAttribute annotation=methodParameter.getParameterAnnotation(RequestAttribute.class);
if(annotation!=null){
return webRequest.getAttribute(annotation.value(),WebRequest.SCOPE_REQUEST);
}else{
return UNRESOLVED;
}
}
}

and the following in the applciation context XML:

<bean id="handlerAdapter"
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="customArgumentResolvers">
<list>
<bean class="org.campuseai.spring.webmvc.annotation.RequestAttributeCustomArgumentResolver"/>
</list>
</property>
</bean>

Ouch. Googling "WebArgumentResolver" also resulted in this blog post which does something similar to what I attempted to do.