如何使用AspectJ拦截处理自身异常的方法

如何使用AspectJ拦截处理自身异常的方法,第1张

如何使用AspectJ拦截处理自身异常的方法

是的你可以。您需要

handler()
切入点:

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

假设类

Example
在包中,则日志输出
de.scrum_master.app

***** Calling method with catch block *****handler(catch(ArithmeticException)) -> java.lang.ArithmeticException: / by zeroCan not divide by zero***** Calling method without catch block *****execution(void de.scrum_master.app.Example.divideByZeroWithNoCatch()) -> java.lang.ArithmeticException: / by zeroexecution(void de.scrum_master.app.Example.main(String[])) -> java.lang.ArithmeticException: / by zeroException 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)

更新:
如果您想知道异常处理程序的位置,有一个简单的方法:使用封闭的连接点的静态部分。您还可以获得有关参数名称和类型等的信息。只需使用代码完成功能即可查看可用的方法。

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

现在像这样更新代码:

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();    }}

然后控制台日志显示:

***** 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 zeroexecution(void de.scrum_master.app.Example.main(String[])) -> java.lang.ArithmeticException: / by zeroException 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)

如果那对您足够好,那么您就很好。但是请注意,静态部分不是完整的连接点,因此您不能从那里访问参数值。为此,您必须进行手动记账。这可能很昂贵,并且可能会使您的应用程序变慢。但是,对于它的价值,我向您展示了如何做到:

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

为什么我们需要一个

ThreadLocal
成员进行联接点簿记?好吧,因为显然,否则我们将在多线程应用程序中遇到问题。

现在控制台日志显示:

***** 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!    de.scrum_master.app.Example@4783da3f    @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 zeroexecution(void de.scrum_master.app.Example.main(String[])) -> java.lang.ArithmeticException: / by zeroException 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)


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zaji/5498636.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-12-12
下一篇2022-12-12

发表评论

登录后才能评论

评论列表(0条)

    保存