Spring AOP对嵌套方法不起作用

来源:互联网 发布:英文信件结尾知乎 编辑:程序博客网 时间:2024/06/08 17:06

Spring AOP有一个限制,它对嵌套方法调用不起作用。究其原因,是因为Spring aop是作用在spring beans上,而不是作用于实际的类的实例。举例来说:

比如我按如下方法配置了一个aspect,

<beanclass="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" /><bean id="positionAspect"class="com.MyPositionUpdateAspect"/>


在这个aspect里(使用aspectj的语法支持),我配置了我的pointcut,意思是对MyTradeProcessor的所有方法调用(正常返回的)进行拦截。

package com;@Aspectpublic class MyPositionUpdateAspect {@AfterReturning(value = "execution(* com.MyTradeProcessor.*(..))", returning = "retTrade")public void updatePosition(JoinPoint joinPoint, Object retTrade) throws Throwable {        // my business logic        }}

下面是MyTradeProcessor类的大致框架:

public class MyTradeProcessor {        public ITrade amend(ITrade inputTrade) throws TradeBookingException {            if (isAmendForTemp)                return newTrade(inputTrade);            }            // other logic        }public ITrade newTrade(ITrade inputTrade) throws TradeBookingException {            // newTrade logic        }}


问题就出在amend方法里,如果某个条件成立,它会嵌套调用newTrade方法,按理说aop的拦截会触发两次,但是实际上它只会触发一次,就是调用amend方法时。当然,如果你直接调用newTrade方法,该方法的拦截会调用。原因就是上面提到的,因为当你在amend方法里调用newTrade方法时,你调用的是this实例,而这个不是spring里面配置的bean对象。所以有一个比较变态的解决办法是在这个类里在配置一个叫做self的bean,调用这个bean的newTrade方法。


还有一种解决办法是利用aspectj weaving。大致的配置如下,详细的说明可以参考http://stackoverflow.com/questions/5780757/spring-aop-logging-and-nested-methods。

<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">    <aspectj>        <weaver options="-Xset:weaveJavaxPackages=true -verbose -showWeaveInfo -debug">            <include within="*"/>    </weaver>    <aspects>        <!-- weave in just this aspect -->        <aspect name="your.logger.impl.LoggingImpl"/>    </aspects>  </aspectj>
This implies weaving in all your files ('within=*', modify as you wish) with the aspect/s specified. On load time you should see verbose information on weaving of classes.
<context:load-time-weaver aspectj-weaving="autodetect"             weaver-class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>