2013-10-18 126 views
1

這裏是我的自定義註解AnnoLogExecTimeAOP類:爲什麼匿名類方法調用方法時不能執行aop?

@Target(ElementType.METHOD) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented 
public @interface AnnoLogExecTime { 

} 

@Aspect 
@Service 
public class AOP { 
    Logger logger = LoggerFactory.getLogger(AOP.class); 

    @Around("execution(@com.judking.general.aop.AnnoLogExecTime * *(..))") 
    public Object calExecTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable  { 
     MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature(); 
     Method method = signature.getMethod(); 

     long t1 = System.currentTimeMillis(); 
     Object obj = proceedingJoinPoint.proceed(); 
     long t2 = System.currentTimeMillis(); 

     logger.info("method `"+method.getName()+"` takes "+(t2-t1)+"ms"); 
     return obj; 
    } 
} 

而且測試用例如下:

@Service 
class A { 
    public void go() { 
    B b = new B() { //Anonymous class B 
     @Override 
     public void exec() { 
     aopMethod(); 
     } 
    }; 
    b.exec(); 
    } 

    @AnnoLogExecTime 
    public void aopMethod() { 
    System.out.println("aopMethod"); 
    } 
} 

@Service 
class B { 
    public void exec() { 
    System.out.println("exec"); 
    } 
} 

當我打電話a.aopMethod(),該AOP.calExecTime是迷上了a.aopMethod()

但如果我叫a.go(),這是使用匿名類B實例調用a.aopMethod(),那麼AOP.calExecTime迷上了a.aopMethod()

任何人都可以給我一個這種現象的解釋嗎?在匿名課堂上,請給我一種解決這個問題的方法。非常感謝!

回答

1

這不完全是因爲它是一個匿名的內部類。 您遇到的問題是AOP代理的限制。

當你有

A a = ...; // get proxy 

代理本身包裝在一個包裝實例的實際情況。當你通過調用

a.aopMethod(); 

與此包裝實例進行交互的代理攔截器攔截呼叫,並可以執行的建議。給你打電話

a.go() 

,如果有一個連接點

這將適用。相反,沒有什麼攔截調用,並調用go()經過攔截,並調用該方法的實際實例

actualA.go(); 

當您創建匿名內部類,並有

@Override 
public void exec() { 
    aopMethod(); 
} 

它含蓄地做

@Override 
public void exec() { 
    A.this.aopMethod(); 
} 

它繞過代理,因爲你在實際的實例上調用它,而不是包裝器。

您可能沒有使用Spring生成代理,但their documentation explains this pretty well.