在使用spring框架配置AOP的时候,不管是通过XML配置文件还是注解的方式都需要定义pointcut"切入点"
例如
定义切入点表达式 execution (* com.sample.service.impl..*.*(..))
execution()
是最常用的切点函数,其语法如下所示:
整个表达式可以分为五个部分:
execution()
: 表达式主体。- 第一个
*
号:表示返回类型,*
号表示所有的类型。 - 包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
- 第二个
*
号:表示类名,*
号表示所有的类。 *(..):
最后这个星号表示方法名,*
号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。
AspectJ的Execution表达式
execution()
execution()是最常用的切点函数,其语法如下所示:
execution(<修饰符模式>? <返回类型模式> <方法名模式>(<参数模式>) <异常模式>?)
除了返回类型模式、方法名模式和参数模式外,其它项都是可选的。与其直接讲解该方法的使用规则,还不如通过一个个具体的例子进行理解。下面,我们给出各 种使用execution()
函数实例。
1. 通过方法签名定义切点
execution(public * *(..))
匹配所有目标类的public方法,但不匹配SmartSeller
和protected void showGoods()
方法。第一个*
代表返回类型,第二个*
代表方法名,而..
代表任意入参的方法;
execution(* *To(..))l
匹配目标类所有以To
为后缀的方法。它匹配NaiveWaiter
和NaughtyWaiter
的greetTo()
和serveTo()
方法。第一个*
代表返回类型,而*To
代表任意以To为后缀的方法;
2. 通过类定义切点
execution(* com.baobaotao.Waiter.*(..))
匹配Waiter
接口的所有方法,它匹配NaiveWaiter
和NaughtyWaiter
类的greetTo()
和serveTo()
方法。第一个*
代表返回任意类型,com.baobaotao.Waiter.*
代表Waiter接口中的所有方法;
execution(* com.baobaotao.Waiter+.*(..))
匹 配Waiter
接口及其所有实现类的方法,它不但匹配NaiveWaiter
和NaughtyWaiter
类的greetTo()
和serveTo()
这 两个Waiter
接口定义的方法,同时还匹配NaiveWaiter#smile()
和NaughtyWaiter#joke()
这两个不在Waiter 接口中定义的方法。
3. 通过类包定义切点
在类名模式串中,“.*”
表示包下的所有类,而“..*”
表示包、子孙包下的所有类。
execution(* com.baobaotao.*(..))
匹配com.baobaotao
包下所有类的所有方法;
execution(* com.baobaotao..*(..))
匹配com.baobaotao
包、子孙包下所有类的所有方法,如com.baobaotao.dao
,com.baobaotao.servier
以及com.baobaotao.dao.user
包下的所有类的所有方法都匹配。“..”
出现在类名中时,后面必须跟“*”
,表示包、子孙包下的所有类;
execution(* com..*.*Dao.find*(..))
匹配包名前缀为com的任何包下类名后缀为Dao
的方法,方法名必须以find
为前缀。如com.baobaotao.UserDao#findByUserId()
、com.baobaotao.dao.ForumDao#findById()
的方法都匹配切点。
4. 通过方法入参定义切点
切点表达式中方法入参部分比较复杂,可以使用“*”
和“ ..”
通配符,其中“*”
表示任意类型的参数,而“..”
表示任意类型参数且参数个数不限。
execution(* joke(String,int)))
匹配joke(String,int)
方法,且joke()
方法的第一个入参是String
,第二个入参是int
。它匹配 NaughtyWaiter#joke(String,int)
方法。如果方法中的入参类型是java.lang
包下的类,可以直接使用类名,否则必须使 用全限定类名,如joke(java.util.List,int);
execution(* joke(String,*)))
匹配目标类中的joke()
方法,该方法第一个入参为String
,第二个入参可以是任意类型,如joke(String s1,String s2)
和joke(String s1,double d2)
都匹配,但joke(String s1,double d2,String s3)
则不匹配;
execution(* joke(String,..)))
匹配目标类中的joke()
方法,该方法第 一个入参为String
,后面可以有任意个入参且入参类型不限,如joke(String s1)
、joke(String s1,String s2)
和joke(String s1,double d2,String s3)
都匹配。
execution(* joke(Object+)))
匹 配目标类中的joke()
方法,方法拥有一个入参,且入参是Object
类型或该类的子类。它匹配joke(String s1)
和joke(Client c)
。如果我们定义的切点是execution(* joke(Object))
,则只匹配joke(Object object)
而不匹配joke(String cc)
或joke(Client c)
。
args()
和@args()
args()
函数的入参是类名,@args()
函数的入参必须是注解类的类名。虽然args()
允许在类名后使用+
通配符后缀,但该通配符在此处没有意义:添加和不添加效果都一样。
1. args()
该函数接受一个类名,表示目标类方法入参对象按类型匹配于指定类时,切点匹配,如下面的例子:
args(com.baobaotao.Waiter)
表示运行时入参是Waiter类型的方法,它和execution(* *(com.baobaotao.Waiter))
区别在于后者是针对类方法的签名而言的,而前者则针对运行时的入参类型而言。如 args(com.baobaotao.Waiter)
既匹配于addWaiter(Waiter waiter)
,也匹配于addNaiveWaiter(NaiveWaiter naiveWaiter)
,而execution(* *(com.baobaotao.Waiter))
只匹配addWaiter(Waiter waiter)
方法;实际上,args(com.baobaotao.Waiter)
等价于execution(* *(com.baobaotao.Waiter+))
,当然也等价于args(com.baobaotao.Waiter+)
。
2. @args()
该函数接受一个注解类的类名,当方法的运行时入参对象标注发指定的注解时,方法匹配切点。这个切点函数的匹配规则不太容易理解,我们通过以下示意图对此进行详细讲解:
类别 | 函数 | 入参 | 说明 |
---|---|---|---|
方法切点函数 | execution() | 方法匹配模式串 | 表示满足某一匹配模式的所有目标类方法连接点。 如 execution(* greetTo(..)) 表示所有目标类中的greetTo() 方法。 |
@annotation() | 方法注解类名 | 表示标注了特定注解的目标方法连接点。 如 @annotation(com.baobaotao.anno.NeedTest) 表示任何标注了@NeedTest 注解的目标类方法。 | |
方法入参切点函数 | args() | 类名 | 通过判别目标类方法运行时入参对象的类型定义指定连接点。 如 args(com.baobaotao.Waiter) 表示所有有且仅有一个按类型匹配于Waiter的入参的方法。 |
@args() | 类型注解类名 | 通过判别目标方法的运行时入参对象的类是否标注特定注解来指定连接点。 如 @args(com.baobaotao.Monitorable) 表示任何这样的一个目标方法:它有一个入参且入参对象的类标注 @Monitorable 注解。 | |
目标类切点函数 | within() | 类名匹配串 | 表示特定域下的所有连接点。 如 within(com.baobaotao.service.*) 表示com.baobaotao.service 包中的所有连接点,也即包中所有类的所有方法,而 within(com.baobaotao.service.*Service) 表示在 com.baobaotao.service 包中,所有以Service 结尾的类的所有连接点。 |
target() | 类名 | 假如目标类按类型匹配于指定类,则目标类的所有连接点匹配这个切点。 如通过 target(com.baobaotao.Waiter) 定义的切点,Waiter 、以及 Waiter 实现类NaiveWaiter 中所有连接点都匹配该切点。 | |
@within() | 类型注解类名 | 假如目标类按类型匹配于某个类A,且类A标注了特定注解, 则目标类的所有连接点匹配这个切点。 如 @within(com.baobaotao.Monitorable) 定义的切点,假如Waiter类标注了 @Monitorable 注解,则Waiter以及 Waiter 实现类NaiveWaiter 类的所有连接点都匹配。 | |
@target() | 类型注解类名 | 目标类标注了特定注解,则目标类所有连接点匹配该切点。 如 @target(com.baobaotao.Monitorable) ,假如 NaiveWaiter· 标注了@Monitorable ,则 NaiveWaiter 所有连接点匹配切点。 | |
代理类切点函数 | this() | 类名 | 代理类按类型匹配于指定类,则被代理的目标类所有连接点匹配切点。 这个函数比较难理解,这里暂不举例,留待后面详解。 |
本文由 创作,采用 知识共享署名4.0 国际许可协议进行许可。本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。最后编辑时间为: 2020/05/15 00:51