Spring AOP 使用通知者和切入点

首先回想一下,之前我们所给出的所有例子都是通过拦截所有的方法调用来完成AOP的实现的。但是我们会遇到两个问题:
我们如何只让某一个或者某一类的方法调用被AOP钩到(hook)而不是所有的方法,从而提高效率?
我们如何不用通过必须在AOP逻辑中硬编码方法名称列表的方式,去检测方法名称,从而找到正确的方法?

对于第一个问题,因为Spring会对不需要被AOP逻辑处理的方法进行优化,而ProxyFactory内部的实现是将所有方法调用交给DefaultPointcutAdvisor来处理,而后者则将AOP拦截设定为“所有方法调用”,这样会大大降低性能。

对于第二个问题,通过硬编码的方式,使用if之类的语句去判断AOP逻辑中调用的是否是正确的方法,显然的,首先重用性会大打折扣,其次,对性能也会有一定的拖累。
那么如何解决以上两个问题呢?答案就是使用通知者和切入点。

Spring中的通知者一共有4个(如果你的Spring不止4个,那么也许是版本更新的缘故吧),但是在Spring AOP基础部分,我们只使用最基本的DefaultPointcutAdvisor来做示例。前面说过Spring中一个Advisor就代表了一个切面,它包含了AOP逻辑(各种通知)和切入点(本文这部分的重点Pointcut接口及其实现)。而DefaultPointcutAdvisor,就是Spring面向切面编程所实现的最简单的类,我们以后在基础部分只使用而不介绍。

那么切入点,很简单,重复强调在Spring中就是方法调用的集合。但是,您是否要使用切入点编程,还要取决于另外一个因素——目标类亲和度。

参考《学习笔记》(十三)中最后部分给出关于验证弱密钥那部分的代码。像这种AOP逻辑与其它的类关系结合紧密的情况,我们称之“目标类亲和度”高,显然,对于这种情况,我们最好不使用切入点编程来处理。然而,大多数情况下,亲和度很低或者干脆没有,那么要坚持使用切入点编程不动摇!

切入点相关接口

说了这么多废话,切入点到底是什么?那么马上就来看看Spring中关于切入点编程的三个重要接口吧!

1。Pointcut接口

Spring中,要创建切入点,就必须要实现Pointcut(切入点)接口。
其中两个主要方法:ClassFilter getClassFilter()和MethodMatcher getMethodMatcher()。二者返回类型显而易见。

getClassFilter()

作用:Spring AOP在确定某个Pointcut是否适用于某个方法时,它首先会用getClassFilter()方法返回的ClassFilter(类过滤器)类实例的相关方法来测试被AOP所截获的方法调用是否来自正确的类。

解释:假如两个类A和B都有相同签名的方法public void operation(int arg),而且这两个类都需要应用到AOP当中去,而我们只希望某个AOP逻辑中使用的是B类的operation(),怎么判定到底是哪个类的operation被调用了呢?您一定已经猜到了,就是通过这个ClassFilter实例的方法来判断的。

getMethodMatcher()

作用:用来检测被Spring AOP所拦截到的方法是否是目标类的正确方法

解释:如果一个类A,有n个operation()方法重载。那么具体是哪个operation()方法被调用了,这个时候Spring AOP就要使用MethodMatcher(方法匹配器)类实例的相关方法去测试了。

2。ClassFilter接口

作用:见Pointcut接口getClassFilter()解释部分
实现:仅仅定义了一个接口

boolean matches(Class clazz)
顾名思义,如果切入点适合目标类,那么(Spring AOP的具体实现中)返回true,否则返回false

3。MethodMatcher接口

作用:见Pointcut接口getMethodMatcher()解释部分

实现:有三种主要方法

boolean isRuntime()
boolean matches(Method m, class targetClass)
boolean matches(Method m, Class targetClass, Object[] args)

方法isRuntime()的返回值为Spring决定了一个MethodMatcher的实例是静态的还是动态的。在Spring使用一个MethodMatcher之前,首先会调用它的isRuntime()方法,如果返回值为false,那么该MethodMatcher实例就是静态的,否则就是动态的。

如果是静态的MethodMatcher实例,Spring会对目标类上的每个方法调用一次MethodMatcher的matches(Method m, class targetClass)方法,返回值会被存放起来以便以后使用。这样对每个方法是否是需要AOP的适用性测试只会进行一次,之后目标类的某个方法被调用时就不会再调用matches()方法了。显而易见,静态的MethodMatcher效率比较高,但是缺乏一定的灵活性。

如果是动态的MethodMatcher,仍然会首先执行matches(Method m, class targetClass)进行测试,但是如果目标类的某个方法使得(matches(Method, Class)方法的)返回值是true的话,那么以后在目标类的这个方法被调用时,Spring会再调用boolean matches(Method m, Class targetClass, Object[] args)方法来进一步价差方法调用是否正确。显而易见,动态的MethodMatcher会更灵活,可以根据一次具体的方法调用而不是方法本身,来决定切入点是否适用,但是性能要低于静态的MethodMatcher。

以上三个接口是实现Spring切面编程的基础,当然我们可以自己实现他们创造出我们自己的切面类,但是这样比较麻烦而且不是必须。事实上Spring AOP框架已经为我们提供好了相应的实现。这些实现能够很好的满足我们的日常需求,如果不够怎么办?AspectJ呗!

Spring提供的实现一共有七种(七剑?别忘了Spring版本不同,数量可能不同),分别是:
DynamicMethodMatcherPointcut(动态方法匹配器切入点)
StaticMethodMatcherPointcut(静态方法匹配器切入点)
NameMethodMatcherPointcut(名称匹配器方法切入点)
JdkRegexpMethodPointcut(JDK正则表达式方法切入点)
Perl5RegexpMethodPointcut(支持Perl5的正则表达式方法切入点)
ComposablePointcut(可组合切入点)
ControlFlowPointcut(控制流程切入点)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值