Using Spring & Java Annotations to Inject Reusable Capabilities – Part II

August 15, 2012

In an earlier post, I wrote about using the Spring BeanPostProcessor to inject cross-cutting concerns. That can easily be extended to inject a proxy more transparently across all beans in the application context. The key is to use the BeanFactoryPostProcessor in conjunction with the post-processor.  Define a custom class that implements the factory post processor like the following:

package learn;

public class ExampleBeanPostProcessorFactory implements BeanPostProcessorFactory {

	@Override
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {

		beanFactory.addBeanPostProcessor(new ExampleBeanPostProcessor());
	}

}

Define this bean alongside the the rest of your declarations. For instance:

<bean class="learn.ExampleBeanPostProcessorFactory" />

The post processor can be injected with required dependencies per your needs – this could be a bean that wraps all annotated objects with instrumentation via the Java Dynamic proxy. The key benefit is that the beans in your context can all be transparently examined and proxied – how to decide which beans need to be proxied can be determined by annotations or beans implementing certain interfaces or custom decision logic using a class.


Using Spring & Java Annotations to Inject Reusable Capabilities

January 19, 2011

Want to inject reusable functionality but don’t want your consumers to go through complex set of steps to implement? Using annotations, a reusable capability can be injected at runtime – your clients can take advantage of common, reusable capabilities while avoiding the need to implement boiler plate code. Consumers can also be allowed to declaratively specify/alter the reusable asset’s behavior using this approach.

Here is an example using Java and Spring framework to print a test message before invoking the target method.

Declare an annotation – a simple annotation with a boolean flag:

package example.annotation;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Loggable {
	 boolean log() default true;
}

Create a dynamic proxy – all this does is examines the boolean log method from the annotation and prints a test message:

package example.proxy;

import java.lang.reflect.*;
import example.annotation.Loggable;

public class ExampleDynamicProxy implements InvocationHandler {

	private Loggable loggable = null;
	private final Object targetObject;

	public ExampleDynamicProxy(Object target, Loggable loggable) {
		targetObject = target;
		this.loggable = loggable;
	}

	public Object invoke(Object target, Method method, Object[] arguments) throws Throwable {

		Object result = null;
		try {
			if (loggable.log()) {
			  System.out.println("message before invoking method...");
			}
			result = method.invoke(targetObject, arguments);
		} catch (InvocationTargetException ite) {
			throw ite.getTargetException();
		}
		return result;
	}
}

Create a spring bean post-processor – checks for annotation and creates a proxied version of bean:

package example.postprocessor;

import java.lang.reflect.Proxy;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

import example.annotation.Loggable;
import example.proxy.ExampleDynamicProxy;

public class ExampleBeanPostProcessor implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object arg0, String arg1)
			throws BeansException {
		return arg0;
	}

	@Override
	public Object postProcessAfterInitialization(Object arg0, String arg1)
			throws BeansException {

		Class clz = arg0.getClass();
		Class[] interfaces = clz.getInterfaces();

		if (interfaces != null && interfaces.length == 1
                        && _interfaces[0].isAnnotationPresent(Loggable.class)) {

			Class _interface = interfaces[0];
			ClassLoader cl = arg0.getClass().getClassLoader();
			Loggable loggable = (Loggable)_interface.getAnnotation(Loggable.class);
			Object proxy= Proxy.newProxyInstance(cl, new Class[] {_interface}, new ExampleDynamicProxy(arg0,loggable));

                        return proxy;
		}
		return arg0;
	}
}

Annotate an example interface as Loggable – this model can be used to inject lot of other reusable capabilities (error handling, notifications to JMS destinations, or even perform data transformations):

package example.bean;

import example.annotation.Loggable;

@Loggable
public interface Example {
	public String getGreeting();
}

Finally, each consuming interface will have an implementation and has to be defined as a bean along with the post-processor during spring initialization. This is a trivial example but was meant to illustrate the injection of reusable behavior via java annotations.


Using Spring Interceptors to Reuse Functionality

August 29, 2010

Spring MVC interceptors (learn more about interceptor design pattern here) can be used to plug in functionality that needs to be executed as part of handling a request. These interceptors can be an ideal place to reuse functionality that is applicable for non-web application related scenarios. Interceptors can be used to execute horizontal, cross cutting concerns – e.g. security, metrics, logging, etc. If you have an existing component that was developed for a command-line application or a JMS event handler and need to reuse it in a web app, an interceptor would be an ideal choice.

Here is an example implementation for a a Spring Interceptor extending the HandlerInterceptorAdapter:

package com.yourapp.learn;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class LoginInterceptor extends HandlerInterceptorAdapter {

 @Override
 public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
 Object handler) throws Exception {

 Boolean userAuthenticated = (Boolean)request.getSession().getAttribute("userAuthenticated");

 if (userAuthenticated) {
    return true;
 } else {
    return false;
 }

 }
}

This interceptor simply checks to see if the user is authenticated by looking for a session attribute. If the result is true, the request is processed further.
Here is an example bean definition fragment for utilizing the above:

<bean id="testInterceptor" />

<bean id="testSimpleUrlHandlerMapping"
 class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

<property name="interceptors">
 <list>
 <ref bean="testInterceptor"/>
 </list>
</property>

 <property name="mappings">
 <props>
 <prop key="/test">someController</prop>
 </props>
 </property>
</bean>

The actual logic can be in another component that is leveraged in the interceptor. The component itself could be reused across several apps. If such a component isn’t available, you can refactor existing logic to carve out the common functionality.


%d bloggers like this: