Java 使用注释进行异常处理?
假设我有一个抛出某种异常的方法。异常抛出代码位于访问外部服务的第三方库中。我有几个类与外部服务做了大量的工作,并且有很多异常处理来处理潜在的问题。我遇到的问题是,我可能有很多异常,但如果有,我可能只需要执行少数操作中的一个,并且有大量的try/catch块。异常的类型甚至可能不相关,或者不同的方法可能抛出相同类型的异常,但是需要根据抛出异常的方法采取不同的操作 我要寻找的是一个注释,它可以取代try/catch,并简单地指示在该方法中出现异常时要采取的行为。我知道SpringApsectJ可以做这类事情,但我目前无法轻松添加任何新的依赖项或修改pom以调整现有的依赖项。因此,我希望这可以通过自定义注释来实现。例如:Java 使用注释进行异常处理?,java,exception,exception-handling,annotations,try-catch,Java,Exception,Exception Handling,Annotations,Try Catch,假设我有一个抛出某种异常的方法。异常抛出代码位于访问外部服务的第三方库中。我有几个类与外部服务做了大量的工作,并且有很多异常处理来处理潜在的问题。我遇到的问题是,我可能有很多异常,但如果有,我可能只需要执行少数操作中的一个,并且有大量的try/catch块。异常的类型甚至可能不相关,或者不同的方法可能抛出相同类型的异常,但是需要根据抛出异常的方法采取不同的操作 我要寻找的是一个注释,它可以取代try/catch,并简单地指示在该方法中出现异常时要采取的行为。我知道SpringApsectJ可以做
@Catcher(action=SomeEnum.SOME_ACTION)
public void doSomething(ServiceObj obj) throws SomeException {
ExternalService.makeThingsHappen(obj);
}
当然,我会假设一个单独的类将处理异常。另一个困难是,我需要同样通过的ServiceObj。如果makeThingsHappen()失败,我可能需要obj来执行其他操作。action变量将告诉处理程序类如何处理obj
这可以在没有严重污点的情况下完成吗,或者我希望得到一些可能不存在的东西吗?这应该是一个低级别的过程,并不意味着我们不能在当前级别上完成同样的事情,但它可能需要一堆代码,并且会使系统稍微复杂一点。 然而,我的建议是这样的(我希望我的建议是正确的),首先为想要处理异常的人定义一个接口,类似这样的
interface ExceptionHandler{
void handleException(Throwable t);
}
interface Caller{
void callMethod()throws Throwable;
}
然后为用户提供一个注释(API)来标记其方法,可能会引发一些异常
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
@interface Catch{
public Class<? extends ExceptionHandler> targetCatchHandler();
public Class<? extends Throwable> targetException() default Exception.class;
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface CatchGroup{
public Catch[] catchers();
}
然后,您需要一个负责管理执行流程并调用可能的异常处理程序的人
class MethodCaller{
/*
* @param isntance: instance which implemented the Caller interface
*/
public static void callMethod(Caller instance)
throws Exception {
Method m = instance.getClass().getMethod("callMethod");
Annotation as[] = m.getAnnotations();
Catch[] li = null;
for (Annotation a : as) {
if (a.annotationType().equals(CatchGroup.class)) {
li = ((CatchGroup) a).catchers();
}
// for(Catch cx:li){cx.targetException().getName();}
}
try {
instance.callMethod();
} catch (Throwable e) {
Class<?> ec = e.getClass();
if (li == null) {
return;
}
for (Catch cx : li) {
if (cx.targetException().equals(ec)) {
ExceptionHandler h = cx.targetCatchHandler().newInstance();
h.handleException(e);
break;
}
}
}
}
}
和方法调用者
class Foo implements Caller{//the class who calls the method
@Override
@CatchGroup(catchers={
@Catch(targetCatchHandler=Bar.class,targetException=ArithmeticException.class),
@Catch(targetCatchHandler=Bar.class,targetException=NullPointerException.class)})
public void callMethod()throws Throwable {
int a=0,b=10;
System.out.println(b/a);
}
public static void main(String[] args) throws Exception {
Foo foo=new Foo();
MethodCaller.callMethod(foo);
}
}
如您所见,用户必须通过callmethod()
方法调用这些方法,您还可以省略Caller
接口,并使用注释在一个类中声明多个方法,它需要一堆额外的代码。
我希望能帮上忙。谢谢大家的帮助。我研究了SpringAOP,但最终决定反对它。最后我使用了try/catch块,但创建了一个注入到每个类中的处理程序,并将所有抛出的异常包装到我自己的异常类中,然后在一行中将其传递给处理程序。这有点类似于User251414的建议,因为有一个专用的处理程序,但我放弃了注释。我有很多try/catch块,但至少我保留了大部分处理逻辑。我的解决方案的简要说明,以防其他人发现这一点,这有点模糊,但您仍然可以理解这一点:
public enum DoThisEnum {
DO_THIS,
DO_THAT,
DO_OTHER_THING;
}
public class MyException extends Exception {
private DoThisEnum doThis;
private MyObject dataObj;
//Constructor, overloaded to run super(originalException) or super()
//as well as taking doThis and dataObj as parameters
//Getters, setters, etc
}
public interface IExceptionHandler {
void handleException(MyException exception);
}
然后用一个具体的类实现IEExceptionHandler,该类接受MyException,读取附加数据,并基于它执行操作。然后,可能引发此类异常的每个块都可以像这样被捕获:
...
try {
doSomething(Object data);
} catch (SomeException e) {
handler.handleException(new MyException(e, DoThisEnum.DO_THAT, data));
//Anything else to do, maybe return or return null, rethrow, etc.
}
现在,大部分的细节都封装在处理程序中,而try/catch块是最小的。处理程序可以记录原始异常的堆栈跟踪,也可以基于它执行其他操作,然后根据枚举执行您自己的操作。也许这不是一个完美的解决方案,但在这里它已经足够好了。注释本身并没有添加行为。它们是元数据。你需要为它们提供一个解析器,如果它找到它们,就可以添加这种行为;它可以通过AOP或一些字节码操作进行简单的处理。
...
try {
doSomething(Object data);
} catch (SomeException e) {
handler.handleException(new MyException(e, DoThisEnum.DO_THAT, data));
//Anything else to do, maybe return or return null, rethrow, etc.
}