0
点赞
收藏
分享

微信扫一扫

【Linux】基于Udp的简易服务端和客户端

书写经典 2024-05-06 阅读 10

目录

Spring AOP详解

@PointCut

切面优先级@Order

切点表达式

execution表达式

切点表达式示例

@annotation

 自定义注解@MyAspect

 切面类

添加自定义注解


Spring AOP详解

@PointCut

上面代码存在一个问题, 就是对于excution(* com.example.demo.controller.*.*(..))的大量重复使用, Spring提供了@PointCut注解, 把公共的切点表达式提取出来, 需要用到时引入切点表达式即可.

@Slf4j
@Component
@Aspect
public class AspectDemo {
    //声明一个切点
    @Pointcut("execution(* com.bite.aop.controller.*.*(..))")
    public void pt(){}; //切点名称:pt()

    @Before("pt()")
    public void doBefore() {
        //此处省略...
    }

    @After("pt()")
    public void doAfter() {
        //此处省略...
    }

    @Around("pt()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        //此处省略...
    }

    @AfterReturning("pt()")
    public void doAfterReturning() {
        //此处省略...
    }
}

 当切点定义为private修饰时, 仅能在当前切面类使用, 当其他切面类也要使用当前切点定义时, 就需要把private改为public. 引用方式为: 全限定类名.方法名()

使用示例:

@Slf4j
@Aspect
@Component
public class AspectDemo2 {
    //前置通知
    @Before("com.example.demo.aspect.AspectDemo.pt()")
    public void doBefore() {
        log.info("卢本伟牛逼");
    }
}

切面优先级@Order

当我们在一个项目中, 定义了多个切面类时, 并且这些切面类的多个切入点都匹配到了同一个目标方法. 当目标方法运行的时候, 这些切面类中的通知方法都会执行, 那么这些通知方法的执行顺序是怎样的呢?

还是通过程序求证:

定义多个切面类如下:

@Component
public class AspectDemo2 {
    @Pointcut("execution(* com.example.demo.controller.*.*(..))")
    private void pt(){}
    //前置通知
    @Before("pt()")
    public void doBefore() {
        log.info("执⾏ AspectDemo2 -> Before ⽅法");
    }
    //后置通知
    @After("pt()")
    public void doAfter() {
        log.info("执⾏ AspectDemo2 -> After ⽅法");
    }
}

@Component
public class AspectDemo3 {
    @Pointcut("execution(* com.example.demo.controller.*.*(..))")
    private void pt(){}
    //前置通知
    @Before("pt()")
    public void doBefore() {
        log.info("执⾏ AspectDemo3 -> Before ⽅法");
    }
    //后置通知
    @After("pt()")
    public void doAfter() {
        log.info("执⾏ AspectDemo3 -> After ⽅法");
    }
}

@Component
public class AspectDemo4 {
    @Pointcut("execution(* com.example.demo.controller.*.*(..))")
    private void pt(){}
    //前置通知
    @Before("pt()")
    public void doBefore() {
        log.info("执⾏ AspectDemo4 -> Before ⽅法");
    }
    //后置通知
    @After("pt()")
    public void doAfter() {
        log.info("执⾏ AspectDemo4 -> After ⽅法");
    }
}

运行指定接口,可以得到日志:

 但是哥们不想这么搞, 哥们想让它们按照哥们的想法排序, 到这里我们就可以使用@Order来对切面优先级排序.

使用方式如下:

@Aspect
@Component
@Order(2)
public class AspectDemo2 {
    //代码省略...
}

@Aspect
@Component
@Order(1)
public class AspectDemo3 {
    //代码省略...
}


@Aspect
@Component
@Order(3)
public class AspectDemo4 {
    //代码省略...
}

执行结果如下:

 @Order控制切面的优先级控制切面的优先级, 先执行优先级较高的切面, 在执行优先级较低的切面, 最终执行目标方法.

切点表达式

上面的代码中, 我们一直在使用切点表达式来描述切点,  下面我们来介绍一下切点表达式的语法.

切点表达式常见有两种表达方式

execution表达式

execution()作为常用的表达式, 语法为:

其中: 访问修饰符和异常可以省略

切点表达式支持通配符表达:

切点表达式示例

TestController下的public 修饰, 返回类型为String方法名为t1, 无参方法

execution(public String com.example.demo.controller.TestController.t1())

省略访问修饰符:

​execution(String com.example.demo.controller.TestController.t1())

匹配所有类型:

execution(* com.example.demo.controller.TestController.t1())

匹配TestController下的所有无参方法:

execution(* com.example.demo.controller.TestController.*())

匹配TestController下的所有方法

​execution(* com.example.demo.controller.TestController.*(..))

匹配controller包下所有类的所有方法:

​​execution(* com.example.demo.controller.*.*(..))

匹配所有包下的TestController

​execution(* com..TestController.*(..))

@annotation

execution表达式更适用于有规则的, 如果我们要匹配出多个无规则的方法呢? 比如: 匹配TestController中的t1(), 和UserController中的u1()这两个方法.

这个时候使用execution就不是很方便了, 因此这里引入@annotation来表示这一类的切点

实现步骤:

准备测试代码:

@Slf4j
@RequestMapping("/test")
@RestController
public class TestController {
    @MyAspect
    @RequestMapping("/t1")
    public String t1() {
        log.info("执行t1方法...");
        return "t1";
    }

    @RequestMapping("/t2")
    public boolean t2() {
        log.info("执行t2方法");
        return true;
    }
}

@Slf4j
@RequestMapping("/user")
@RestController
public class UserController {
    @RequestMapping("/u1")
    public String u1() {
        log.info("执行u1方法...");
        return "u1";
    }

    @MyAspect
    @RequestMapping("/u2")
    public boolean u2() {
        log.info("执行u2方法");
        return true;
    }
}
 自定义注解@MyAspect

创建一个注解类:

定义如下代码:

//注解类型
@Target({ElementType.METHOD})
//注解生命周期
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAspect {

}

这里只做简单说明, 不必深究:

 切面类

使用@annotation切点表达式定义切点, 只对@MyAspect生效.

切面类代码如下:

@Slf4j
@Component
@Aspect
public class MyAspectDemo {
    //前置通知
    @Before("@annotation(com.example.demo.aspect.MyAspect)")
    public void before() {
        log.info("MyAspect -> before ...");
    }

    //后置通知
    @After("@annotation(com.example.demo.aspect.MyAspect)")
    public void after() {
        log.info("MyAspect -> after ...");
    }    
}
添加自定义注解

在TestController中的t1()和 UserController中的u1()这两个方法上添加自定义注解 @MyAspect.

    @MyAspect
    @RequestMapping("/t1")
    public String t1() {
        log.info("执行t1方法...");
        return "t1";
    }

    @MyAspect
    @RequestMapping("/u2")
    public boolean u2() {
        log.info("执行u2方法");
        return true;
    }

顺利执行.

举报

相关推荐

0 条评论