springboot AOP

Spring Boot AOP(面向切面编程)是一种面向对象编程技术,它可以使代码更加模块化和可重用。它通过将横切关注点(如日志记录、性能检测等)与应用程序的主要逻辑分离开来,实现代码的分离和复用。

Spring Boot AOP的主要组件是切点和通知。切点是指一个或多个方法,这些方法可以被通知拦截并执行额外的代码。通知是指在切点方法周围执行的代码,这些代码可以在切点方法之前、之后或周围执行。Spring Boot AOP支持不同类型的通知,例如前置通知、环绕通知、后置通知和异常通知。其中最常用的是环绕通知。

使用Spring Boot AOP有两种方式,分别是非注解的方式和使用注解的方式。

首先,需要在pom.xml文件中导入以下依赖;

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

 方式一:基于非注解的方式

@Aspect
@Component
public class MyAop {
    //切入点:待增强的方法
    @Pointcut("execution(public * com.learn.controller.TeacherController.*(..)) " +
            "|| execution(public * com.learn.controller.LearnController.*(..))")
    //切入点签名
    public void log(){
        System.out.println("pointCut签名。。。");
    }
//    前置通知
    @Before("log()")
    public void deBefore(JoinPoint jp) throws Throwable {
        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 记录下请求内容
        System.out.println("URL : " + request.getRequestURL().toString());
        System.out.println("HTTP_METHOD : " + request.getMethod());
        System.out.println("CLASS_METHOD : " + jp);
        System.out.println("ARGS : " + Arrays.toString(jp.getArgs()));
        System.out.println("前置通知:方法执行前执行...");
    }
    //返回通知
    @AfterReturning(returning = "ret", pointcut = "log()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 处理完请求,返回内容
        System.out.println("返回通知:方法的返回值 : " + ret);
    }

    //异常通知
    @AfterThrowing(throwing = "ex", pointcut = "log()")
    public void throwss(JoinPoint jp, Exception ex) {
        System.out.println("异常通知:方法异常时执行.....");
        System.out.println("产生异常的方法:" + jp);
        System.out.println("异常种类:" + ex);
    }

    //后置通知
    @After("log()")
    public void after(JoinPoint jp){
        System.out.println("后置通知:最后且一定执行.....");
    }

    @Around("log()")
    public Object aroundAnnotationAdvice(ProceedingJoinPoint pjp) {
        Object rtValue = null;
        try {
            System.out.println("通知类中的aroundAnnotationAdvice方法执行了。。前置");
            rtValue = pjp.proceed(args);//明确调用切入点方法(切入点方法)
            System.out.println("通知类中的aroundAnnotationAdvice方法执行了。。返回");
            System.out.println("返回通知:"+rtValue);
            return rtValue;
        } catch (Throwable e) {
            System.out.println("通知类中的aroundAnnotationAdvice方法执行了。。异常");
            throw new RuntimeException(e);
        } finally {
            System.out.println("通知类中的aroundAnnotationAdvice方法执行了。。后置");
        }
    }
}

 方式二:基于注解的方式

首先创建一个注解类:

//表示此注解可以标注在类和方法上
@Target({ElementType.METHOD, ElementType.TYPE})
//运行时生效
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLogAnnotation {
    String desc() default " ";
}

其次在需要增强的方法上进行注解

@MyLogAnnotation(desc = "测试注解类型:helloAnnotation")

最后创建一个java类

@Aspect
@Component
public class MyAopAnnotation {
    //切入点:增强标有MyLogAnnotation注解的方法
    @Pointcut(value="@annotation(com.wch.youxia.learn.myannotation.MyLogAnnotation)")
    //切入点签名
    public void logAnnotation(){
        System.out.println("pointCut签名。。。");
    }
    //前置通知
    //注意:获取注解中的属性时,@annotation()中的参数要和deBefore方法中的参数写法一样,即myLogAnnotation
    @Before("logAnnotation() && @annotation(myLogAnnotation)")
    public void deBefore(JoinPoint jp, MyLogAnnotation myLogAnnotation) throws Throwable {
        System.out.println("前置通知:方法执行前执行...");
        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 获取注解中的属性
        System.out.println("deBefore===========>" + myLogAnnotation.desc());
        // 记录下请求内容
        System.out.println("URL : " + request.getRequestURL().toString());
    }
    //返回通知
    @AfterReturning(returning = "ret", pointcut = "logAnnotation() && @annotation(myLogAnnotation)")
    public void doAfterReturning(Object ret, MyLogAnnotation myLogAnnotation) throws Throwable {
        // 获取注解中的属性
        System.out.println("doAfterReturning===========>" + myLogAnnotation.desc());
        // 处理完请求,返回内容
        System.out.println("返回通知:方法的返回值 : " + ret);
    }

    //异常通知
    @AfterThrowing(throwing = "ex", pointcut = "logAnnotation() && @annotation(myLogAnnotation)")
    public void throwss(JoinPoint jp,Exception ex, MyLogAnnotation myLogAnnotation){
        // 获取注解中的属性
        System.out.println("throwss===========>" + myLogAnnotation.desc());
        System.out.println("异常通知:方法异常时执行.....");
        System.out.println("产生异常的方法:"+jp);
        System.out.println("异常种类:"+ex);
    }

    //后置通知
    @After("logAnnotation() && @annotation(myLogAnnotation)")
    public void after(JoinPoint jp, MyLogAnnotation myLogAnnotation){
        // 获取注解中的属性
        System.out.println("after===========>" + myLogAnnotation.desc());
        System.out.println("后置通知:最后且一定执行.....");
    }

    @Around("logAnnotation()&& @annotation(myLogAnnotation)")
    public Object aroundAnnotationAdvice(ProceedingJoinPoint pjp,MyLogAnnotation myLogAnnotation) {
        Object rtValue = null;
        try {
       
            System.out.println("通知类中的aroundAnnotationAdvice方法执行了。。前置");
            rtValue = pjp.proceed(args);//明确调用切入点方法(切入点方法)
            System.out.println("通知类中的aroundAnnotationAdvice方法执行了。。返回");
            System.out.println("返回通知:"+rtValue);
            return rtValue;
        } catch (Throwable e) {
            System.out.println("通知类中的aroundAnnotationAdvice方法执行了。。异常");
            throw new RuntimeException(e);
        } finally {
            System.out.println("通知类中的aroundAnnotationAdvice方法执行了。。后置");
        }
    }
}

可以看到,两种方式运行方法的注解与参数列表有差异

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值