在本文中,我们将通过示例详细讨论 AOP 切入点表达式。
什么是切入点表达式 spring AOP中的切入点是基于一个称为切入点表达式的表达式来定义的。
这有助于根据表达式中指定的条件查找一组连接点。这些条件有助于定位特定的包、方法、类、注释和 bean。
- 切入点指示符 (PCD):PCD(上面以突出显示)有助于将方法、类、包、bean 和注释精确定位为连接点。
- 表达式条件:它(非突出显示)有助于识别哪个特定类、方法、bean 或注释用作连接点。每个PCD具有不同的表达式条件语法。
不同的PCD及其表达式条件语法:
1、execution : 最常用的 PCD,主要用于根据方法查找连接点。 语法: modifiers-pattern? return-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?
这里的修饰符模式(modifiers-pattern)、声明类型模式(declaring-type-pattern)和抛掷模式(throws-pattern)是可选的:
- modifiers-pattern:指定要匹配的方法的访问修饰符。例如,公共、受保护、私有以及*(如有)。
- return-type-pattern:指定要匹配的方法的返回类型,例如void、int、String、Object。* 如果是任何返回类型。
- declaring-type-pattern:它指定声明方法的类型或完全限定类名,例如 com.sample.aopdemo.service.MyServiceImpl 和 * 表示任何类型。
- name-pattern:它指定要匹配的方法的名称,例如,getSum 和* 表示任何方法名称。
- param-pattern:指定要匹配的方法的参数类型,例如,int、String、* 表示任意参数类型,.. 表示任意数量的参数。
- throws-pattern:它指定要匹配的方法抛出的异常的完整限定类名,例如 com.sample.aopdemo.exception.CoderStuffException 和 * 表示任何异常。
execution(public int com.sample.aopdemo.service.MyServiceImpl.getSum(int,int)) // 它将 aopdemo.service.MyServiceImpl 类中的 getSum 方法视为 joipoint,该方法接受 2 个 int 类型参数,并具有公共访问修饰符。 execution(public int com.sample.aopdemo.service.MyServiceImpl.getSum(..)) // 这与前面的示例相同,唯一不同的是 getSum 方法可以接受任意数量的参数。 execution(public int com.sample.aopdemo.service.MyServiceImpl.getException() throws com.sample.aopdemo.exception.CoderStuffException) //在这里,我们将 com.sample.aopdemo.service.MyServiceImpl 类中的 getException() 方法视为连接点,该 getException 方法必须抛出 com.sample.aopdemo.exception.CoderStuffException 异常。 |
但也可以根据包和类来搜索连接点。示例:
execution(public * com.sample.aopdemo.controller.MyAppController.*()) //此表达式将 MyAppController 类中的所有方法都视为连接点。 execution(public * com.sample.aopdemo.controller.*.*()) //此表达式将 com.sample.aopdemo.controller 内所有类中的所有方法都视为连结点。 |
2、within : 它将指定软件包或类中的所有方法视为连接点。 语法:within(full qualified class name) 示例:
within(com.sample.aopdemo.service.MyServiceImpl) // 它将 com.sample.aopdemo.MyServiceImpl 类中的所有方法都视为连结点。 within(com.sample.aopdemo.service.*) // 它将 com.sample.aopdemo.service 包内所有类中的所有方法都视为连结点。 |
3、bean 它将指定 bean 中定义的所有方法都视为连接点。 语法:bean(bean name)
bean(coderstuffservice) |
这会将名为 coderstuffservice 的 bean 中的所有方法都视为连接点。
4、this 它将所有方法都视为指定类实例中的连接点。 语法:this(class qualified name)
this(com.sample.aopdemo.service.MyServiceIntf) |
com.sample.aopdemo.service.MyServiceIntf 是一个接口,其实现由 com.sample.aopdemo.service.MyServiceImpl 类提供。因此它将 com.sample.aopdemo.service.MyServiceImpl 类中的所有方法都视为连结点。
5、annotation 它将所有在其上有指定注解的方法都视为连接点。 语法:@annotation(annotation-type-pattern)
@annotation(org.springframework.web.bind.annotation.GetMapping) |
@Pointcut 在 Spring AOP 中,我们还可以创建一个命名的快捷方式,以便在应用代码中重复使用。@Pointcut 注解有助于实现这一目的。使用 @Pointcut 注解,我们可以为一个点切口命名,并通过其名称重复使用它。示例
@Pointcut("execution(public int *.*.aopdemo.service.MyServiceImpl.*(..))") public void logBeforeMethodExecutionPointCut(){ } @Before("logBeforeMethodExecutionPointCut()") public void logBeforeMethodExecution(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().toShortString(); Object[] args = joinPoint.getArgs(); log.info("Executing "+methodName+" with "+args.length+" arguments "+ Arrays.toString(args)); } /*output** Executing MyServiceImpl.getSum(..) with 2 arguments [4, 5] Executing MyServiceImpl.multiply(..) with 2 arguments [4, 5] Executing MyServiceImpl.getException() with 0 arguments [] */ |
我们可以使用 &&、|| 和 .NET,在一个点切表达式中组合多个点切条件!操作符。示例 :
@Before("this(com.sample.aopdemo.service.MyServiceIntf) && !execution(public int com.sample.aopdemo.service.MyServiceImpl.getSum(int,int))" |
在这里,它会考虑类中所有 com.sample.aopdemo.service.MyServiceIntf 类型的方法,但不会考虑 public int com.sample.aopdemo.service.MyServiceImpl.getSum(int,int) 方法。