当前位置:   article > 正文

基于注解的AOP(准备工作、前置通知、后置通知、返回通知、异常通知、环绕通知)_aop后置通知

aop后置通知

技术说明:

示意图如下所示:

动态代理:JDK原生的实现方式,需要被代理的目标类必须实现接口,因为这个技术要求代理对象额目标对象实现同样的接口

cglib:通过继承被代理的目标类实现代理,所有不需要目标类实现接口

AspectJ:本质上是静态代理,将代理逻辑"织入"被代理的目标类编译得到的字节码文件,所有最终效果是动态的,weaver就是织入器,Spring只是借用了AspectJ中的注解

准备工作

新创建一个Maven

 在pom.xml文件中引入依赖

 将之前的接口和目标类复制到main的java中

 创建切面类        

 创建一个配置文件

 在目标文件中引用之前的目标文件,并添加@Component注解

 在切面类添加@Component和@Aspect注解

 在配置文件中添加扫描组件进行扫描注解

 前置通知

在切面类中通过指定的注解(@Before)将方法标识为通知方法

 在spring-annotation的配置文件中添加扫描组件和基于AOP注解的功能

 在测试类中添加测试方法

 测试结果如下所示:

切入点表达式的语法和重用以及获取连接点的信息

优化切入点表达式:

在切面类中修改:

 测试方法如下所示:

测试结果如下所示: 

 对切面类的方法进行优化:

 测试结果如下:

对切入点表达式的重用 

 后置通知+返回通知+异常通知+环绕通知

在切面中,需要通过指定的注解将方法标识为通知方法:
@Before:前置通知,在目标对象方法执行之前执行

@After:后置通知,在目标对象方法的finally字句中执行

@AfterReturning:后置通知,在目标对象方法返回值之后执行

@AfterThrowing:异常通知,在目标对象方法的catch字句中执行

@Around:环绕通知,

在切面类中添加通知的方法

@Component
@Aspect //将当前组件标识为切面
public class LoggerAspect {

    //添加公共的切入点表达式
    /*
    * @Pointcut:声明一个公共的切入点表达式
    * 使用方式:@After("pointCut()")
    * */
    @Pointcut("execution(* com.spring.pojo.test.aop.annotation.CalculatorImpl.*(..))")
    public void pointCut(){

    }

    @After("pointCut()")//加入切入点表达式
    public void AfterAdviceMethod(JoinPoint joinPoint){
        System.out.println("LoggerAspect,后置通知");
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();
        Object[] args = joinPoint.getArgs();
        System.out.println("方法名:" + name);
        System.out.println("参数列表:" + Arrays.toString(args));
    }

    /*
    * 在切面中,需要通过指定的注解将方法标识为通知方法
    * @Before:前置通知,在目标对象方法执行之前执行
    * */
//    @Before("execution(public int com.spring.test.aop.annotation.CalculatorImpl.add(int,int))")//切入点表达式
    /*
    * 切入点表达式的优化:
    * 切入点表达式设置在表示通知的注解的value属性中
    * 第一个*代表:任意的访问修饰符和任意的返回类型
    * 第二个*代表:当前类中的任意方法
    * ..代表:任意的参数列表
    * 类所在的地方也可以使用*,表示包下所有的类
    * */
    @Before("execution(* com.spring.pojo.test.aop.annotation.CalculatorImpl.*(..))")
    /*
    * 获取连接点的信息:
    *   在通知方法的参数位置,设置JoinPoint类型的参数,就可以获取连接点所对应方法的信息
    *
    * */
    public void beforeAdviceMethod(JoinPoint joinPoint){
        //获取连接点所对应方法的签名信息
        Signature signature = joinPoint.getSignature();
        //获取方法名
        String name = signature.getName();
        //获取连接点所对应方法的参数
        Object[] args = joinPoint.getArgs();
        System.out.println("LoggerAspect,前置通知");
        System.out.println("LoggerAspect,方法名:" + name);
        System.out.println("LoggerAspect,参数:" + Arrays.toString(args));

    }


    //返回通知
    /*
    *在返回通知中获取目标对象方法的返回值,只需要通过@AfterReturning注解的returning属性
    *就可以将通知方法的某个参数指定为接收目标对象方法的返回值的参数
    *
    * */
    @AfterReturning(value = "pointCut()",returning = "result" )
    public void afterReturningAdviceMethod(JoinPoint joinPoint,Object result){
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();
        System.out.println("返回通知-方法名: " + name);
        System.out.println("返回通知-结果:" + result);
        System.out.println("LoggerAspect,返回通知");

    }

    //异常通知
    /*
    * 在异常通知中若需要获取目标对象方法的异常,只需要通过@AfterThrowing注解的throwing属性
    *就可以将通知方法的某个参数指定为接收目标对象方法出现的异常的参数
    * */
    @AfterThrowing(value = "pointCut()" ,throwing = "throwable")
    public void afterThrowingAdviceMethod(JoinPoint joinPoint,Throwable throwable ){
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();
        System.out.println("异常通知-方法名 :" +name);
        System.out.println("异常:" + throwable);

        System.out.println("LoggerAspect,异常通知");

    }

    //环绕通知
    @Around("pointCut()")
    //环绕通知方法的返回值一定要和目标对象方法的返回值一致
    public Object aroundAdviceMethod(ProceedingJoinPoint joinPoint){
        Object result = null;
        try {
            System.out.println("环绕通知->前置通知");
            //表示目标对象方法的执行
            result = joinPoint.proceed();
            System.out.println("环绕通知->返回通知");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("环绕通知->异常通知");
        }finally {
            System.out.println("环绕通知->后置通知");
        }

        return result;
    }

测试结果如下:

后置通知:

测试方法:

测试结果:

 

 返回通知:

测试结果:

 异常通知:

测试方法:

 测试结果:

 环绕通知:

测试方法:

 测试结果:

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/674956
推荐阅读
相关标签
  

闽ICP备14008679号