gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 21:28:48 27 4
gpt4 key购买 nike

当某些特定异常发生时,我正在尝试添加一些监控。例如,如果我有这样的方面:

@Aspect
public class LogAspect {

@AfterThrowing(value = "execution(* *(..))", throwing = "e")
public void log(JoinPoint joinPoint, Throwable e){
System.out.println("Some logging stuff");
}
}

和测试类:

 public class Example {


public void divideByZeroWithCatch(){
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();
System.out.println("***** Calling method without catch block *****");
e.divideByZeroWithNoCatch();
}
}

作为输出,我将得到:

***** Calling method with catch block *****
Can not divide by zero
***** Calling method without catch block *****
Some logging stuff

我想知道是否有办法让我在抛出异常后拦截方法执行,在我的建议中做一些事情并继续在相应的 catch block 中执行代码?因此,如果我调用 divideByZeroWithCatch() 我可以得到:

Some logging stuff
Can not divide by zero

最佳答案

是的,你可以。你需要一个 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;

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

日志输出,假设类 Example 在包 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)

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

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

如果这对你来说足够好,那么你很好。但请注意,静态部分不是完整的连接点,因此您无法从那里访问参数值。为此,您必须进行手动簿记。这可能很昂贵,并且会减慢您的应用程序。但是对于它的值(value),我会告诉你如何去做:

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

为什么我们需要一个 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 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)

关于java - 如何拦截使用 AspectJ 处理自身异常的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42092503/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com