1

我正在尝试使用 Spring AOP 来分析我的控制器,但是一旦我在我的 servlet 上下文 xml 中启用了 monitoringAdvisor,我的 @Controller 类构造函数就会被调用两次,并使用下面提到的堆栈。

我认为它与 CGLIB 代理有关,该代理源自 @Controller 注释类(在本例中为 PersonController)

但如果是这种情况,那么这是否违反了 Spring 的单例概念(假设我尝试在单例中获取系统范围的资源)。请让我知道在使用 CGLIB 代理时如何避免此问题。

我没有在 web.xml 中使用任何 ContextLoaderListener,

我的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 代码

@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) {
    }
}

当 org.mypackage.PersonController(用 @Controller 注释的类)构造函数首先命中时调用堆栈

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   

断点第二次命中时调用堆栈

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   
4

1 回答 1

1

在http://nurkiewicz.blogspot.in/2011/10/spring-pitfalls-proxying.html 以下段落中找到了答案

“而不是子类化和实例化子类化 bean,Spring 首先创建原始 bean,然后创建一个子类,该子类将原始 bean(有点装饰器模式)包装在一个后处理器中”

这就是构造函数被调用两次的原因,但实际上只有一个 bean。我尝试了@PostConstruct 并且只调用了一次,这澄清了我的所有疑问。所以本质上只有一个豆子。另一个只是代理。

于 2013-10-10T09:33:54.047 回答