Spring AOP - 实现

Spring 支持 @AspectJ annotation style 方法和 schema-based 方法来实现自定义方面。


基于 XML 架构

方面是使用常规类和基于 XML 的配置来实现的。

要使用本节介绍的 AOP 命名空间标签,需要导入 spring AOP schema,描述如下 −

实例


<?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>

声明 Aspect

aspect 使用 元素声明,支持 bean 使用 ref 属性引用,如下所示 .

实例


<aop:config>
   <aop:aspect id = "myAspect" ref = "aBean">
   ...
   </aop:aspect>
</aop:config>

<bean id = "aBean" class = "...">
   ...
</bean>

这里"aBean"将被配置和依赖注入,就像您在前面章节中看到的任何其他 Spring bean 一样。


声明 Pointcut

Pointcut 有助于确定要使用不同建议执行的感兴趣的连接点(即方法)。 在使用基于 XML Schema 的配置时,Pointcut 将定义如下 −

实例


<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.tutorialspoint 包下 Student 类中可用的 getName() 方法的执行。

实例


<aop:config>
   <aop:aspect id = "myAspect" ref = "aBean">

   <aop:pointcut id = "businessService"
      expression = "execution(* com.tutorialspoint.Student.getName(..))"/>
   ...
   </aop:aspect>
</aop:config>

<bean id = "aBean" class = "...">
   ...
</bean>

声明 Advices

您可以使用 <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 5 注解进行注解的常规 Java 类的风格。 通过在基于 XML 模式的配置文件中包含以下元素来启用 @AspectJ 支持。

<aop:aspectj-autoproxy/>

声明 Aspect

Aspects 类与任何其他普通 bean 一样,并且可以像任何其他类一样具有方法和字段,除了它们将使用 @Aspect 注解如下。

实例


package org.xyz;

import org.aspectj.lang.annotation.Aspect;

@Aspect
public class AspectModule {
}

它们将像任何其他 bean 一样在 XML 中配置,如下所示。

实例


<bean id = "myAspect" class = "org.xyz.AspectModule">
   <!-- configure properties of aspect here as normal -->
</bean>

声明 Pointcut

Pointcut 有助于确定要使用不同建议执行的感兴趣的连接点(即方法)。 在使用基于 @AspectJ 的配置时,Pointcut 声明有两个部分 −

  • 一个切入点表达式,它准确地确定我们感兴趣的方法执行。

  • 一个切入点签名,包括名称和任意数量的参数。 该方法的实际主体是无关紧要的,实际上应该是空的。

以下示例定义了一个名为 "businessService" 的切入点,它将匹配 com.xyz.myapp.service 包下的类中可用的每个方法的执行。

实例


import org.aspectj.lang.annotation.Pointcut;

@Pointcut("execution(* com.xyz.myapp.service.*.*(..))") // expression 
private void businessService() {}  // signature

以下示例定义了一个名为"getname"的切入点,它将匹配 com.tutorialspoint 包下 Student 类中可用的 getName() 方法的执行。

实例


import org.aspectj.lang.annotation.Pointcut;

@Pointcut("execution(* com.tutorialspoint.Student.getName(..))") 
private void getname() {}

声明 Advices

您可以使用@{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 通知定义内联切入点的示例。

实例


@Before("execution(* com.xyz.myapp.service.*.*(..))")
public doBeforeTask(){
   ...
}