java - 将元数据添加到 java throwable 对象

标签 java spring exception spring-aop

在我的应用程序中,我执行一些业务逻辑,例如我有业务逻辑方法:

@Override
@ByPassable(exceptions = {"InvalidIdentityException"})
public void validate(Model model) {
    if (nonNull(model)) {
        final boolean test = isOk(model.getIdentity());
        if (test) {
            throw new InvalidIdentityException("Invalid bla bla");
        }
    }
}

和自定义异常类:

public class InvalidIdentityException extends SomeException {

    public InvalidIdentityException (final String message) {
        super(message);
    }
}
@ByPassable on 方法获取可以绕过的异常列表,因此在此实例中 InvalidIdentityException被抛出,它变成 bypassable在不久的将来重新执行此方法时。

我为我的 Spring Boot 应用程序启动了一个 bean,它具有一组可绕过的异常:
public class Config {

    @Bean("bypassable-exceptions")
    public Set<String> getBypassableExceptions() {
        final Set<String> exceptions = new HashSet<>();
        new Reflections(new MethodAnnotationsScanner())
                .getMethodsAnnotatedWith(ByPassable.class).stream()
                .filter(method -> method.getAnnotation(ByPassable.class).enabled())
                .forEach(method -> {
                    final String[] exceptions = method.getAnnotation(ByPassable.class).exceptions();
                    exceptions.addAll(Arrays.asList(exceptions));
                });
        return exceptions;
    }
}

每当出现 Bypassable 的异常时被抛出一个方法,我的应用程序坚持 Throwable对象作为数据库中的 Json 但是我需要一个额外的 boolean 属性 bypassable在这个应该更新的可抛出对象上 @BeforeThrowing作为拦截的异常(exception)。这可能吗?
public class ExceptionAspect {

    @Pointcut("@annotation(com.services.aop.ByPassable)")
    public void byPassableExceptionMethods() {
    }

    @BeforeThrowing(pointcut = "byPassableExceptionMethods()", throwing = "exception")
    public void beforeThrowingAdviceForByPassableExceptionMethods(final JoinPoint jp,
                                                                 final Throwable exception) {

     // check against the set of bypassable exceptions and update a custom property on the exception 
        class so when Throwable is persisted it is persisted with this customer property e.g. bypassable 
         = true

    }

最佳答案

来自 Spring 引用文档:AOP Concepts没有建议类型@BeforeThrowing .

在 Spring AOP 中,可以建议方法执行(连接点)——在方法开始之前、方法结束之后(有或没有异常(exception))或前后(方法开始之前和方法结束之后)。这也意味着该方法中的逻辑在运行时无法更改,只能操作方法执行的输入或结果。

根据共享的代码逻辑,异常是基于方法内的验证而引发的,并且 Spring AOP 在引发异常之前不提供通知句柄。

话虽如此,以下是我能想到的实现相同目标的方法。

  • 根据条件和字段 bypassable 引发可绕过的异常可以在异常实例创建时间本身期间设置。这将是最简单的方法。

  • 以下是我想出的实现相同目标的 Spring AOP 方法。
  • @AfterThrowing可按如下方式设置可旁路。
  • @BeforeThrowing可以模拟。

  • 注意:使用 Spring AOP 不能拦截内部调用。引用文档中的相关信息可在 section 下找到。 .

    Due to the proxy-based nature of Spring’s AOP framework, calls within the target object are, by definition, not intercepted.



    因此,出于演示目的,示例代码自动连接自己的引用。抛出异常的方法可以移动到另一个 bean 并类似地被拦截。

    对示例进行了以下更改。

    具有公共(public)基类的可绕过异常

    public class BaseBypassableException extends RuntimeException {
    
        private boolean bypassable;
    
        public BaseBypassableException(String message) {
            super(message);
        }
    
        public boolean isBypassable() {
            return bypassable;
        }
    
        public void setBypassable(boolean bypassable) {
            this.bypassable = bypassable;
        }
    }
    

    可绕过的异常从公共(public)基类扩展

    public class InvalidIdentityException extends BaseBypassableException {
    
        public InvalidIdentityException(String message) {
            super(message);
        }
    }
    

    建议方法修改如下。 (示例有 String 而不是 Model)

    @Component
    public class BypassableServiceImpl implements BypassableService {
    
        @Autowired
        BypassableService service;
    
        @Override
        @ByPassable(exceptions = {"InvalidIdentityException"})
        public void validate(String model) {
            if (null != model) {
                final boolean test = !("Ok".equals(model));
                if (test) {
                    service.throwException(new InvalidIdentityException("Invalid bla bla"));
                }
            }
            System.out.println("Validate called : "+model);
    
        }
    
        @Override
        public void throwException(BaseBypassableException exception) {
            throw exception;
        }
    
    }
    

    方面建议这两种方法。 throwing基于异常类型的过滤器,因此对于示例,我没有包含检查 bypassableExceptionNames 的逻辑并且逻辑安全地假定异常的类型为 BaseBypassableException .如果需要,可以修改逻辑以包括检查。

    @Component
    @Aspect
    public class ExceptionAspect {
    
        @Autowired
        @Qualifier("bypassable-exceptions")
        Set<String> bypassableExceptionNames;
    
        @Pointcut("@annotation(com.services.aop.ByPassable)")
        public void byPassableExceptionMethods() {
        }
    
        @AfterThrowing(pointcut = "byPassableExceptionMethods()", throwing = "exception")
        public void afterThrowingAdviceForByPassableExceptionMethods(final JoinPoint jp,
                final BaseBypassableException exception) {
            System.out.println(jp.getSignature());
            System.out.println("Before " + exception.isBypassable());
            exception.setBypassable(true);
            System.out.println("After " + exception.isBypassable());
            System.out.println(exception);
        }
    
        @Before("execution(* com.services..*.*(..)) && args(exception)")
        public void beforeThrowingAdviceForByPassableExceptionMethods(final JoinPoint jp,
                final BaseBypassableException exception) {
            System.out.println(jp.getSignature());
            System.out.println("Before " + exception.isBypassable());
            exception.setBypassable(true);
            System.out.println("After " + exception.isBypassable());
            System.out.println(exception);
        }
    }
    

    希望这可以帮助

    关于java - 将元数据添加到 java throwable 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61483347/

    相关文章:

    .net - 在 .NET 异常中保留原始堆栈跟踪/行号

    c# - 继承除 System.Exception 之外的内置异常类

    java - org.apache.jasper.JasperException:java.lang.NumberFormatException:null

    java - 查找ColumnDefinition枚举或常量

    java - 尝试在Java中反转字符串时遇到错误

    java - 将文件上传到 Spring 时 net::ERR_CONNECTION_ABORTED 的可能原因是什么

    java - 使用@Transactional 注释的问题

    java - 文件的 Junit 测试用例

    java - 在Jsoup中选择带有空格字符的类

    java - autowire 如何在手动对象实例化中工作?