Spring 基于 @AspectJ 的 AOP

返回 Spring AOP


@AspectJ 作为通过 Java 5 注释注释的普通的 Java 类,它指的是声明 aspects 的一种风格。通过在你的基于架构的 XML 配置文件中包含以下元素,@AspectJ 支持是可用的。

<aop:aspectj-autoproxy/>

你还需要在你的应用程序的 CLASSPATH 中使用以下 AspectJ 库文件。这些库文件在一个 AspectJ 装置的 ‘lib’ 目录中是可用的,如果没有,你可以在 Internet 中下载它们。

  • aspectjrt.jar
  • aspectjweaver.jar
  • aspectj.jar
  • aopalliance.jar

附上官网下载地址:http://www.eclipse.org/aspectj/downloads.php

本站也提供aspectj-1.8.13.jar版本的下载 https://pan.baidu.com/s/1E3_1rFBkxd1TOic9nwHong 提取码: ahil


声明一个 aspect

Aspects 类和其他任何正常的 bean 一样,除了它们将会用 @AspectJ 注释之外,它和其他类一样可能有方法和字段,如下所示:

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>

声明一个切入点

一个切入点有助于确定使用不同建议执行的感兴趣的连接点(即方法)。在处理基于配置的 XML 架构时,切入点的声明有两个部分:

一个切入点表达式决定了我们感兴趣的哪个方法会真正被执行。

一个切入点标签包含一个名称和任意数量的参数。方法的真正内容是不相干的,并且实际上它应该是空的。 下面的示例中定义了一个名为 ‘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() {}

声明通知

你可以使用 @{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(){
 ...
}

基于 @AspectJ 的 AOP 示例

为了理解上面提到的关于基于 AOP 的 @AspectJ 的概念,让我们编写一个示例,可以实现几个建议。为了在我们的示例中使用几个建议

  1. 使用我们 Spring第一个示例 中的项目 FirstSpring。
  2. 在项目中添加 Spring AOP 指定的库文件 aspectjrt.jar, aspectjweaver.jar 和 aspectj.jar。
  3. 在 com.tutorialspoint 包下创建 Java 类 Logging, Student 和 MainApp。
  4. 在 src 文件夹下创建 Beans 配置文件 Beans.xml。
  5. 最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并且按如下解释的那样运行应用程序。

这是 Logging.java 文件的内容。 这实际上是一个方面模块的示例,它定义了要在各个点调用的方法。

Logging.java

package com.jiyik;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;

@Aspect
public class Logging {
    /**
     * 以下是要选择的切入点的定义
     * 所以对于所有方法通知将被调用
     */
    @Pointcut("execution(* com.jiyik.*.*(..))")
    private void selectAll() {
    }

    /**
     * 这是在选定的方法执行之前想要执行的方法。
     */
    @Before("selectAll()")
    public void beforeAdvice() {
        System.out.println("Going to setup student profile.");
    }

    /**
     * 这是在选定的方法执行之后想要执行的方法。
     */
    @After("selectAll()")
    public void afterAdvice() {
        System.out.println("Student profile has been setup.");
    }

    /**
     * 这是当任何方法返回时想要执行的方法。
     */
    @AfterReturning(pointcut = "selectAll()", returning = "retVal")
    public void afterReturningAdvice(Object retVal) {
        System.out.println("Returning:" + retVal.toString());
    }

    /**
     * 这是当出现异常时想要执行的方法。
     */
    @AfterThrowing(pointcut = "selectAll()", throwing = "ex")
    public void AfterThrowingAdvice(IllegalArgumentException ex) {
        System.out.println("There has been an exception: " + ex.toString());
    }
}

以下是 Student.java 文件的内容

Student.java

package com.jiyik;

public class Student {
   private Integer age;
   private String name;

   public void setAge(Integer age) {
      this.age = age;
   }
   public Integer getAge() {
      System.out.println("Age : " + age );
      return age;
   }
   public void setName(String name) {
      this.name = name;
   }
   public String getName() {
      System.out.println("Name : " + name );
      return name;
   }
   public void printThrowException(){
      System.out.println("Exception raised");
      throw new IllegalArgumentException();
   }
}

以下是 MainApp.java 文件的内容

MainApp.java

package com.jiyik;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      
      Student student = (Student) context.getBean("student");
      student.getName();
      student.getAge();
      
      student.printThrowException();
   }
}

以下是配置文件Beans.xml

Beans.xml

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

   <aop:aspectj-autoproxy/>

   <!-- 学生bean的定义 -->
   <bean id = "student" class = "com.jiyik.Student">
      <property name = "name" value = "Zara" />
      <property name = "age"  value = "11"/>      
   </bean>

   <!-- 日志方面的定义 -->
   <bean id = "logging" class = "com.jiyik.Logging"/> 
      
</beans>

完成源代码和 bean 配置文件后,让我们运行应用程序。 如果应用程序一切正常,运行结果如下所示

Spring-AspectJ-运行结果


返回 Spring AOP

查看笔记

扫码一下
查看教程更方便