Невозможно перехватить исключение, созданное в совете @Before в совете @AfterThrowing

Я использую советы @Before и @AfterThrowing Spring AOP. В предыдущем совете я проверяю данные и выбрасываю определенные пользователем исключения при сбое проверки. Поскольку я уже определил @AfterThrowing, я ожидаю, что это перехватит ошибку и напечатает дополнительную информацию, которая мне нужна. Но неожиданно я не могу воспользоваться советом @AfterThrowing. Я не уверен, правильно ли я это делаю, или это не поддерживается Spring AOP.

Класс конфигурации Spring

package configurations;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScans({
    @ComponentScan(value = "beans"), 
    @ComponentScan(value = "aspects")
})
@ComponentScan(basePackages = {"exceptions"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class SpringConfiguration {}

Класс сотрудников

package beans;

import java.io.Serializable;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;

@Component("employee")
//@DependsOn("fullName")
public class Employee implements Comparable<Employee>, Serializable, Cloneable {
    private int id;
    private String userId;
    private String email;
    
    @Autowired(required = false)
    private FullName fullName;
    
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    public String getUserId() { return userId; }
    public void setUserId(String userId) { this.userId = userId; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public FullName getFullname() { return fullName; }
    public void setFullname(FullName fullname) { this.fullName = fullname; }
    
    @Override
    public String toString() {
        return "Employee [id=" + id + ", userId=" + userId + ", email=" + email + ", fullname=" + fullName + "]";
    }
    
    public int compareTo(Employee secondEmployee) {
        return Integer.compare(this.id, secondEmployee.id); 
    }
}

Аспекты сотрудников

package aspects;

import java.util.Arrays;
import java.util.List;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import exceptions.DataOverflowException;
import exceptions.NumberUnderflowException;

@Component
@Aspect
public class EmployeeAspect {
    
    @Before(value="execution(* beans.Employee.set*(..))")
    public void before(JoinPoint joinPoint) throws  Exception{
        List<Object> inputArguments = Arrays.asList(joinPoint.getArgs());
        for(Object argument : inputArguments) {
            switch(argument.getClass().getName()) {
                case "java.lang.String" : {
                    String inputString = (String) argument;
                    if(inputString.length() > 20) 
                        throw new DataOverflowException(joinPoint.getSignature().toString() +" is having excess input information to store.");
                    else
                        break;
                }
                case "java.lang.int" : {
                    int inputNumber = (int) argument;
                    if(inputNumber < 1) 
                        throw new NumberUnderflowException(joinPoint.getSignature().toString() +" is not meeting minimun input information to store.");
                    else
                        break;
                }
            }
        }
    }

    @Around("execution(* beans.Employee.*(..))")
    public void invoke(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Method with Signature :: "+ joinPoint.getSignature() + " having data "+ joinPoint.getTarget() + " invoked");
        joinPoint.proceed(joinPoint.getArgs());
        System.out.println("Method with Signature :: "+ joinPoint.getSignature() + " having data "+ joinPoint.getTarget() + " completed Successfully");
    }
    
    @AfterThrowing(pointcut = "execution(* *(..))",  throwing= "error")
    public void afterThrowing(JoinPoint joinPoint, Exception error) {
        System.out.println("===============ExceptionAspect============");
    }

}

ТестКласс

package clients;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import beans.Employee;
import configurations.SpringConfiguration;

public class TestClientA {
    public static void main(String[] args) {
        ConfigurableApplicationContext springContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        Employee empl = springContext.getBean(Employee.class);
        empl.setEmail("[email protected]");
        springContext.close();
    }
}

person Vineel Pellella    schedule 16.02.2021    source источник


Ответы (1)


Из справочной документации @AfterThrowing можно прочитать:

Обратите внимание, что @AfterThrowing не указывает на общий обратный вызов обработки исключений. В частности, метод совета @AfterThrowing должен получать исключения только от самой точки соединения (целевой метод, объявленный пользователем), но не от сопутствующего метода @After/@AfterReturning.

В вашем коде совет @Before выполняется до фактического объявленного пользователем целевого метода и выдается исключение. С этой точки управление возвращается, и, следовательно, до @AfterThrowing совета не дойдет.

Также просмотрите консультация по заказу

Начиная с Spring Framework 5.2.7, методам-советам, определенным в одном и том же классе @Aspect, которые должны выполняться в одной и той же точке соединения, назначается приоритет в зависимости от их типа совета в следующем порядке, от самого высокого до самого низкого приоритета: @Around, @Before , @After, @AfterReturning, @AfterThrowing.

Вы можете просмотреть этот ответ (на основе spring-aop-5.3.3) с @Around, чтобы попытаться реализовать свой вариант использования.

person R.G    schedule 16.02.2021