spring-aop常用切点表达式

AOP是spring的最重要模块之一,关于AOP的原理,主要就是基于动态代理,可以查看官网Understanding AOP Proxies,本节内容不去深究AOP原理,仅仅列出在spring框架中编写AOP代码时,常用的切点表达式写法,官网上关于AOP这一节的说明,也可以看下,一定会有收获Aspect Oriented Programming with Spring本文也是基于官方文档形成的。

需要说明的是在spring框架中共用了AspectJ的一些注解,且目前仅支持方法级别的增强,AspectJ支持更多的切点表达式,在本文例子中也不去详述,想要了解的可以去看The AspectJTM Programming Guide

由于本文的重点在于切点表达式的例子,所以本文所采用的增强方式一般以环绕增强为主。

1. spring-aop支持的切点表达式关键字

官网很明确的说明了spring支持哪些切点表达式关键字,如下:

Spring AOP supports the following AspectJ pointcut designators (PCD) for use in pointcut expressions:

  • execution: For matching method execution join points. This is the primary pointcut designator to use when working with Spring AOP.
  • within: Limits matching to join points within certain types (the execution of a method declared within a matching type when using Spring AOP).
  • this: Limits matching to join points (the execution of methods when using Spring AOP) where the bean reference (Spring AOP proxy) is an instance of the given type.
  • target: Limits matching to join points (the execution of methods when using Spring AOP) where the target object (application object being proxied) is an instance of the given type.
  • args: Limits matching to join points (the execution of methods when using Spring AOP) where the arguments are instances of the given types.
  • @target: Limits matching to join points (the execution of methods when using Spring AOP) where the class of the executing object has an annotation of the given type.
  • @args: Limits matching to join points (the execution of methods when using Spring AOP) where the runtime type of the actual arguments passed have annotations of the given types.
  • @within: Limits matching to join points within types that have the given annotation (the execution of methods declared in types with the given annotation when using Spring AOP).
  • @annotation: Limits matching to join points where the subject of the join point (the method being executed in Spring AOP) has the given annotation.

至于官方暂时不支持的切点表达式关键字,也列举出来了,还表示将来的版本可能会支持更多的关键字:

Other pointcut types

The full AspectJ pointcut language supports additional pointcut designators that are not supported in Spring: call, get, set, preinitialization, staticinitialization, initialization, handler, adviceexecution, withincode, cflow, cflowbelow, if, @this, and @withincode. Use of these pointcut designators in pointcut expressions interpreted by Spring AOP results in an IllegalArgumentException being thrown.

The set of pointcut designators supported by Spring AOP may be extended in future releases to support more of the AspectJ pointcut designators.

切点表达式之间支持&&, || ! 连接,连接时候可以采用具体的表达式,也可以采用pointcut注解对应的方法签名:比如在spring中自定义注解中用到的myAnnoCut()&&myPointCut()

2. 常用切点表达式

采用execution关键字定义的切点表达式格式如下:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)
                throws-pattern?)

表达式中除了返回值类型匹配规则ret-type-pattern (通常是 *来匹配所有返回值类型)之外的其他类型匹配规则都是可选的

name-pattern方法名,可以是具体的方法名,也可以用*圈定所有方法

param-pattern方法入参:()匹配无参方法,(..)匹配多参数方法,(*)匹配单参数任意入参类型的方法,(*,String)匹配有两个入参的方法,第一个可以是任意类型,第二个必须是字符串类型。

以下是官方文档中提到的一些表达式:

execution(public * *(..)) //匹配所有public方法
execution(* set*(..))//匹配所有方法名开头为set的方法
execution(* com.xyz.service.AccountService.*(..))//匹配AccountService下的所有方法
execution(* com.xyz.service.*.*(..))//匹配service包下的所有方法
execution(* com.xyz.service..*.*(..))//匹配service包或其子包下的所有方法
within(com.xyz.service.*)//匹配service包下的所有方法
within(com.xyz.service..*)//匹配service包或其子包下的所有方法
this(com.xyz.service.AccountService)//匹配所有实现了AccountService接口的类的代理类的方法(注意是代理类)
target(com.xyz.service.AccountService)//匹配所有实现了AccountService接口的类的方法(注意是本类)
args(java.io.Serializable)//匹配只有一个入参,且入参实现了Serializable接口的方法
@target(org.springframework.transaction.annotation.Transactional)//匹配类上标注了@Transactional注解的类中方法
@within(org.springframework.transaction.annotation.Transactional)//匹配运行时子类上标注了@Transactional注解的类中方法
@annotation(org.springframework.transaction.annotation.Transactional)//匹配所有打了@Transactional注解的方法
@args(com.xyz.security.Classified)//匹配只有一个入参,且运行时入参有@Classified注解的方法
bean(tradeService)//匹配命名为tradeService的类的方法
bean(*Service)//匹配命名后缀为Service的类的方法

‘this’ is more commonly used in a binding form. See the section on Declaring Advice for how to make the proxy object available in the advice body.

关于上面@target和@within区别请看博客

3. 运算符组合切点表达式

这一部分直接列举几个,基础表达式会写之后,组合按照自己想圈定的范围进行组合运算匹配即可:

//或(||)运算符
@Pointcut("execution(* com.xxx.yyy.service.*.*.*(..))||" +
        "execution(* com.xxx.yyy.api.*.*.*(..))")
public void myElseCut(){};
//与(&&)运算符
@Pointcut("execution(* com.xxx.yyy.controller..*.*(..))"
        + "&& @within(org.springframework.web.bind.annotation.RestController)")
public void myAndCut(){};
//非(!)运算符
@Pointcut("@within(org.springframework.validation.annotation.Validated)"
            + "&& !@within(org.springframework.web.bind.annotation.RestController)"
            + "&& !@within(org.springframework.stereotype.Controller)")
public void myNotCut(){};

组合切点表达式均可以拆分成两个切点声明,然后再使用运算符连接,这样可读性好些,例如:

@Aspect
@Component
public class MyselfAnnotionAspect {
    //通过切点表达式定义切点
    /**@Pointcut("execution(* com.enjoyican.demo.selfannotion.service.impl..*(..))")
    public void myPointCut(){};
    @Pointcut("@annotation(MyselfAnnotion)")
    public void myAnnoCut(){};
    @Pointcut("within(com.enjoyican.demo.selfannotion.service..*)")
    public void myWithinCut(){};
    @Pointcut("target(com.enjoyican.demo.selfannotion.service.MyAnnotionTestService)")
    public void myTargetCut(){};*/
    @Pointcut("@target(MyselfAnnotion)")
    public void myAtTargetCut(){};
    @Pointcut("bean(myAnnotionTestServiceImpl)")
    public void myBeanCut(){};
    //定义方法增强类型(本例子采用环绕增强)
    @Around("myBeanCut()&&myAtTargetCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("AOP切面在执行service方法之前增强");
        point.proceed();
        System.out.println("AOP切面在执行service方法之后增强");
        return null;
    }
}

总结

对于切点表达式的熟悉可以使我们在项目中更好的写出匹配到更灵活规则的类的表达式,强烈建议看下官网中Aspect Oriented Programming with Spring这一节的内容,很多我们平时用的其实官方文档上都说明了,而且这里的英文相对简单,除了一些专业词汇外都是很通俗易懂的语句。

如有疑问,可在我的个人博客spring-aop常用切点表达式下留言或者在CSDN留言即可

你可能感兴趣的:(基础知识,aop,spring,java)