Skip to main content

Spring AOP中的Aspect

本文相关代码(来自官方源码spring-test模块)请参见spring-framework org.springframework.mylearntest包下。

Aspect是对系统中的横切关注点逻辑进行模块化封装的AOP的概念实体。通常情况下,Aspect可以包含多个Pointcut以及相关Advice定义。

Advisor代表Spring中的Aspect,但是与正常的Aspect不同,Advisor通常只持有一个Pointcut和一个Advice。而理论上,Aspect定义中可以有多个Pointcut和多个Advice,所以Advisor是一种特殊的Aspect。

PointcutAdvisor


实际上,org.springframework.aop.PointcutAdvisor才是真正定义的有一个Pointcut和一个Advice的Advisor,大部分的Advisor实现全部是在PointcutAdvisor下的。

DefaultPointcutAdvisor

<beans>
<bean id="pointcut"
class="org.springframework.mylearntest.aop.pointcut.selfdefinepointcut.QueryMethodPointcut"/>
<bean id="advice" class="org.springframework.mylearntest.aop.advice.perclass.DiscountMethodInterceptor"/>

<bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="pointcut"/>
<property name="advice" ref="advice"/>
</bean>
</beans>

NameMatchMethodPointcutAdvisor

此类内部持有一个NameMatchMethodPointcut类型的Pointcut实例。当通过NameMatchMethodPointcutAdvisor公开的setMappedName和setMappedNames方法设置将要被拦截的方法名的时候,实际上是在操作NameMatchMethodPointcutAdvisor内部的NameMatchMethodPointcut实例。

Advice advice = new DiscountMethodInterceptor();
NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor(advice);
advisor.setMappedName("invoke");

RegexpMethodPointcutAdvisor

只能通过正则表达式为其设置相应的Pointcut,内部持有一个AbstractRegexpMethodPointcut的实例。AbstractRegexpMethodPointcut有两个实现类,Perl5RegexpMethodPointcutAdvisor和JdkRegexpMethodPointcut。默认使用JdkRegexpMethodPointcut,如果强制使用Perl5RegexpMethodPointcutAdvisor,那么可以通过RegexpMethodPointcutAdvisor的setPerl5(boolean)实现。

DefaultBeanFactoryPointcutAdvisor

DefaultBeanFactoryPointcutAdvisor自身绑定到了BeanFactory,要使用DefaultBeanFactoryPointcutAdvisor,要绑定到Spring IoC容器。通过容器中的Advice注册的beanName来关联对应的Advice。只有当对应的Pointcut匹配成功之后,采取实例化对应的Advice,减少了容器启动初期Advisor和Advice之间的耦合性。

IntroductionAdvisor

IntroductionAdvisor只能应用于类级别的拦截,只能使用Introduction型的Advice,而不能像PointcutAdvisor那样,可以使用任意类型的Pointcut,以及差不多任何类型的Advice。

IntroductionAdvisor类结构图

Order

大多数时候,会有多个关注横切点,那么,系统实现中就会有多个Advisor存在。当其中的某些Advisor的Pointcut匹配了同一个Joinpoint的时候,就会在这同一个Joinpoint处执行多个Advice的横切逻辑。一旦这几个需要在同一个Joinpoint处执行的Advice逻辑存在优先顺序依赖的话,就需要我们来干预了。

Spring在处理同一Joinpoint处的多个Advisor的时候,会按照指定的顺序有优先级来执行他们。顺序号越小,优先级越高,优先级越高的,越先被执行。(默认情况下,Spring会按照它们的声明顺序来应用它们,最先声明的顺序号最小但优先级最大,其次次之)

各个Advisor实现类,其实已经实现了Order接口。在使用的时候我们可以直接指定即可

<beans>
<bean id="permissionAuthAdvisor" class="...PermissionAuthAdvisor">
<property name="order" value="1"/>
...
</bean>

<bean id="exceptionBarrierAdvisor" class="...ExceptionBarrierAdvisor">
<property name="order" value="0"/>
...
</bean>
</beans>