Oui, vous pouvez. Vous avez besoin d'un handler()
pointcut:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class LogAspect {
@AfterThrowing(value = "execution(* *(..))", throwing = "e")
public void log(JoinPoint thisJoinPoint, Throwable e) {
System.out.println(thisJoinPoint + " -> " + e);
}
@Before("handler(*) && args(e)")
public void logCaughtException(JoinPoint thisJoinPoint, Exception e) {
System.out.println(thisJoinPoint + " -> " + e);
}
}
sortie du journal, en supposant la classe Example
est dans le paquet de.scrum_master.app
:
***** Calling method with catch block *****
handler(catch(ArithmeticException)) -> java.lang.ArithmeticException:/by zero
Can not divide by zero
***** Calling method without catch block *****
execution(void de.scrum_master.app.Example.divideByZeroWithNoCatch()) -> java.lang.ArithmeticException:/by zero
execution(void de.scrum_master.app.Example.main(String[])) -> java.lang.ArithmeticException:/by zero
Exception in thread "main" java.lang.ArithmeticException:/by zero
at de.scrum_master.app.Example.divideByZeroWithNoCatch(Example.java:13)
at de.scrum_master.app.Example.main(Example.java:21)
Mise à jour: Si vous voulez savoir où se trouve le gestionnaire d'exception, il y a un moyen simple: utiliser la partie statique du joinpoint. Vous pouvez également obtenir des informations sur les noms et les types de paramètres, etc. Utilisez simplement l'achèvement du code pour voir quelles méthodes sont disponibles.
@Before("handler(*) && args(e)")
public void logCaughtException(
JoinPoint thisJoinPoint,
JoinPoint.EnclosingStaticPart thisEnclosingJoinPointStaticPart,
Exception e
) {
// Exception handler
System.out.println(thisJoinPoint.getSignature() + " -> " + e);
// Method signature + parameter types/names
MethodSignature methodSignature = (MethodSignature) thisEnclosingJoinPointStaticPart.getSignature();
System.out.println(" " + methodSignature);
Class<?>[] paramTypes = methodSignature.getParameterTypes();
String[] paramNames = methodSignature.getParameterNames();
for (int i = 0; i < paramNames.length; i++)
System.out.println(" " + paramTypes[i].getName() + " " + paramNames[i]);
// Method annotations - attention, reflection!
Method method = methodSignature.getMethod();
for (Annotation annotation: method.getAnnotations())
System.out.println(" " + annotation);
}
maintenant mettre à jour votre code comme ceci:
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
int id();
String name();
String remark();
}
package de.scrum_master.app;
public class Example {
@MyAnnotation(id = 11, name = "John", remark = "my best friend")
public void divideByZeroWithCatch(int dividend, String someText) {
try {
int a = 5/0;
} catch (ArithmeticException e) {
System.out.println("Can not divide by zero");
}
}
public void divideByZeroWithNoCatch() {
int b = 5/0;
}
public static void main(String[] args) {
Example e = new Example();
System.out.println("***** Calling method with catch block *****");
e.divideByZeroWithCatch(123, "Hello world!");
System.out.println("***** Calling method without catch block *****");
e.divideByZeroWithNoCatch();
}
}
Ensuite, le journal de la console dit:
***** Calling method with catch block *****
catch(ArithmeticException) -> java.lang.ArithmeticException:/by zero
void de.scrum_master.app.Example.divideByZeroWithCatch(int, String)
int dividend
java.lang.String someText
@de.scrum_master.app.MyAnnotation(id=11, name=John, remark=my best friend)
Can not divide by zero
***** Calling method without catch block *****
execution(void de.scrum_master.app.Example.divideByZeroWithNoCatch()) -> java.lang.ArithmeticException:/by zero
execution(void de.scrum_master.app.Example.main(String[])) -> java.lang.ArithmeticException:/by zero
Exception in thread "main" java.lang.ArithmeticException:/by zero
at de.scrum_master.app.Example.divideByZeroWithNoCatch(Example.java:14)
at de.scrum_master.app.Example.main(Example.java:22)
Si cela est assez bon pour vous, alors vous êtes bien. Mais attention, la partie statique n'est pas le point de connexion complet, donc vous ne pouvez pas accéder aux valeurs des paramètres à partir de là. Pour ce faire, vous devez faire une comptabilité manuelle. Et c'est peut-être cher et peut ralentir votre application.Mais pour ce qu'il vaut la peine, je vous montre comment le faire:
package de.scrum_master.aspect;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
@Aspect
public class LogAspect {
private ThreadLocal<JoinPoint> enclosingJoinPoint;
@AfterThrowing(value = "execution(* *(..))", throwing = "e")
public void log(JoinPoint thisJoinPoint, Throwable e) {
System.out.println(thisJoinPoint + " -> " + e);
}
@Before("execution(* *(..)) && within(de.scrum_master.app..*)")
public void recordJoinPoint(JoinPoint thisJoinPoint) {
if (enclosingJoinPoint == null)
enclosingJoinPoint = ThreadLocal.withInitial(() -> thisJoinPoint);
else
enclosingJoinPoint.set(thisJoinPoint);
}
@Before("handler(*) && args(e)")
public void logCaughtException(JoinPoint thisJoinPoint, Exception e) {
// Exception handler
System.out.println(thisJoinPoint + " -> " + e);
// Method signature + parameter types/names
JoinPoint enclosingJP = enclosingJoinPoint.get();
MethodSignature methodSignature = (MethodSignature) enclosingJP.getSignature();
System.out.println(" " + methodSignature);
Class<?>[] paramTypes = methodSignature.getParameterTypes();
String[] paramNames = methodSignature.getParameterNames();
Object[] paramValues = enclosingJP.getArgs();
for (int i = 0; i < paramNames.length; i++)
System.out.println(" " + paramTypes[i].getName() + " " + paramNames[i] + " = " + paramValues[i]);
// Target object upon which method is executed
System.out.println(" " + enclosingJP.getTarget());
// Method annotations - attention, reflection!
Method method = methodSignature.getMethod();
for (Annotation annotation: method.getAnnotations())
System.out.println(" " + annotation);
}
}
Pourquoi avons-nous besoin d'un membre ThreadLocal
pour la tenue de livres joinpoint? Eh bien, parce que, évidemment, nous aurions des problèmes dans les applications multithread dans le cas contraire.
Maintenant, le journal de la console dit:
***** Calling method with catch block *****
handler(catch(ArithmeticException)) -> java.lang.ArithmeticException:/by zero
void de.scrum_master.app.Example.divideByZeroWithCatch(int, String)
int dividend = 123
java.lang.String someText = Hello world!
[email protected]
@de.scrum_master.app.MyAnnotation(id=11, name=John, remark=my best friend)
Can not divide by zero
***** Calling method without catch block *****
execution(void de.scrum_master.app.Example.divideByZeroWithNoCatch()) -> java.lang.ArithmeticException:/by zero
execution(void de.scrum_master.app.Example.main(String[])) -> java.lang.ArithmeticException:/by zero
Exception in thread "main" java.lang.ArithmeticException:/by zero
at de.scrum_master.app.Example.divideByZeroWithNoCatch(Example.java:14)
at de.scrum_master.app.Example.main(Example.java:22)
Oh, je ne savais pas à propos de ce pointcut supplémentaire. Est-il disponible dans toutes les implémentations d'AspectJ? Pour autant que je sache, par exemple, l'implémentation de SpringAspectJ ne permet pas d'utiliser le gestionnaire, comme on peut le voir [ici (Spring-pointcut-designators)] (https://docs.spring.io/spring/docs/current/ spring-framework-reference/html/aop.html # aop-pointcuts-designators) –
Je sais, mais cette question concerne AspectJ, pas Spring AOP. Ce dernier est juste "AOP Lite", et la section manuelle que vous avez liée à une mention dans la boîte grise "Autres types de point" qu'AspectJ supporte 'handler()' et Spring AOP ne le fait pas. Mais les bonnes nouvelles sont: Vous pouvez également configurer Spring pour utiliser full [AspectJ via le tissage de temps de chargement] (https://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html # aop-using-aspectj). Ensuite, vous pouvez également utiliser 'handler()'. – kriegaex
oui, j'ai déjà édité ma réponse dans ce que je pense que je voulais dire, en soulignant explicitement qu'il ne s'agissait pas de "full AspectJ". Ayant seulement travaillé auparavant avec la saveur printanière, je me suis sentie là-bas, semble-t-il. –