首页 > 其他分享 >@Around() 和 @Pointcut()注解的区别

@Around() 和 @Pointcut()注解的区别

时间:2024-11-14 15:16:57浏览次数:3  
标签:Around 切点 method Pointcut result println 注解 execution public

1. @Around 注解

@Around 是一种环绕通知(Around Advice),它允许你在目标方法执行前后都执行一些逻辑。这意味着你可以在方法调用之前、之后甚至在方法抛出异常时执行特定的逻辑。

示例
@Around("@annotation(myLock)")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
    // 前置逻辑
    System.out.println("Before method execution");

    // 执行目标方法
    Object result = joinPoint.proceed();

    // 后置逻辑
    System.out.println("After method execution");

    return result;
}
特点
  • 灵活性高:可以在方法调用前后执行任意逻辑。
  • 控制方法执行:可以决定是否继续执行目标方法(通过 proceed() 方法)。
  • 捕获异常:可以在方法抛出异常时捕获并处理。

2. @Pointcut 注解

@Pointcut 用于定义切点(Pointcut),即确定哪些方法需要被拦截。切点表达式可以非常灵活,可以基于方法名、类名、注解等多种条件来定义。

示例
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethods() {
}

@Before("serviceMethods()")
public void beforeServiceMethods(JoinPoint joinPoint) {
    System.out.println("Before service method execution");
}

@AfterReturning(pointcut = "serviceMethods()", returning = "result")
public void afterServiceMethods(JoinPoint joinPoint, Object result) {
    System.out.println("After service method execution, result: " + result);
}
特点
  • 定义切点:用于定义一组匹配的方法,这些方法将成为通知的目标。
  • 复用性高:可以被多个通知(如 @Before@AfterReturning@AfterThrowing@Around)共享。
  • 简化配置:避免在多个通知中重复相同的切点表达式。

区别总结

  1. 作用不同

    • @Around:定义环绕通知,可以在目标方法执行前后执行逻辑。
    • @Pointcut:定义切点,确定哪些方法需要被拦截。
  2. 使用场景不同

    • @Around:适用于需要在方法调用前后执行复杂逻辑的场景,例如事务管理、日志记录等。
    • @Pointcut:适用于需要定义一组方法作为通知目标的场景,提高代码的复用性和可维护性。
  3. 语法和参数不同

    • @Around:需要一个 ProceedingJoinPoint 参数,通过 proceed() 方法执行目标方法。
    • @Pointcut:通常没有参数,只是一个无参方法,用于定义切点表达式。

结合使用

你可以在同一个切面类中同时使用 @Pointcut@Around,以提高代码的可读性和复用性。

@Aspect
@Component
public class MyAspect {

    @Pointcut("@annotation(myLock)")
    public void myLockPointcut() {
    }

    @Around("myLockPointcut()")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        // 前置逻辑
        System.out.println("Before method execution with myLock annotation");

        // 执行目标方法
        Object result = joinPoint.proceed();

        // 后置逻辑
        System.out.println("After method execution with myLock annotation");

        return result;
    }

    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethods() {
    }

    @Before("serviceMethods()")
    public void beforeServiceMethods(JoinPoint joinPoint) {
        System.out.println("Before service method execution");
    }

    @AfterReturning(pointcut = "serviceMethods()", returning = "result")
    public void afterServiceMethods(JoinPoint joinPoint, Object result) {
        System.out.println("After service method execution, result: " + result);
    }
}

 通过这种方式,你可以更灵活地管理和复用切点表达式,使代码更加清晰和模块化。

同时,一个切面可以对多个表达式进行监听。通过在同一个切面类中定义多个 @Pointcut 方法,并在不同的通知方法中引用这些切点表达式,你可以实现对多个表达式的监听。这种方式不仅提高了代码的复用性,还使得切点表达式的管理更加清晰和集中。

示例

假设我们有一个切面类 MyAspect,需要对带有 @MyLock 注解的方法和 com.example.service 包下的所有方法进行监听。

1. 定义切点表达式

首先,在切面类中定义多个 @Pointcut 方法,每个方法对应一个切点表达式。

@Aspect
@Component
public class MyAspect {

    @Pointcut("@annotation(myLock)")
    public void myLockPointcut() {
    }

    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethodsPointcut() {
    }
}
2. 定义通知方法

接下来,在同一个切面类中定义多个通知方法,并在这些通知方法中引用相应的切点表达式。

环绕通知 (@Around)
@Around("myLockPointcut()")
public Object aroundAdviceWithMyLock(ProceedingJoinPoint joinPoint) throws Throwable {
    // 前置逻辑
    System.out.println("Before method execution with myLock annotation");

    // 执行目标方法
    Object result = joinPoint.proceed();

    // 后置逻辑
    System.out.println("After method execution with myLock annotation");

    return result;
}

@Around("serviceMethodsPointcut()")
public Object aroundAdviceForServiceMethods(ProceedingJoinPoint joinPoint) throws Throwable {
    // 前置逻辑
    System.out.println("Before service method execution");

    // 执行目标方法
    Object result = joinPoint.proceed();

    // 后置逻辑
    System.out.println("After service method execution");

    return result;
}
前置通知 (@Before)
@Before("myLockPointcut()")
public void beforeAdviceWithMyLock(JoinPoint joinPoint) {
    System.out.println("Before method execution with myLock annotation");
}

@Before("serviceMethodsPointcut()")
public void beforeAdviceForServiceMethods(JoinPoint joinPoint) {
    System.out.println("Before service method execution");
}
后置返回通知 (@AfterReturning)
@AfterReturning(pointcut = "myLockPointcut()", returning = "result")
public void afterReturningAdviceWithMyLock(JoinPoint joinPoint, Object result) {
    System.out.println("After method execution with myLock annotation, result: " + result);
}

