добавить метаданные к java метаемому объекту - PullRequest
0 голосов
/ 28 апреля 2020

В моем приложении я выполняю бизнес-логи c, например, у меня есть бизнес-логи c, методы:

@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 для ближайшего будущего, когда этот метод повторяется.

Я инициирую 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 в базе данных, однако Мне нужно иметь дополнительное логическое свойство bypassable для этого бросаемого объекта, которое должно быть обновлено @BeforeThrowing исключение как перехват. Это возможно?

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

    }

1 Ответ

0 голосов
/ 29 апреля 2020

Из справочной документации Spring: AOP Concepts нет типа подсказки @BeforeThrowing.

В Spring AOP может быть рекомендовано выполнение метода (точка соединения) - до его запуска после завершения метода (с исключением или без исключения) или около (до начала метода и после завершения метода). Это также означает, что логика c в этом методе не может быть изменена во время выполнения, можно манипулировать только входом или результатом выполнения метода.

Согласно общему коду logi c, Исключение выдается на основе проверки в методе, и Spring AOP не предоставляет дескриптор для совета перед выдачей исключения.

Сказав, что я могу придумать следующие способы достижения того же.

  1. A Обходное исключение возникает в зависимости от условия, и поле bypassable может быть установлено во время самого создания экземпляра исключения. Это был бы самый простой способ.

Ниже приводятся способы Spring AOP, которые я придумал для достижения того же.

@AfterThrowing можно использовать для настройки обхода следующим образом.

@BeforeThrowing можно смоделировать.

Примечание. Внутренние вызовы не могут быть перехвачены с помощью Spring AOP. Соответствующую информацию из справочной документации можно найти в разделе .

Из-за прокси-природы среды AOP среды Spring вызовы внутри целевого объекта по определению не перехватываются.

По этой причине в демонстрационных целях Пример кода автоматически связывает собственную ссылку. Метод генерирования исключения может быть перемещен в другой bean-компонент и перехвачен аналогично.

В этом примере сделаны следующие изменения.

Обходные исключения имеют общий базовый класс

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 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 основаны на типе исключения, поэтому для примера я не включил лог c для проверки bypassableExceptionNames, а лог c предполагает, что исключение имеет тип BaseBypassableException. Логика c может быть изменена, чтобы включить проверку при необходимости.

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

Надеюсь, это поможет

...