I am upgrading old Java EE application to Spring based solution. In the old applications there were custom annotations to create proxy inject proxy bean and intercept the method invocation [Interceptor classes implements MethodInterceptor
) or (implements InvocationHandler
), which used to perform some before and after execution stuff.
We have replaced those custom annotations with Spring marker interfaces like @Service, @Repository etc. and we are able to use @Autowire the bean instances. Now my question is how to intercept these autowired beans to perform per and post execution activities. One solution I can think is to use Spring AOP and use @Around pointcut. Just want to know is there any other and better alternative which can be used like
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
BeanFactoryPostProcessor
or BeanPostProcessor
.InstantiationAwareBeanPostProcessor
I have used this alternative instead of AOP. I have used Spring's bean pre & post processor call back. Below is the code snippet.
Application Context Provider, to get Spring beans statically
package com.appname.config;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* @author dpoddar
*
*/
@Component("applicationContextProvider")
public class ApplicationContextProvider implements ApplicationContextAware{
private static ApplicationContext ctx = null;
public static ApplicationContext getApplicationContext() {
return ctx;
}
@Override
@Autowired
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
ApplicationContextProvider.ctx = ctx;
}
/**
* Returns the Spring managed bean instance of the given class type if it exists.
* Returns null otherwise.
* @param beanClass
* @return
*/
public static <T extends Object> T getBean(Class<T> beanClass) {
return ctx.getBean(beanClass);
}
/**
* Returns the Spring managed bean instance of the given class type if it exists.
*
* @param <T>
* @param name
* @param beanClass
* @return
*/
public static <T extends Object> T getBean(String name,Class<T> beanClass) {
return ctx.getBean(name,beanClass);
}
}
Spring Bean Post Processor, InstantiationAwareBeanPostProcessor
adds before and after initialization call backs
package com.appname.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.SpringProxy;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import com.appname.core.ExecutionContext;
import com.appname.core.di.FacadeService;
import com.appname.interceptors.BusinesServiceInterceptor;
import com.appname.interceptors.FacadeServiceInterceptor;
import com.appname.interceptors.RepositoryInterceptor;
import net.sf.cglib.proxy.Enhancer;
/**
* @author dpoddar
*
*/
@Component
public class AppSpringBeanPostProcessor extends AutowiredAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
private static Logger logger = LoggerFactory.getLogger(AppSpringBeanPostProcessor.class);
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
Class<?> clazz = bean.getClass();
AutowireCapableBeanFactory factory = ApplicationContextProvider.getApplicationContext().getAutowireCapableBeanFactory();
if(clazz.isAnnotationPresent(FacadeService.class)) {
//This is to instatiate InvocationHandler classes
//return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new FacadeServiceInterceptor(bean));
FacadeServiceInterceptor interceptor = new FacadeServiceInterceptor();
Enhancer e = new Enhancer();
e.setSuperclass(clazz);
e.setInterfaces(new Class[]{SpringProxy.class}); /// Identification Spring-generated proxies
e.setCallback(interceptor);
Object o = e.create();
factory.autowireBean( o ); //Autowire Bean dependecies to the newly created object
return o;
}else if(clazz.isAnnotationPresent(Service.class)) {
BusinesServiceInterceptor interceptor = new BusinesServiceInterceptor();
Enhancer e = new Enhancer();
e.setSuperclass(clazz);
e.setInterfaces(new Class[]{SpringProxy.class});
e.setCallback(interceptor);
Object o = e.create();
factory.autowireBean( o );
return o;
}else if(clazz.isAnnotationPresent(Repository.class)) {
ExecutionContext.newInstance();
RepositoryInterceptor interceptor = new RepositoryInterceptor();
Enhancer e = new Enhancer();
e.setSuperclass(clazz);
e.setInterfaces(new Class[]{SpringProxy.class});
e.setCallback(interceptor);
return e.create();
}else {
return bean;
}
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}