2012-04-27 13 views
5

Mam kilka metod, które rzuca wyjątek, i chcę użyć AspectJ wokół doradzić, aby obliczyć czas wykonania i jeśli wyjątek jest wyrzucony i zalogować się do dziennika błędów i kontynuować przepływ przez ponowne rzucenie wyjątku.Jak ponownie rzucić wyjątek w AspectJ wokół doradzić

Próbowałem osiągnąć to przez obserwowanie, ale zaćmienie mówi "Nieobsługiwany typ wyjątku".

Code-przeciwko któremu AspectJ jest używane: -

public interface Iface { 
    public void reload() throws TException; 

    public TUser getUserFromUserId(int userId, String serverId) throws ResumeNotFoundException, TException; 

    public TUser getUserFromUsername(String username, String serverId) throws ResumeNotFoundException, TException; 

    public TResume getPartialActiveProfileFromUserId(int userId, int sectionsBitField, String serverId) throws ResumeNotFoundException, UserNotFoundException; 

    public TResume getPartialActiveProfileFromUsername(String username, int sectionsBitField, String serverId) throws ResumeNotFoundException, UserNotFoundException, TException; 
} 

Kod AspectJ: -

public aspect AspectServerLog { 

public static final Logger ERR_LOG = LoggerFactory.getLogger("error"); 

Object around() : call (* com.abc.Iface.* (..)) { 
    Object ret; 
    Throwable ex = null; 

    StopWatch watch = new Slf4JStopWatch(); 

    try { 
    ret = proceed(); 
    }catch (UserNotFoundException e) { 
    ex = e ; 
    throw e ; 
    } catch (ResumeNotFoundException e) { 
    ex = e ; 
    throw e ; 
    } catch (Throwable e) { 
    ex = e ; 
    throw new RuntimeException(e); 
    }finally{ 

    watch.stop(thisJoinPoint.toShortString()); 

    if(ex!=null){ 
     StringBuilder mesg = new StringBuilder("Exception in "); 
     mesg.append(thisJoinPoint.toShortString()).append('('); 
     for(Object o : thisJoinPoint.getArgs()) { 
     mesg.append(o).append(','); 
     } 
     mesg.append(')'); 

     ERR_LOG.error(mesg.toString(), ex); 
     numEx++; 
    } 

    } 
return ret; 
} 
} 

Proszę o pomoc, dlaczego ten AspectJ nie działa.

Odpowiedz

10

można uniknąć wyjątków i po prostu użyć bloku try/finally bez haczyka. A jeśli naprawdę potrzebne do logowania wyjątek można użyć po wrzuceniu porady, na przykład:

public aspect AspectServerLog { 

    public static final Logger ERR_LOG = LoggerFactory.getLogger("error"); 

    Object around() : call (* com.abc.Iface.* (..)) { 

     StopWatch watch = new Slf4JStopWatch(); 

     try { 
      return proceed(); 
     } finally { 
      watch.stop(thisJoinPoint.toShortString()); 
     } 
    } 

    after() throwing (Exception ex) : call (* com.abc.Iface.* (..)) { 
     StringBuilder mesg = new StringBuilder("Exception in "); 
     mesg.append(thisJoinPoint.toShortString()).append('('); 
     for (Object o : thisJoinPoint.getArgs()) { 
      mesg.append(o).append(','); 
     } 
     mesg.append(')'); 

     ERR_LOG.error(mesg.toString(), ex); 
    } 

} 
+0

dzięki, to jest świetne proste rozwiązanie. –

6

Obawiam się, że nie można pisać porad, aby zgłaszać wyjątki, które nie są zadeklarowane jako wyrzucone w dopasowanym punkcie łączenia. Per: http://www.eclipse.org/aspectj/doc/released/progguide/semantics-advice.html: "Zgłoszenie porady musi zawierać klauzulę throws z listą sprawdzonych wyjątków, którą może rzucić ciało. Ta lista sprawdzanych wyjątków musi być zgodna z każdym punktem sprzężenia docelowego porady lub błąd jest sygnalizowany przez kompilator."

Nastąpiło dyskusji na liście dyskusyjnej AspectJ o poprawę tej sytuacji - zobacz wątki tak: http://dev.eclipse.org/mhonarc/lists/aspectj-dev/msg01412.html

ale w zasadzie to, co trzeba zrobić, to inna rada dla każdego wariantu zgłoszenia wyjątku. Na przykład:

Object around() throws ResumeServiceException, ResumeNotFoundException, TException: 
    call (* Iface.* (..) throws ResumeServiceException, ResumeNotFoundException, TException) { 

które doradzi wszędzie, że ma te 3 wyjątki.

1

Tam jest „brzydka” obejście - Znalazłem je w Spring4 AbstractTransactionAspect

Object around(...): ... { 
    try { 
     return proceed(...); 
    } 
    catch (RuntimeException ex) { 
     throw ex; 
    } 
    catch (Error err) { 
     throw err; 
    } 
    catch (Throwable thr) { 
     Rethrower.rethrow(thr); 
     throw new IllegalStateException("Should never get here", thr); 
    } 
} 

/** 
* Ugly but safe workaround: We need to be able to propagate checked exceptions, 
* despite AspectJ around advice supporting specifically declared exceptions only. 
*/ 
private static class Rethrower { 

    public static void rethrow(final Throwable exception) { 
     class CheckedExceptionRethrower<T extends Throwable> { 
      @SuppressWarnings("unchecked") 
      private void rethrow(Throwable exception) throws T { 
       throw (T) exception; 
      } 
     } 
     new CheckedExceptionRethrower<RuntimeException>().rethrow(exception); 
    } 
} 
Powiązane problemy