Rahul
Rahul

Reputation: 870

@Controller class instantiated twice with Spring AOP

I am trying to use Spring AOP for profiling my Controllers, but as soon as I enable monitoringAdvisor in my servlet context xml my @Controller class constructor gets called twice with below mentioned stacks.

I assume it has something to do with CGLIB proxy which derives from by @Controller annotated class (PersonController in this case)

But if that's the case then isn't this against the Singleton concept of Spring (suppose I try to acquire a system wide resource in the singleton). Please let me know how can I avoid this problem when using CGLIB proxying.

I am not using any ContextLoaderListener in web.xml,

my-servlet.xml

<bean id="monitoringInterceptor" class="org.javasimon.spring.MonitoringInterceptor" />
<bean id="monitoringAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
    <property name="advice" ref="monitoringInterceptor" />
    <property name="pointcut">
        <bean class="org.javasimon.spring.MonitoredMeasuringPointcut" />
    </property>
</bean>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
</bean>
<context:component-scan base-package="org.mypackage" />

Java code

@Controller
public class PersonController {
PersonController()
    {

    }

    @Monitored // works well even when I remove this annotation
    @RequestMapping(value="/addPerson", method=RequestMethod.POST) 
    public String addPerson(HttpServletRequest request) {
    }
}

Call stack when the org.mypackage.PersonController (class annotated with @Controller) constructor hit first

PersonController.<init>() line: 48  
NativeConstructorAccessorImpl.newInstance0(Constructor, Object[]) line: not available [native method]   
NativeConstructorAccessorImpl.newInstance(Object[]) line: 57    
DelegatingConstructorAccessorImpl.newInstance(Object[]) line: 45    
Constructor<T>.newInstance(Object...) line: 526 
BeanUtils.instantiateClass(Constructor<T>, Object...) line: 148 
CglibSubclassingInstantiationStrategy(SimpleInstantiationStrategy).instantiate(RootBeanDefinition, String, BeanFactory) line: 87    
DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).instantiateBean(String, RootBeanDefinition) line: 1000   

Call stack when the breakpoint hits second time

PersonController$$EnhancerByCGLIB$$4ad0c197(PersonController).<init>() line: 48 
PersonController$$EnhancerByCGLIB$$4ad0c197.<init>() line: not available    
NativeConstructorAccessorImpl.newInstance0(Constructor, Object[]) line: not available [native method]   
NativeConstructorAccessorImpl.newInstance(Object[]) line: 57    
DelegatingConstructorAccessorImpl.newInstance(Object[]) line: 45    
Constructor<T>.newInstance(Object...) line: 526 
ReflectUtils.newInstance(Constructor, Object[]) line: 228   
ReflectUtils.newInstance(Class, Class[], Object[]) line: 220    
ReflectUtils.newInstance(Class) line: 216   
Enhancer.createUsingReflection(Class) line: 643 
Enhancer.firstInstance(Class) line: 538 
Enhancer(AbstractClassGenerator).create(Object) line: 225   
Enhancer.createHelper() line: 377   
Enhancer.create() line: 285 
CglibAopProxy.getProxy(ClassLoader) line: 205   

Upvotes: 1

Views: 1230

Answers (1)

Rahul
Rahul

Reputation: 870

Found the answer at http://nurkiewicz.blogspot.in/2011/10/spring-pitfalls-proxying.html following paragraph

"Instead of subclassing and instantiating subclassed bean Spring first creates the original bean and then creates a subclass which wraps the original one (somewhat Decorator pattern) in one of the post processors"

Thats why the constructor is getting called twice, But there is actually one bean only. I tried @PostConstruct and that got called just once, which clarified my all doubts. So essentially there is only one bean. the other one is just a proxy.

Upvotes: 1

Related Questions