Spring AOP实现
Spring支持使用@AspectJ
注释样式方法和基于模式的方法来实现自定义方面。
基于XML模式
方面(Aspects
)使用常规类以及基于XML的配置来实现。
要使用本节中描述的aop
命名空间标签,您需要按照以下所述导入spring-aop
模式:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<!-- bean definition & AOP specific configuration -->
</beans>
声明一个方面(Aspects
)
使用<aop:aspect>
元素声明一个方面(Aspects
),并使用ref
属性引用后台bean
,如下所示:
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
...
</aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>
这个“aBean
”将被配置和依赖注入就像任何其他的Spring Bean
一样,就像在前几章中看到的一样。
声明一个切入点
切入点(pointcut
)有助于确定要用不同建议执行的关联点(即方法)。 在使用基于XML模式的配置时,切入点将定义如下:
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
...
</aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>
以下示例定义了一个名为“businessService
”的切入点,该切入点将匹配com.yiibai
包中Student
类中的getName()
方法的执行:
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="businessService"
expression="execution(* com.yiibai.Student.getName(..))"/>
...
</aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>
声明通知
您可以使用<aop:{ADVICE NAME}>
元素在<aop:aspect>
内的五个通知中的任何一个声明如下:
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
<!-- a before advice definition -->
<aop:before pointcut-ref="businessService"
method="doRequiredTask"/>
<!-- an after advice definition -->
<aop:after pointcut-ref="businessService"
method="doRequiredTask"/>
<!-- an after-returning advice definition -->
<!--The doRequiredTask method must have parameter named retVal -->
<aop:after-returning pointcut-ref="businessService"
returning="retVal"
method="doRequiredTask"/>
<!-- an after-throwing advice definition -->
<!--The doRequiredTask method must have parameter named ex -->
<aop:after-throwing pointcut-ref="businessService"
throwing="ex"
method="doRequiredTask"/>
<!-- an around advice definition -->
<aop:around pointcut-ref="businessService"
method="doRequiredTask"/>
...
</aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>
可以对不同的通知使用相同doRequiredTask
或不同的方法。 这些方法将被定义为方面模块的一部分。
基于@AspectJ
@AspectJ
是指将Java方法注释为Java 5注释的常规Java类的方式。 @AspectJ
是指将Java方法注释为Java 5注释的常规Java类的方式。通过在基于XML Schema的配置文件中包含以下元素来启用@AspectJ
支持。
<aop:aspectj-autoproxy/>
声明一个方面(aspect)
方面(aspect
)的类就像任何其他正常的bean一样,并且可以像任何其他类一样具有方法和字段,不过它们使用@Aspect
进行注释,如下所示:
package org.xyz;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class AspectModule {
}
它们就像任何其他以XML格式配置的bean
一样,如下所示:
<bean id="myAspect" class="org.xyz.AspectModule">
<!-- configure properties of aspect here as normal -->
</bean>
声明一个切入点
切入点(pointcut
)有助于确定要用不同通知执行的关联点(即方法)。 在使用基于@AspectJ
的配置时,切入点声明有两部分:
- 一个切入点表达式,确定哪些方法执行。
- 切入点签名包括名称和任意数量的参数。 该方法的实体是无关紧要的,也可以是空的。
以下示例定义了一个名为“businessService
”的切入点,该切入点将匹配com.xyz.myapp.service
包下的类中可用的每个方法的执行:
import org.aspectj.lang.annotation.Pointcut;
@Pointcut("execution(* com.xyz.myapp.service.*.*(..))") // expression
private void businessService() {} // signature
以下示例定义了一个名为“getname
”的切入点,该切入点将与com.yiibai
包下的Student
类中的getName()
方法的执行相匹配:
import org.aspectj.lang.annotation.Pointcut;
@Pointcut("execution(* com.yiibai.Student.getName(..))")
private void getname() {}
声明通知
您可以使用@{ADVICE-NAME}
注释在以下所述的五个建议中声明任何一个。假设您已经定义了一个切入点签名方法为businessService()
,参考以下配置:
@Before("businessService()")
public void doBeforeTask(){
...
}
@After("businessService()")
public void doAfterTask(){
...
}
@AfterReturning(pointcut = "businessService()", returning="retVal")
public void doAfterReturnningTask(Object retVal){
// you can intercept retVal here.
...
}
@AfterThrowing(pointcut = "businessService()", throwing="ex")
public void doAfterThrowingTask(Exception ex){
// you can intercept thrown exception here.
...
}
@Around("businessService()")
public void doAroundTask(){
...
}
可以为任何通知定义切入点内嵌。 下面是一个为之前通知定义的内联切入点的示例:
@Before("execution(* com.xyz.myapp.service.*.*(..))")
public doBeforeTask(){
...
}