当前位置: 首页 > 教程 > Spring AOP >

Spring AOP实现

精华
小牛编辑
109浏览
2023-03-14

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(){
 ...
}