Java

Java Spring-AOP切面的优先级和切点表达式

2020-01-31  本文已影响0人  一亩三分甜

可以使用@Order注解指定切面的优先级,值越小优先级越高

在同一个连接点上应用不止一个切面时,除非明确指定,否则它们的优先级是不确定的。切面的优先级可以通过实现Ordered接口或利用@Order注解指定。

public interface ArithmeticCalculator {
    int add(int i, int j);
    int sub(int i, int j);
    int mul(int i, int j);
    int div(int i, int j);
}

@Component
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
    @Override
    public int add(int i, int j) {
        int result = i + j;
        return result;
    }

    @Override
    public int sub(int i, int j) {
        int result = i - j;
        return result;
    }

    @Override
    public int mul(int i, int j) {
        int result = i * j;
        return result;
    }

    @Override
    public int div(int i, int j) {
        int result = i / j;
        return result;
    }
}

//把这个类声明为一个切面:需要把该类放入到IOC容器中、再声明为一个切面
@Order(2)
@Aspect
@Component
public class LoggingAspect {

    //声明该方法是一个前置通知:在目标方法开始之前执行
    @Before("execution(public int com.cloud.spring.aop.impl.ArithmeticCalculator.*(int,int))")
    public void beforeMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        System.out.println("The method " + methodName + " begins with" + args);
    }

    //后置通知:在目标方法执行后(无论是否发生异常),执行的通知
    //在后置通知中还不能访问目标方法执行的结果
    @After("execution(* com.cloud.spring.aop.impl.*.*(int,int))")
    public void afterMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " ends");
    }

    /*
    * 在方法正常结束之后执行的代码
    * 返回通知是可以访问到方法的返回值的!
    */
    @AfterReturning(value = "execution(* com.cloud.spring.aop.impl.*.*(..))",returning = "result")
    public void afterReturing(JoinPoint joinPoint,Object result){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " ends with " + result);
    }
     /*
     *  在目标方法出现异常时会执行的代码
     *  可以访问到异常对象,且可以指定在出现特定异常时再执行通知代码
     */
    @AfterThrowing(value = "execution(* com.cloud.spring.aop.impl.*.*(..))",throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint,Exception ex){
        String  methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " occurs exception with " + ex);
    }

    /*
    * 环绕通知需要携带ProceedingJointPoint 类型的参数
    * 环绕通知类似于动态代理的全过程:ProceedingJointPoint 类型的参数可以决定是否执行目标方法。
    * 且环绕通知必须有返回值,返回值即为目标方法的返回值
    */
    @Around("execution(* com.cloud.spring.aop.impl.*.*(..))")
    public Object aroundMethod(ProceedingJoinPoint pjd){
        Object result = null;
        String methodName = pjd.getSignature().getName();
        try {
            //前置通知
            System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
            //执行目标方法
            result = pjd.proceed();
            //返回通知
            System.out.println("The method " + methodName + " ends with " + result);
        }catch (Throwable e){
            //异常通知
            System.out.println("The method " + methodName + " occurs exception: " + e);
            throw new RuntimeException(e);
        }
        System.out.println("The method " + methodName + " ends ");
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        //1.创建Spring的IOC容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.从IOC容器中获取bean的实例
        ArithmeticCalculator arithmeticCalculator = context.getBean(ArithmeticCalculator.class);
        //3.使用bean
        int result = arithmeticCalculator.add(3,6);
        System.out.println("result:" + result);

        result = arithmeticCalculator.div(9,3);
        System.out.println("result:" + result);
    }
}

@Order(1)
@Aspect
@Component
public class ValidationAspect {

    @Before("execution(public int com.cloud.spring.aop.impl.ArithmeticCalculator.*(..))")
    public void validateArgs(JoinPoint joinPoint){
        System.out.println("--> validate: " + Arrays.asList(joinPoint.getArgs()));
    }
}
//输出
Connected to the target VM, address: '127.0.0.1:51995', transport: 'socket'
--> validate: [3, 6]
The method add begins with [3, 6]
The method add begins with[3, 6]
The method add ends with 9
The method add ends 
The method add ends
The method add ends with 9
result:9
--> validate: [9, 3]
The method div begins with [9, 3]
The method div begins with[9, 3]
The method div ends with 3
The method div ends 
The method div ends
The method div ends with 3
result:3

重用切点表达式:定义一个方法,用于声明切入点表达式,一般地,该方法中再不需要填入其他的代码。使用Pointcut来声明切入点表达式。后面的其他通知直接使用方法名来引用当前的切入点表达式。

//把这个类声明为一个切面:需要把该类放入到IOC容器中、再声明为一个切面
@Order(2)
@Aspect
@Component
public class LoggingAspect {

    /*
    * 定义一个方法,用于声明切入点表达式。一般地,该方法中再不需要添入其他的代码。
    * 使用@Pointcut来声明切入点表达式
    * 后面的其他通知直接使用方法名来引用当前的切入点表达式
    */
    @Pointcut("execution(public int com.cloud.spring.aop.impl.ArithmeticCalculator.*(..))")
    public void declareJointPointExpression(){}

    //声明该方法是一个前置通知:在目标方法开始之前执行
    @Before("declareJointPointExpression()")
    public void beforeMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        System.out.println("The method " + methodName + " begins with" + args);
    }

    //后置通知:在目标方法执行后(无论是否发生异常),执行的通知
    //在后置通知中还不能访问目标方法执行的结果
    @After("declareJointPointExpression()")
    public void afterMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " ends");
    }

    /*
    * 在方法正常结束之后执行的代码
    * 返回通知是可以访问到方法的返回值的!
    */
    @AfterReturning(value = "declareJointPointExpression()",returning = "result")
    public void afterReturing(JoinPoint joinPoint,Object result){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " ends with " + result);
    }
     /*
     *  在目标方法出现异常时会执行的代码
     *  可以访问到异常对象,且可以指定在出现特定异常时再执行通知代码
     */
    @AfterThrowing(value = "declareJointPointExpression()",throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint,Exception ex){
        String  methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " occurs exception with " + ex);
    }

    /*
    * 环绕通知需要携带ProceedingJointPoint 类型的参数
    * 环绕通知类似于动态代理的全过程:ProceedingJointPoint 类型的参数可以决定是否执行目标方法。
    * 且环绕通知必须有返回值,返回值即为目标方法的返回值
    */
    @Around("declareJointPointExpression()")
    public Object aroundMethod(ProceedingJoinPoint pjd){
        Object result = null;
        String methodName = pjd.getSignature().getName();
        try {
            //前置通知
            System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
            //执行目标方法
            result = pjd.proceed();
            //返回通知
            System.out.println("The method " + methodName + " ends with " + result);
        }catch (Throwable e){
            //异常通知
            System.out.println("The method " + methodName + " occurs exception: " + e);
            throw new RuntimeException(e);
        }
        System.out.println("The method " + methodName + " ends ");
        return result;
    }
}
//输出
Connected to the target VM, address: '127.0.0.1:52041', transport: 'socket'
--> validate: [3, 6]
The method add begins with [3, 6]
The method add begins with[3, 6]
The method add ends with 9
The method add ends 
The method add ends
The method add ends with 9
result:9
--> validate: [9, 3]
The method div begins with [9, 3]
The method div begins with[9, 3]
The method div ends with 3
The method div ends 
The method div ends
The method div ends with 3
result:3
上一篇 下一篇

猜你喜欢

热点阅读