@AfterReturning(pointcut = "serviceMethodsPointcut()", returning = "result")
public void afterReturningAdviceForServiceMethods(JoinPoint joinPoint, Object result) {
    System.out.println("After service method execution, result: " + result);
}
异常通知 (@AfterThrowing)
@AfterThrowing(pointcut = "myLockPointcut()", throwing = "ex")
public void afterThrowingAdviceWithMyLock(JoinPoint joinPoint, Throwable ex) {
    System.out.println("Exception in method execution with myLock annotation: " + ex.getMessage());
}

@AfterThrowing(pointcut = "serviceMethodsPointcut()", throwing = "ex")
public void afterThrowingAdviceForServiceMethods(JoinPoint joinPoint, Throwable ex) {
    System.out.println("Exception in service method execution: " + ex.getMessage());
}

总结

通过在同一个切面类中定义多个 @Pointcut 方法,并在不同的通知方法中引用这些切点表达式,你可以实现对多个表达式的监听。这种方式不仅提高了代码的复用性,还使得切点表达式的管理更加清晰和集中。以下是一些关键点:

  1. 定义切点表达式:使用 @Pointcut 注解定义切点表达式,每个切点表达式对应一个方法。
  2. 引用切点表达式:在通知方法中使用切点表达式的名字来引用对应的切点。
  3. 多种通知类型:可以在同一个切面类中定义多种通知类型(如 @Around@Before@AfterReturning@AfterThrowing),并分别引用不同的切点表达式。

标签:Around,切点,method,Pointcut,result,println,注解,execution,public
From: https://blog.csdn.net/m0_56088675/article/details/143772265

相关文章

  • 深入理解Spring框架中的@Async注解实现异步任务
    目录1.引言2.环境准备3.启用异步支持4.创建异步任务5.调用异步任务6.运行应用7.使用@Async需要注意的地方8.结论在现代Web应用中,异步任务的执行变得越来越重要。Spring框架提供了强大的@Async注解,可以帮助开发者轻松实现异步任务。本文将详细介绍如何在Sprin......
  • @Lazy注解解决循环依赖
    @Lazy是Spring框架中的一个注解,用于延迟一个bean的初始化,直到它第一次被使用。在默认情况下,Spring容器会在启动时创建并初始化所有的单例bean。这意味着,即使某个bean直到很晚才被使用,或者可能根本不被使用,它也会在应用启动时被创建。@Lazy注解就是用来改变这种行为的。也就是......
  • 【Java】自定义注解的使用
    什么是注解java中的,注解分为两种,元注解和自定义注解,类似于公理和定理的关系。我们常用一些注解:@Autowired、@Override等都是自定义注解。在JAVA中如何实现自定义注解?@interface关键字我们想定义一个自己的注解需要使用@interface来定义。//元注解@Target(ElementType.ME......
  • 深入理解JUnit注解:从入门到最佳实践
    深入理解JUnit注解:从入门到最佳实践一、JUnit注解基础概览1.五大核心注解JUnit提供了五个最基本也是最常用的注解:@Test@Before@After@BeforeClass@AfterClass让我们通过一个完整的示例来了解这些注解:publicclassBankAccountTest{privatestaticDatabaseConn......
  • MyBatis如何关闭一级缓存(分注解和xml两种方式)
    @目录问题:为什么有缓存什么场景下必须需要关闭一级缓存关闭一级缓存方法(针对使用MyBatis场景)第1种:注解形式(可指定仅仅某个Mapper关闭注解)第2种:sql动态拼接传入的随机数问题:为什么有缓存mybatis默认开启一级缓存什么场景下必须需要关闭一级缓存场景:执行2次相同sql,但是第一次......
  • 解锁Java编程新高度!用validate注解做校验,让你的代码更高效、更安全!
    在Java中,@Valid注解通常用于验证对象的属性。它通常与Spring框架一起使用,以自动触发对JavaBean的验证。以下是如何使用@Valid注解进行校验的详细步骤和示例代码:1.添加依赖首先,确保你的项目中包含了SpringBoot的starter-web依赖,因为我们需要用到Spring的验证功能。<depend......
  • 后端数据校验注解不可用
    解决方法:    1.导入依赖,版本与springboot一致<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId><version>${spring-boot-starter-validation}</version>......
  • MyBatis Plus之注解实现动态SQL
     参考下面的sql语句即可实现@Select("<script>"+"selectgp.TEWRTYR,gp.FJFNM,gs.CVNNN,u.VCNBMBNV,gp.RAEER,gr.BVNCCVN\n"+"fromUPPBHTu\n"+"leftjoinGP_testgp\n"+......
  • 【SpringCloud】SpringBoot集成Swagger 常用Swagger注解
    概述:SpringBoot集成Swagger常用Swagger注解导语相信无论是前端还是后端开发,都或多或少地被接口文档折磨过。前端经常抱怨后端给的接口文档与实际情况不一致。后端又觉得编写及维护接口文档会耗费不少精力,经常来不及更新。其实无论是前端调用后端,还是后端调用后端,都期望有......
  • 【Spring IoC&DI】IoC容器,IoC注解,Bean的使用
    【Spring核心思想:IoC】spring是一个开源框架,支持广泛的应用场景,简而言之:Spring是包含了众多工具方法的IoC容器【IoC】IoC的意思是「控制反转」,也就是说Spring是一个“控制反转”的容器通用程序的实现代码,类的创建顺序是反的,如果想改tire需要连同之前的一起改,很麻烦改......