Search code examples
springspring-aopspring-beanspring-aspects

Decorate or Intercept Spring @Autowired Bean


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

  1. extending org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
  2. Using BeanFactoryPostProcessor or BeanPostProcessor.
  3. Using InstantiationAwareBeanPostProcessor

Solution

  • 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;
        }
    }