自学内容网 自学内容网

Spring学习笔记_23——切面其他注解

切面中的其他注解

1. @Pointcut注解

@Pointcut注解可以指定切入点表达式,在使用Spring注解开发AOP程序时,如果需要执行多个通知,并且使用AOP增强的功能确定的情况下,就可以使用@Pointcut注解将切入点表达式通用化。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Pointcut {
    // 表示指定的切入点表达式
    String value() default "";
    // 表示指定的切入点表达式的参数,
    // 参数可以是execution中的,也可以是args中的,并且不使用这个属性也可以获得切入点的方法参数
    String argNames() default "";
}

2. @Before注解

@Before注解指定方法为前置通知,指定为前置通知的方法在切入点方法之前执行。

在实际开发项目的过程中,如果需要在切入点方法之前执行一些业务逻辑处理,就可以使用@Before注解指定前置通知的方法,让前置通知的方法在切入点方法之前执行。

如果在前置通知的方法中需要获取切入点方法中的参数进行处理时,就需要配合使用切入点表达式参数。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Before {
    // 表示指定切入点表达式,可以是表达式,也可以是表达式的引用
    String value();
    // 表示指定切入点表达式参数的名称。要求和切入点表达式中的参数名称一致。
    // 如果不指定切入点表达式参数的名称,一般情况下也可以获取切入点方法的参数内容。
    String argNames() default "";
}

3. @After注解

@After注解主要指定最终的通知,如果在实际项目的开发过程中,需要指定最终通知的执行时机,并且需要在切入点方法完成之后执行,无论切入点方法的执行是否抛出异常,都要执行最终的通知方法,就可以使用@After注解标注最终通知的方法。

使用@After注解标注的方法也可以用来执行一些清理工作。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface After {
    // 表示指定切入点表达式,可以是表达式,也可以是表达式的引用
    String value();
    // 表示指定切入点表达式参数的名称。要求和切入点表达式中的参数名称一致。
    // 如果不指定切入点表达式参数的名称,一般情况下也可以获取切入点方法的参数内容。
    String argNames() default "";
}

4. @AfterReturning注解

@AfterReturning注解可以配置后置增强切入点方法。

在实际项目的开发过程中,比如提交事务、记录访问日志等等功能都可以使用@AfterReturning注解的后置通知实现。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AfterReturning {
    // 表示指定切入点表达式,可以是表达式,也可以是表达式的引用
    String value() default "";
    // 表示指定切入点表达式,可以是表达式,也可以是表达式的引用
    String pointcut() default "";
    // 表示指定切入点方法返回值的变量名称,需要注意的是,指定的名称需要和切入点方法返回值名称一致。
    String returning() default "";
    // 表示指定切入点表达式参数的名称。要求和切入点表达式中的参数名称一致。
    // 如果不指定切入点表达式参数的名称,一般情况下也可以获取切入点方法的参数内容
    String argNames() default "";
}

5. @AfterThrowing注解

@AfterThrowing 是Spring AOP(面向切面编程)中的一个注解,用于定义一个异常通知(advice),它会在目标方法抛出异常后执行。

这个注解可以确保在方法抛出异常时运行一个通知,这对于异常处理和日志记录非常有用。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AfterThrowing {
     // 一个切入点表达式(pointcut expression),它定义了哪些方法的执行会触发通知(advice)。
    // 如果不指定value属性,那么可以使用pointcut属性来指定切入点表达式。
    // 默认值为空字符串,意味着如果不设置value,则必须设置pointcut。
    String value() default "";
    // pointcut 属性同样用于定义切入点表达式,它提供了另一种方式来指定触发通知的方法。
    // 
    String pointcut() default "";
    // 用于指定一个参数名,这个参数会作为通知方法的一个参数,代表抛出的异常对象。
    // 在通知方法中,你可以通过这个参数名访问到实际抛出的异常。
    // 默认值为空字符串,如果未指定,那么在通知方法中将没有代表异常的参数。
    String throwing() default "";
}

6. @Around注解

@Around 注解是 AspectJ 框架中的一个切面注解,用于定义环绕通知(around advice)。

它允许你在目标方法执行前后进行一些额外的操作,例如日志记录、性能监控、事务管理等。下面是 @Around 注解的详细介绍和源码。

package org.aspectj.lang.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Around {
    // 用于定义切入点表达式,如果不指定,则必须通过 pointcut 属性指定。
    String value() default "";
    // 用于定义参数名,这是可选的
    String argNames() default "";
}

7. Demo

配置类

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
}

定义切面

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.Throwable;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    // 定义切入点,匹配com.example.service包下的所有方法
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceLayer() {}

    // 在方法执行前执行
    @Before("serviceLayer()")
    public void beforeAdvice(JoinPoint joinPoint) {
        System.out.println("Before method: " + joinPoint.getSignature().getName());
    }

    // 在方法执行后执行
    @After("serviceLayer()")
    public void afterAdvice() {
        System.out.println("After method");
    }

    // 在方法成功执行后执行
    @AfterReturning(pointcut = "serviceLayer()", returning = "result")
    public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
        System.out.println("After method returned: " + result);
    }

    // 在方法抛出异常后执行
    @AfterThrowing(pointcut = "serviceLayer()", throwing = "error")
    public void afterThrowingAdvice(JoinPoint joinPoint, Throwable error) {
        System.out.println("After method threw exception: " + error.getMessage());
    }

    // 在方法执行前后执行,可以控制方法的执行
    @Around("serviceLayer()")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        System.out.println("Method started: " + joinPoint.getSignature().getName());
        Object result = joinPoint.proceed();
        long timeTaken = System.currentTimeMillis() - startTime;
        System.out.println("Method finished: " + joinPoint.getSignature().getName() + " took " + timeTaken + " ms");
        return result;
    }
}

使用切面

package com.example.service;

import org.springframework.stereotype.Service;

@Service
public class MyService {
    public String performAction() {
        return "Action performed";
    }

    public String performActionWithException() throws Exception {
        throw new Exception("Something went wrong");
    }
}


原文地址:https://blog.csdn.net/LuckyLay/article/details/143490173

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!