记录异常并继续执行而不会使代码混乱

时间:2018-07-30 19:53:49

标签: java aop spring-aop

我正在研究在我的应用程序上实现标准错误处理。我希望无法处理的错误(自定义未检查的错误),但也不会因故障屏障而记录下来而不会造成灾难性的错误,而不必使我的代码陷入麻烦的try catch和logger调用中。

让我举例说明。 我有一个接收一个json字符串并将其设置到我的对象模型中的入口,该模型中的字段之一调用timeHelper函数,如果参数无效(空或空),则此函数会引发异常。该函数的生成量对程序并不重要,实际上,该程序永远不会崩溃(以我的最大能力),因为它可以保持24/7的速度。

型号

public class MyModel{
   private string myField
   public void setMyField(String myfield){
       this.myField = Helper.DoStuff(myField)
   }
}

摄入

public class Intake{
    public MyModel receiveJson(){
        return JacksonMagic(arguments,MyModel.class)
    }
}

助手

Public class Helper{

    public String DoStuff(String myField){
        //Check that can throw exception
        //regular operation with return
    }
}

现在,当生活DoStuff美好时,它返回一个字符串,实际上永远不应该引发该异常,因为它暗示我的应用程序外部的json源发送了错误/丢失的信息。如果确实发生了,我希望将其记录下来,以便我调查发生了什么。我还想设置一个框架(可能与Spring AOP一起使用)来处理该日志记录。但是正如您通过示例所看到的那样,我还希望执行继续进行,因为这并不是破坏应用程序的事情。

我正在寻找的执行流程是这样的 Intake>模型> Helper(抛出异常)> Logger>谁叫Intake

再说一次,我想做到这一点,而无需尝试捕获记录器调用混乱

AOP有可能吗?

发布答案编辑 只想在这里留下一些消息来源。

要为IDE进行AspectJ编译设置,这篇文章真的很有帮助。 https://www.baeldung.com/aspectj

2 个答案:

答案 0 :(得分:2)

这不是例外的好用例。

异常表示您无法处理的事情,是您无法处理的“异常”事件。您所说的是一种可能的情况,将这种情况从异常更改为用例,在这种情况下,在服务层中记录警告可能是最佳解决方案。

异常有其位置,但是过度使用它们会使代码更难遵循,因为它破坏了应用程序的“流程”。异常不应用于控制流程。

在我的选择中,

AOP在异常处理方面几乎没有提供。充其量,它可以记录异常(也可以使用ExceptionHandler模式以更清晰的方式记录异常),但是,它肯定不会触发代码继续执行,就好像没有发生那样。

如果还没有,请研究日志记录策略,它们在这种情况下非常有用。

最重要的是:如果要继续控制流,请不要抛出异常(选中或未选中)。

答案 1 :(得分:1)

好的,假设您知道如何使用AspectJ编译器来编译您的项目,那么我们这里附带完整的MCVE。很抱歉重复使用包名称,导入等的类,但我希望您看到所有详细信息:

首先,我们需要我们的助手,该助手会随机抛出未经检查的异常,以便稍后可以看到实际的情况:

package de.scrum_master.app;

import java.util.Random;

public class Helper {
  private static final Random RANDOM = new Random();

  public static String doStuff(String myField) {
    if (RANDOM.nextBoolean())
      throw new RuntimeException("uh-oh!");
    return "processed " + myField;
  }
}
package de.scrum_master.app;

public class MyModel {
  private String myField;

  public void setMyField(String myField) {
    this.myField = Helper.doStuff(myField);
  }

  @Override
  public String toString() {
    return "MyModel(myField=" + myField + ")";
  }
}
package de.scrum_master.app;

public class Intake {
  public MyModel receiveJson(String... arguments) {
    return jacksonMagic(arguments, MyModel.class);
  }

  public MyModel jacksonMagic(String[] arguments, Class<?> clazz) {
    MyModel myModel = new MyModel();
    myModel.setMyField(arguments[0]);
    return myModel;
  }

  public static void main(String[] args) {
    for (int i = 0; i < 10; i++)
      System.out.println(new Intake().receiveJson("foo"));
  }
}

现在,当您通过Intake.main运行Little Driver应用程序时,您会在控制台上看到未处理的异常。这是使用方面处理此问题的方法。我将方面限制为将所有方法执行与返回类型String匹配,每当发生异常时就愚蠢地返回一个哑数值。您可以在适当的地方在其中添加更复杂的逻辑,并调整方面的切入点以匹配您要处理的方法。

package de.scrum_master.aspect;

public aspect ErrorHandler {
  String around() : execution(String *(..)) {
    try {
      return proceed();
    } catch (Exception e) {
      System.out.println("Exception handled: " + e);
      return "dummy";
    }
  }
}

我喜欢富有表现力的本机AspectJ语法,但是我知道有些人出于各种原因对基于注释的语法感到更自在。只需查看throws声明,字符串常量中的切入点,显式连接点声明,强制转换-糟糕!无论如何,我们开始:

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class ErrorHandler {

  @Around("execution(String *(..))")
  public String handleErrors(ProceedingJoinPoint thisJoinPoint) throws Throwable {
    try {
      return (String) thisJoinPoint.proceed();
    } catch (Exception e) {
      System.out.println("Exception handled: " + e);
      return "dummy";
    }
  }
}

控制台日志如下所示:

MyModel(myField=processed foo)
MyModel(myField=processed foo)
Exception handled: java.lang.RuntimeException: uh-oh!
MyModel(myField=dummy)
MyModel(myField=processed foo)
Exception handled: java.lang.RuntimeException: uh-oh!
MyModel(myField=dummy)
Exception handled: java.lang.RuntimeException: uh-oh!
MyModel(myField=dummy)
Exception handled: java.lang.RuntimeException: uh-oh!
MyModel(myField=dummy)
MyModel(myField=processed foo)
Exception handled: java.lang.RuntimeException: uh-oh!
MyModel(myField=dummy)
MyModel(myField=processed foo)