Spring 基于 @AspectJ 的 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 的概念,让我们编写一个示例,可以实现几个建议。为了在我们的示例中使用几个建议
- 使用我们 Spring第一个示例 中的项目 FirstSpring。
- 在项目中添加 Spring AOP 指定的库文件 aspectjrt.jar, aspectjweaver.jar 和 aspectj.jar。
- 在 com.tutorialspoint 包下创建 Java 类 Logging, Student 和 MainApp。
- 在 src 文件夹下创建 Beans 配置文件 Beans.xml。
- 最后一步是创建所有 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 配置文件后,让我们运行应用程序。 如果应用程序一切正常,运行结果如下所示