基于注解的Spring AOP

Posted 天河一粟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于注解的Spring AOP相关的知识,希望对你有一定的参考价值。

基于注解的Spring AOP

  1. 常用的注解

    注解解释
    @Before该通知方法会在目标方法执行之前执行
    @AfterReturning该通知方法会在目标方法执行完返回后执行
    @After该通知方法会在目标方法返回或抛出异常后执行
    @Around该通知方法将目标方法封装起来,环绕通知
    @AfterThrowing该通知方法会在目标方法抛出异常后执行
    @Pointcut通用切入点
  2. @Pointcutexecution语法

    execution(<修饰符模式>? <返回类型模式> <方法名模式>(<参数模式>) <异常模式>?)

    带有?的模式可以省略掉
    多种语法可以使用&&、 ||、 !连接

  3. @Pointcut之其它语法

    语法解释
    execution用于匹配方法执行的连接点
    within用于匹配指定类型内的方法执行
    this用于匹配当前AOP代理对象类型的执行方法
    args用于匹配当前执行的方法传入的参数为指定类型的执行方法
    @within用于匹配所有持有指定注解类型类的方法(注解在类上)
    @annotation用于匹配当前执行方法持有指定注解的方法(注解在方法上)
  4. 代码示例
    完整代码示例

    package sky.jin.aspect.aspect;
    
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    import sky.jin.aspect.annotaion.UnknownException;
    
    /**
     * 切面
     *
     * @author sky.jin
     * @date 2022/2/7 15:35
     */
    @Slf4j
    @Aspect
    @Component
    public class MyAspect 
    
        /**
         * execution(<修饰符模式>? <返回类型模式> <方法名模式>(<参数模式>) <异常模式>?)
         *
         * - execution:用于匹配方法执行的连接点;
         * - within:用于匹配指定类型内的方法执行;
         * - this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口类型匹配;
         * - target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口类型匹配;
         * - args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;
         * - @within:用于匹配所以持有指定注解类型内的方法;
         * - @target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
         * - @args:用于匹配当前执行的方法传入的参数持有指定注解的执行;
         * - @annotation:用于匹配当前执行方法持有指定注解的方法;
         *
         */
        // 组合方式 &&、 ||、 !
        // 指定 aspect 包和子包的任意方法的执行
    //    @Pointcut(value = "execution(* sky.jin.aspect..*(..))")
        // 任意公共方法的执行
    //    @Pointcut(value = "execution(public * sky.jin.aspect..*(..))")
        // 任何一个以“queryNameBy”开始的方法的执行
    //    @Pointcut(value = "execution(* queryNameBy*(..))")
        // 指定 AspectService 接口的任意方法的执行
    //    @Pointcut(value = "execution(* sky..aspect.service.AspectService.*(..))")
        // 指定 service 包任意类方法的执行
    //    @Pointcut(value = "execution(* sky..aspect.service.*(..))")
        // 指定 service 包和子包任意类方法的执行
    //    @Pointcut(value = "execution(* sky..aspect.service..*(..))")
        // 指定 controller 包任意类方法的执行
    //    @Pointcut(value = "within(sky.jin.aspect.controller.*)")
        // 指定 aspect 包和子包任意类方法的执行
    //    @Pointcut(value = "within(sky.jin.aspect..*)")
        // 实现了AspectController接口的所有类,如果AspectController不是接口,限定AspectController单个类
    //    @Pointcut(value = "this(sky.jin.aspect.controller.AspectController)")
        // 实现了AspectService接口的所有类,如果AspectService不是接口,限定SAspectService单个类
    //    @Pointcut(value = "this(sky.jin.aspect.service.AspectService)")
        // 带有@UnknownException注解的所有类的任意方法
    //    @Pointcut(value = "@within(sky.jin.aspect.annotaion.UnknownException)")
        // 带有@UnknownException注解的所有类的任意方法 ×(没有调通)
    //    @Pointcut(value = "@target(sky.jin.aspect.annotaion.UnknownException)")
        // 带有@UnknownException注解的任意方法
    //    @Pointcut(value = "@annotation(sky.jin.aspect.annotaion.UnknownException)")
        // 参数带有@PathVariable注解的任意方法 ×(没有调通)
    //    @Pointcut(value = "@args(org.springframework.web.bind.annotation.PathVariable)")
        @Pointcut(value = "within(sky.jin.aspect..*) && args(Long, ..)") // 参数为String类型(运行时决定)的方法
        public void point()
    
        /**
         * 该通知方法会在目标方法执行之前执行
         */
        @Before(value = "point()", argNames = "jp")
        public void before(JoinPoint jp) 
            log.info("===> 前置通知 MyAfterThrowing before jp =  params = ", jp, jp.getArgs());
        
    
        /**
         * 该通知方法会在目标方法执行完返回后执行
         */
        @AfterReturning("point()")
        public void afterReturning(JoinPoint jp) 
            log.info("===> 后置通知 MyAfterThrowing afterReturning jp =  params = ", jp, jp.getArgs());
        
    
        /**
         * 通知方法会在目标方法返回或抛出异常后执行
         */
        @After("point()")
        public void after(JoinPoint jp) 
            log.info("===> 后置或异常通知 MyAfterThrowing after jp = ", jp);
        
    
        /**
         * 该通知方法将目标方法封装起来,环绕通知
         */
        @Around(value = "point()", argNames = "jp")
        public Object around(ProceedingJoinPoint jp) throws Throwable 
            log.info("===> 环绕通知开始 MyAfterThrowing around begin jp = ", jp);
            Object proceed = jp.proceed();
            log.info("===> 环绕通知结束 MyAfterThrowing around end jp = ", jp);
            return proceed;
        
    
        /**
         * 该通知方法会在目标方法抛出异常后执行
         * - @annotation:用于匹配当前执行方法持有指定注解的方法
         */
        @AfterThrowing(throwing = "e", pointcut = "@annotation(unknownException)")
        public void afterThrowing_annotation(JoinPoint jp, Throwable e, UnknownException unknownException) 
            log.info("===> 异常通知 MyAfterThrowing afterThrowing_annotation jp =  unknownException =  ", jp, unknownException);
        
    
        /**
         * 该通知方法会在目标方法抛出异常后执行
         */
        @AfterThrowing(throwing = "e", pointcut = "point()")
        public void AfterThrowing(JoinPoint jp, Throwable e) 
            log.info("===> 异常通知 MyAfterThrowing AfterThrowing jp = ", jp);
        
    
    

以上是关于基于注解的Spring AOP的主要内容,如果未能解决你的问题,请参考以下文章

spring学习5:基于注解实现spring的aop

基于Spring AOP实现对外接口的耗时监控

Spring_Aop的xml和注解的使用

Spring事务

spring

spring