2012-06-08 80 views
16

我看到Guice和Spring使用AOP聯盟進行方法攔截,我一直在試圖弄清楚如何讓AOP聯盟攔截並處理某些異常,所以我不必保留在每個catch區塊內反覆寫入相同的代碼。AOP異常處理

但是在審查了這個遊戲之後,它看起來並不像AOP聯盟提供的攔截攔截方式,以便處理程序/攔截器可以做一些事情(記錄異常等),然後確定是否要繼續傳播異常或只是恢復回下一行以下引發異常行:

HerpDerp hd = null; 

if(hd == null) 
    throw new RuntimeException("Herpyl derp!"); 

Manny.pacquiao(); 

我正在尋找一個AOP的異常處理機制,攔截RuntimeException並使用業務邏輯來決定是否繼續傳播它或在Manny.pacquioa()呼叫中恢復。

  • 如果它僅僅是不可能做到這一點在Java中,請讓我知道
  • 不管其是否可能做到這一點在Java中,有沒有辦法攔截拋出的異常與AOP聯盟或我必須去別的地方嗎?如果我必須去其他地方,在哪裏? AspectJ的?

謝謝!

回答

30

您可以使用Spring AOP來捕獲異常,但我不知道它是否符合您對純Java框架的要求。

使用Spring,你可以寫一個簡單的AOP攔截器,就像這樣:

@Aspect 
public class ErrorInterceptor{ 
@AfterThrowing(pointcut = "execution(* com.mycompany.package..* (..))", throwing = "ex") 
public void errorInterceptor(WidgetException ex) { 
    if (logger.isDebugEnabled()) { 
     logger.debug("Error Message Interceptor started"); 
    } 

    // DO SOMETHING HERE WITH EX 
    logger.debug(ex.getCause().getMessage()); 


    if (logger.isDebugEnabled()) { 
     logger.debug("Error Message Interceptor finished."); 
    } 
} 
} 

,但也沒有辦法返回到調用方法或繼續對後續行處理。但是,如果你在這裏處理例外情況,除非你自己重新拋出它,否則它不會冒出連鎖。

1

「釣」用AspectJ捕獲的異常,您可以使用以下方面:

pointcut uncaughtExceptionScope() : 
    (execution(* com.mycompany.myrootpackage..Main.main(..)) 
    || execution(* java.util.concurrent.Callable+.call()) 
    || execution(* java.lang.Runnable+.run()) 
    )); 

after() throwing(Throwable t) : uncaughtExceptionScope() && !cflow(adviceexecution()) { 
    handleException(thisJoinPoint, t); 
} 

protected void handleException(JoinPoint jp, Throwable t) 
{ 
    // handle exception here 
} 

我不認爲這是可能的「返回」的執行點。

+0

謝謝@Wim - 是基於AOP像AOP這樣的異常處理是不可能的? – IAmYourFaja

+0

我不這麼認爲。如果你檢查[spring docs](http://static.springsource.org/spring/docs/3.1.1.RELEASE/spring-framework-reference/html/aop.html),它會顯示: '加入點:程序執行期間的一個點,例如執行方法或處理異常。在Spring AOP中,一個連接點總是表示一個方法的執行。[ –

+0

可能[ConstructorInterceptor](http://aopalliance.sourceforge.net/doc/org/aopalliance/intercept/ConstructorInterceptor.html)以某種方式被破解以攔截異常(因爲他們正在構建)? – IAmYourFaja

3

有一個原因,這不存在。這將需要重寫代碼的塊結構,就好像你在第一時間編寫try/catch塊一樣。這在我看來,可能會對可變範圍和其他事物造成嚴重破壞。您要求AOP將字節碼重寫爲類似下面的代碼,這是相當重寫的。

HerpDerp hd = null; 

try { 
    if(hd == null) 
     throw new RuntimeException("Herpyl derp!"); 
} catch(RuntimeException e) { 
    if (someConditionIsMet) { 
     throw e; 
    } 
} 

Manny.pacquiao(); 
1

@ 4herpsand7derpsago如果你想要做的是使用AOP來執行各種任務來處理它趕上拋出的異常,然後回來到異常拋出原來的代碼,我想你好想了解AOP的概念。

正如你指出你的代碼

HerpDerp hd = null; 

if(hd == null) 
throw new RuntimeException("Herpyl derp!"); 

Manny.pacquiao(); 

如果你想AOP趕上你RuntimeException,執行一些東西來處理它,回來Manny.pacquiao();,答案是你不能。 原因是因爲當AOP拋出並捕獲RuntimeException時,堆棧已經在您的AOP代碼中。你不能回來執行Many.pacquiao();。如果要繼續執行Many.pacquiao();的唯一方法是通過使用try-finally塊作爲跟隨

HerpDerp hd = null; 

try { 
    if(hd == null) 
     throw new RuntimeException("Herpyl derp!"); 
} finally { 
    Manny.pacquiao(); 
} 

只有這樣,你的Many.pacquiao()將得到執行,但在此之前你的AOP趕上RuntimeException