Spring笔记(八)—— AOP 之基于 Schema 配置

Spring 提供了使用新的 aop 命名标签定义切面的支持,使得我们可以使用 Schema 配置切面。基于 @AspectJ 注解的切面,本质上是将切点、增强类型的信息使用注解进行描述;而在基于 Schema 的实现方式中,把这两个信息移到 Schema 的 XML 配置文件中。虽然配置方式不同,但两者表达的信息完全相同。使用基于 Schema 的切面定义后,切点、增强类型的注解信息从切面类中剥离出来,原本的切面类变成了真正意义上的 POJO。在 Spring 配置中,所有的 aspect、pointcut 和 advisor 元素都需要放置在 <aop:config> 元素之下。

声明切面(aspect)

使用 Schema 支持时,一个切面只是一个 POJO 类,它在 Spring 应用程序上下文中定义为一个 Bean。状态和行为由对象的字段和方法提供,切点和增强由 XML 配置文件提供。
切面的声明使用 <aop:aspect> 元素,而 bean 使用 ref 属性注入。

1
2
3
4
5
6
7
8
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
...
</aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>

声明切点(pointcut)

使用切点表达式的方式:

1
2
3
4
<aop:config>
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
</aop:config>

直接声明切点的方式:

1
2
3
4
<aop:config>
<aop:pointcut id="businessService"
expression="com.xyz.myapp.SystemArchitecture.businessService()"/>
</aop:config>

声明增强(advice)

和 @AspecJ 所支持的类型一致,sechema 也支持 5 种增强方式,且在使用方法上也大致相同。
参考 Spring笔记(七)—— AOP 之 @AspectJ 支持

Before advice

<aop:aspect> 元素下使用 <aop:before> 子元素声明。

1
2
3
4
5
<aop:aspect id="beforeExample" ref="aBean">
<aop:before pointcut-ref="dataAccessOperation"
method="doAccessCheck"/>
...
</aop:aspect>

上面的 dataAccessOperation 是切点的 id,要直接定义切点,需要使用 pointcut 属性代替 pointcut-ref:

1
2
3
4
5
<aop:aspect id="beforeExample" ref="aBean">
<aop:before pointcut="execution(* com.xyz.myapp.dao.*.*(..))"
method="doAccessCheck"/>
...
</aop:aspect>

After returning advice

使用 returning 属性指定传递返回值的参数名:

1
2
3
4
5
6
7
<aop:aspect id="afterReturningExample" ref="aBean">
<aop:after-returning
pointcut-ref="dataAccessOperation"
returning="retVal"
method="doAccessCheck"/>
...
</aop:aspect>

doAccessCheck 方法必须声明一个名为 retVal 的参数,此参数的类型以与 @AfterReturning 中所述相同的方式约束匹配。

1
public void doAccessCheck(Object retVal) {...}

After throwing advice

使用 throwing 属性指定应传递异常的参数的名称:

1
2
3
4
5
6
7
<aop:aspect id="afterThrowingExample" ref="aBean">
<aop:after-throwing
pointcut-ref="dataAccessOperation"
throwing="dataAccessEx"
method="doRecoveryActions"/>
...
</aop:aspect>

doRecoveryActions 方法必须声明一个名为 dataAccessEx 的参数:

1
public void doRecoveryActions(DataAccessException dataAccessEx) {...}

After (finally) advice

1
2
3
4
5
6
<aop:aspect id="afterFinallyExample" ref="aBean">
<aop:after
pointcut-ref="dataAccessOperation"
method="doReleaseLock"/>
...
</aop:aspect>

Around advice

Around advice 通常于线程安全的方式下,在要执行的方法前后分享状态时使用。

1
2
3
4
5
6
<aop:aspect id="aroundExample" ref="aBean">
<aop:around
pointcut-ref="businessService"
method="doBasicProfiling"/>
...
</aop:aspect>

1
2
3
4
5
6
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}

Introductions

通过 <aop:declare-parents> 配置引介增强,引介增强和其它类型的增强不同,它没有 method、pointcut 和 pointcut-ref 属性:

1
2
3
4
5
6
7
8
9
<aop:aspect id="usageTrackerAspect" ref="usageTracking">
<aop:declare-parents
types-matching="com.xzy.myapp.service.*+"
implement-interface="com.xyz.myapp.service.tracking.UsageTracked"
default-impl="com.xyz.myapp.service.tracking.DefaultUsageTracked"/>
<aop:before
pointcut="com.xyz.myapp.SystemArchitecture.businessService() and this(usageTracked)"
method="recordUsage"/>
</aop:aspect>

<aop:declare-parents> 通过 implement-interface 属性声明要实现的接口,通过 default-impl 属性指定默认的接口实现类,通过 types-matching 属性以 AspectJ 切点表达式语法指定哪些 Bean 需要引介 UsageTracked 接口的实现。注意:虽然 <aop:declare-parents> 没有 method 属性指定增强方法所在的 Bean,但 <aop:aspect id="usageTrackerAspect" ref="usageTracking"> 的 ref 属性依然要指定一个增强 Bean。

Advisors

Advisors 是 Spring 中切面概念的对应物,是切点和增强的复合体,不过仅包含一个切点和一个增强。在 AspectJ 中没有对应的等价物,在 aop Schema 配置样式中,可以通过 <aop:advisor> 配置一个 Advisor。通过 advice-ref 属性引用基于接口定义的增强,通过 pointcut 定义切点表达式,或通过 pointcut-ref 引用一个命名的切点。

1
2
3
4
5
6
7
8
9
10
11
12
<aop:config>
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
<aop:advisor
pointcut-ref="businessService"
advice-ref="tx-advice"/>
</aop:config>
<tx:advice id="tx-advice">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>

参考资料:

Spring 3.x 企业应用开发实战
Spring Framework Reference Documentation

热评文章