嗨,我想排除带注释的方法,这里是代码。
@Aspect
public class ExceptionHandlingAspect {
private static final String TAG = ExceptionHandlingAspect.class.getName();
@Pointcut("execution(* android.mobile.peakgames.net.aspectjandroid.AspectActivity.*(..)) " +
"&& !@annotation(android.mobile.peakgames.net.aspectjandroid.exception.NoTryCatch)")
public void exceptionEntryPoint() {
}
@AfterThrowing(pointcut = "exceptionEntryPoint()", throwing = "throwable")
public void exceptionMethod(JoinPoint joinPoint, Throwable throwable) {
Log.e(TAG, "Exception caught : " + throwable + " on method : " + joinPoint.getSignature());
if (joinPoint.getTarget() instanceof Activity) {
if (throwable instanceof AuthenticationException) {
new AlertDialog.Builder((Context) joinPoint.getTarget())
.setTitle("Authentication Error")
.setMessage("You are not authenticated")
.show();
} else {
new AlertDialog.Builder((Context) joinPoint.getTarget())
.setTitle("Error")
.setMessage("Error occurred at : " + joinPoint.getSignature() + " " +
"Exception : " + throwable)
.show();
}
}
}
@Around(value = "exceptionEntryPoint()")
public Object exceptionAroundMethod(ProceedingJoinPoint joinPoint) {
try {
return joinPoint.proceed();
} catch (Throwable ignored) {
}
return null;
}
}
排除任何用NoTryCatch注释的方法
上面的代码确实排除了用NoTryCatch注释的方法,但是当这个方法被异常调用时,它会停止下一个方法的执行。例如
@NoTryCatch
void test(){throws NullPointor..}
现在我按顺序调用方法
test()
test1()
test1()不运行。
如果我删除@注释(android.mobile.peakgames.net.aspectjandroid.exception.NoTryCatch)
test1()运行
当然,如果忽略在test()中引发的异常,即让它升级,则test1()不会运行。由于该未处理的异常,从未调用下一个方法。我认为这正是你的aspect设计的目的。你为什么期待不同的行为?如果你真的期望其他的东西,那么请在评论中描述它,我可以在编辑我的答案时告诉你如何做。
OP评论后更新:
好吧,这里有一个自制的问题:如果方法调用NoTryCatch void callee(),当然不会像设计的那样处理被调用方()中的异常。相反,它升级到未注释的调用方(),因此方面将在那里处理它。调用者如何知道被调用者中的某个方面忽略了异常?或者这个方面怎么知道呢?当将控制返回给调用方时,被调用方的控制流已经结束。
这种异常处理的概念至少很复杂。我甚至认为它有问题,因为调用链的最内部元素决定了所有外部元素都应该忽略一个异常。通常,异常处理的工作方式正好相反。调用方决定如何处理被调用方而不是被调用方本身引发的异常。因此,我建议您改变异常处理的想法和概念。
话虽如此,我将用一点MCVE向您展示我所说的在您的应用程序中真正发生的事情。因为我不是Android开发者,希望它能在任何Java SE机器上运行,所以我用实物模型模拟了AndroidAPI的相关部分:
Android API模型:
package android.content;
public class Context {}
package android.app;
import android.content.Context;
public class Activity extends Context {}
这一个只是通过登录控制台来模拟警报对话框。
package android.app;
import android.content.Context;
public class AlertDialog {
public AlertDialog() {}
public static class Builder {
private String title;
private String message;
public Builder(Context target) {}
public Builder setTitle(String title) {
this.title = title;
return this;
}
public Builder setMessage(String message) {
this.message = message;
return this;
}
public void show() {
System.out.println("ALERT DIALOG: " + title + " -> " + message);
}
}
}
package org.apache.http.auth;
public class AuthenticationException extends Exception {
private static final long serialVersionUID = 1L;
public AuthenticationException(String message) {
super(message);
}
}
标记注释:
package android.mobile.peakgames.net.aspectjandroid.exception;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
@Retention(RUNTIME)
public @interface NoTryCatch {}
驱动程序应用:
package android.mobile.peakgames.net.aspectjandroid;
import org.apache.http.auth.AuthenticationException;
import android.app.Activity;
import android.mobile.peakgames.net.aspectjandroid.exception.NoTryCatch;
public class AspectActivity extends Activity {
public String doSomething() {
System.out.println("Doing something");
return "something";
}
@NoTryCatch
public String doSomethingElse() {
System.out.println("Doing something else");
throw new RuntimeException("oops");
}
public String doSomethingFancy() throws AuthenticationException {
System.out.println("Doing something fancy");
throw new AuthenticationException("uh-oh");
}
public void run() throws AuthenticationException {
doSomething();
doSomethingElse();
doSomethingFancy();
}
public static void main(String[] args) throws AuthenticationException {
new AspectActivity().run();
}
}
OP的方面,略有优化:
基本上,这正是你的方面,有一些优化:
package de.scrum_master.aspect;
import org.apache.http.auth.AuthenticationException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.mobile.peakgames.net.aspectjandroid.AspectActivity;
import android.util.Log;
@Aspect
public class ExceptionHandlingAspect {
private static final String TAG = ExceptionHandlingAspect.class.getName();
@Pointcut("execution(* *(..)) && target(activity)")
public void methodsOfInterest(AspectActivity activity) {}
@Pointcut("@annotation(android.mobile.peakgames.net.aspectjandroid.exception.NoTryCatch)")
public void annotationNoTryCatch() {}
@Around("methodsOfInterest(activity) && !annotationNoTryCatch()")
public Object exceptionAroundMethod(ProceedingJoinPoint thisJoinPoint, AspectActivity activity) {
try {
return thisJoinPoint.proceed();
} catch (Throwable throwable) {
String errorMessage = "Error " + throwable + " in method " + thisJoinPoint.getSignature();
Log.e(TAG, errorMessage);
Builder builder = new AlertDialog.Builder(activity);
if (throwable instanceof AuthenticationException)
builder.setTitle("Authentication Error").setMessage("You are not authenticated").show();
else
builder.setTitle("Error").setMessage(errorMessage).show();
return null;
}
}
}
控制台日志:
Doing something
Doing something else
[de.scrum_master.aspect.ExceptionHandlingAspect] Error java.lang.RuntimeException: oops in method void android.mobile.peakgames.net.aspectjandroid.AspectActivity.run()
ALERT DIALOG: Error -> Error java.lang.RuntimeException: oops in method void android.mobile.peakgames.net.aspectjandroid.AspectActivity.run()
日志清楚地显示
doThingElse()
并且没有在那里处理错误,run()
反而触发了建议,因此错误在那里得到了处理。run()
,错误也会在main(...)
中处理。那么,为了避免注释整个调用链,您需要做什么?只有一种非常丑陋的方法可以做到这一点:手动簿记,即您的方面需要记住它以前忽略的异常实例,因为相应的错误处理建议从未针对该异常运行。
因此,您需要这样更改您的方面(忽略由手动try-catch创建的多线程和嵌套异常等问题,以免使其变得更复杂):
方面,迭代2:
package de.scrum_master.aspect;
import java.util.HashSet;
import java.util.Set;
import org.apache.http.auth.AuthenticationException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.mobile.peakgames.net.aspectjandroid.AspectActivity;
import android.util.Log;
@Aspect
public class ExceptionHandlingAspect {
private static final String TAG = ExceptionHandlingAspect.class.getName();
private Set<Throwable> ignoredErrors = new HashSet<>();
@Pointcut("execution(* *(..)) && target(activity)")
public void methodsOfInterest(AspectActivity activity) {}
@Pointcut("@annotation(android.mobile.peakgames.net.aspectjandroid.exception.NoTryCatch)")
public void annotationNoTryCatch() {}
@Around("methodsOfInterest(activity) && !annotationNoTryCatch()")
public Object exceptionAroundMethod(ProceedingJoinPoint thisJoinPoint, AspectActivity activity) throws Throwable {
try {
return thisJoinPoint.proceed();
} catch (Throwable throwable) {
if (ignoredErrors.contains(throwable))
throw throwable;
String errorMessage = "Error " + throwable + " in method " + thisJoinPoint.getSignature();
Log.e(TAG, errorMessage);
Builder builder = new AlertDialog.Builder(activity);
if (throwable instanceof AuthenticationException)
builder.setTitle("Authentication Error").setMessage("You are not authenticated").show();
else
builder.setTitle("Error").setMessage(errorMessage).show();
return null;
}
}
@AfterThrowing(value = "methodsOfInterest(activity) && annotationNoTryCatch()", throwing = "throwable")
public void ignoreExceptions(JoinPoint thisJoinPoint, AspectActivity activity, Throwable throwable) {
ignoredErrors.add(throwable);
}
}
控制台日志,迭代2:
Doing something
Doing something else
Exception in thread "main" java.lang.RuntimeException: oops
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.doSomethingElse(AspectActivity.java:17)
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.run_aroundBody4(AspectActivity.java:27)
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.run_aroundBody5$advice(AspectActivity.java:34)
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.run(AspectActivity.java:1)
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.main(AspectActivity.java:32)
如您所见,异常现在升级,按您所说的那样“崩溃”应用程序。
P、 S.:InheritableThreadLocal
P. P. S.:如果您将
@NoTryCatch
注释从doXXthingElse()
向下移动到doXXTHingFancy
,则日志更改如下:
Doing something
Doing something else
[de.scrum_master.aspect.ExceptionHandlingAspect] Error java.lang.RuntimeException: oops in method String android.mobile.peakgames.net.aspectjandroid.AspectActivity.doSomethingElse()
ALERT DIALOG: Error -> Error java.lang.RuntimeException: oops in method String android.mobile.peakgames.net.aspectjandroid.AspectActivity.doSomethingElse()
Doing something fancy
Exception in thread "main" org.apache.http.auth.AuthenticationException: uh-oh
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.doSomethingFancy(AspectActivity.java:22)
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.run_aroundBody4(AspectActivity.java:28)
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.run_aroundBody5$advice(AspectActivity.java:34)
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.run(AspectActivity.java:1)
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.main(AspectActivity.java:32)
我对AOP相当陌生。我正在尝试使用AspectJ在没有Spring的maven项目中创建注释。然而,我试图使用@方面调用的方法没有被调用。 这就是我的pom看起来的样子: 注释如下所示: 我为我的注释创建了一个注释处理器: } 我在这次通话中称之为: 我创建了一个aop。xml文件,并将其放置在与pom相同的文件夹中。xml。 当我调用createPurchase方法时,它在没有首先调用@Befo
问题内容: 我需要 在类中使用@X注释的方法或使用@X注释的方法的切入点 。我还 需要注释对象 。如果同时注释了类和方法,则 我更喜欢将方法注释作为参数 。 我尝试了以下操作,这将创建“不一致的绑定”警告。(为什么不将它们设置为null?) 下面创建“跨’||’的参数x的模糊绑定 在切入点”警告。(我认为这并不一定有意义:为什么不绑定第一个短路评估?) 如果存在类和方法注释,则将先前的尝试自然地分
我有一个用@Cacheable注释的方法。如果在方法内部捕获了异常,我希望清除缓存。但是,缓存似乎是在清除缓存的行之后执行的方面中加载的。因此,当在方法中捕获异常时,即使清除了缓存,空字符串结果仍保留在缓存中。 我应该从哪里清除缓存?
我尝试在DAO中使用带有Spring注释的,但遇到了这样的问题: 工作正确: 例外: 如何使用parallelStream()注释的事务方法? 更新为什么会发生这种情况Spring事务管理器和多线程,但我希望支持java 8的Spring 4能够提供一些解决方案。有什么想法吗?
问题内容: 我有一个带有注释的类(而不是对其所有方法进行标记)。 虽然我在该类中只有一个方法,但不应将其注释为。 我的问题是我可以在此方法中添加注释以将其标记为“非事务性”吗?或者我应该开始将此类中的每个方法都标记为“事务性”,但不包括此方法(很多工作) 谢谢。 问题答案: 有不同的事务传播策略可以使用。这些存在于枚举中。您可能要使用的是 因此,使用这两种方法在您的类中注释方法。 您可以在此处找到
我有一个方法,每隔20分钟运行一次。我只是在Spring boot中使用了@scheduled注释,但是我需要一个在运行时需要延迟时间的调度器。例如。如果我希望能够在运行时改变方法执行的延迟时间/频率,而不停止应用程序,即改变以DB为单位的频率,那么代码应该适应它。 代码中的固定速率应该是可变的,并在运行时取值。有可能实现吗?