web-dev-qa-db-fra.com

Gestion des exceptions AOP

Je vois que Guice et Spring utilisent AOP Alliance sous le capot pour les interceptions de méthode, et j'ai essayé de comprendre comment obtenir AOP Alliance pour intercepter et gérer certaines exceptions, donc je n'ai pas à continuer d'écrire le même code et à nouveau à l'intérieur de chaque bloc catch.

Mais après avoir examiné le jeu, il ne semble pas que l'AOP Alliance offre un moyen d'intercepter les Throwables lancés de telle manière que le gestionnaire/intercepteur puisse faire certaines choses (enregistrer l'exception, etc.), puis - déterminer s'il faut ou non propager l'exception plus loin ou simplement revenir à la ligne suivante après la ligne qui a levé l'exception:

HerpDerp hd = null;

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

Manny.pacquiao();

Je recherche un mécanisme de gestion des exceptions AOP qui intercepterait le RuntimeException et utiliserait la logique métier pour décider de continuer à le propager ou de récupérer à l'appel de Manny.pacquioa().

  • S'il n'est tout simplement pas possible de le faire en Java, faites-le moi savoir
  • Qu'il soit possible ou non de le faire en Java, existe-t-il un moyen d'intercepter l'exception levée avec AOP Alliance ou dois-je aller ailleurs. Et si je dois aller ailleurs, où? AspectJ?

Merci!

20
IAmYourFaja

Vous pouvez intercepter des exceptions avec Spring AOP, mais je ne sais pas si cela correspond à vos besoins pour un cadre Java Java pur.

Avec Spring, vous pouvez écrire un simple intercepteur AOP comme quelque chose comme:

@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.");
    }
}
}

mais il n'y a aucun moyen de revenir à la méthode appelante ou de poursuivre le traitement sur la ligne suivante. Cependant, si vous gérez l'exception ici, elle ne bouillonnera pas la chaîne à moins que vous ne la retourniez vous-même.

35
Eric B.

Il y a une raison pour laquelle cela n'existe pas. Cela nécessiterait de réécrire la structure de bloc de votre code comme si vous aviez écrit le bloc try/catch en premier lieu. Il me semble que cela fait des ravages avec une portée variable et d'autres choses. Vous demandez à AOP de réécrire le code d'octet pour qu'il ressemble au code suivant, et c'est tout à fait une réécriture.

HerpDerp hd = null;

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

Manny.pacquiao();
4
bmargulies

@ 4herpsand7derpsago Si ce que vous essayez de faire est d'attraper l'exception levée en utilisant AOP pour effectuer diverses tâches pour la gérer, puis revient au code où l'exception levée à l'origine, je pense que vous manquez de comprendre le concept d'AOP.

Comme vous le signalez dans votre code

HerpDerp hd = null;

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

Manny.pacquiao();

Si vous voulez qu'AOP intercepte votre RuntimeException, effectuez quelques trucs pour le gérer et revienne à Manny.pacquiao();, la réponse est vous ne pouvez pas. La raison en est que lorsque le RuntimeException est lancé et intercepté par AOP, la pile est déjà dans votre code AOP. vous ne pouvez pas revenir pour exécuter Many.pacquiao();. La seule façon si vous souhaitez continuer à exécuter Many.pacquiao(); est d'utiliser le bloc try-finally Comme suit

HerpDerp hd = null;

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

Ce n'est qu'alors que votre Many.pacquiao() sera exécutée, mais avant que votre AOP n'attrape le RuntimeException

2
Wins

Pour "intercepter" les exceptions non interceptées avec AspectJ, vous pouvez utiliser l'aspect suivant:

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
}

Je ne pense pas qu'il soit possible de "revenir" au point d'exécution.

2
Wim Deblauwe