要在 Spring 应用中使用 AspectJ 注解, 必须在 classpath 下包含 AspectJ 类库: aopalliance.jar、aspectj.weaver.jar 和 spring-aspects.jar
将 aop Schema 添加到 <beans> 根元素中. 要在 Spring IOC 容器中启用 AspectJ 注解支持, 只要在 Bean 配置文件中定义一个空的 XML 元素 <aop:aspectj-autoproxy>
当 Spring IOC 容器侦测到 Bean 配置文件中的 <aop:aspectj-autoproxy> 元素时,会自动为与 AspectJ 切面匹配的 Bean 创建代理要在 Spring 中声明 AspectJ 切面,
只需要在 IOC 容器中将切面声明为 Bean 实例. 当在 Spring IOC 容器中初始化 AspectJ 切面之后,Spring IOC 容器就会为那些与 AspectJ 切面相匹配的 Bean 创建代理.
在 AspectJ 注解中, 切面只是一个带有 @Aspect 注解的 Java 类. 通知是标注有某种注解的简单的 Java 方法. AspectJ 支持 5 种类型的通知注解: @Before: 前置通知, 在方法执行之前执行 @After: 后置通知, 在方法执行之后执行 @AfterRunning: 返回通知, 在方法返回结果之后执行 @AfterThrowing: 异常通知, 在方法抛出异常之后 @Around: 环绕通知, 围绕着方法执行
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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"> <context:component-scan base-package="com.aspectsAop"></context:component-scan> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
前置、后置、返回、异常AOP处理
1 package com.aspectsAop; 2 3 import java.util.Arrays; 4 import org.aspectj.lang.ProceedingJoinPoint; 5 import org.aspectj.lang.annotation.Around; 6 import org.aspectj.lang.annotation.Aspect; 7 import org.aspectj.lang.annotation.Pointcut; 8 import org.springframework.core.annotation.Order; 9 import org.springframework.stereotype.Component; 10 11 /** 12 * 可以使用 @Order 注解指定切面的优先级, 值越小优先级越高 13 */ 14 @Order(1) 15 @Aspect 16 @Component 17 public class ArithmeticCalculatorAspectsAround { 18 19 /** 20 * 定义一个方法, 用于声明切入点表达式. 一般地, 该方法中再不需要添入其他的代码. 21 * 使用 @Pointcut 来声明切入点表达式. 22 * 后面的其他通知直接使用方法名来引用当前的切入点表达式. 23 */ 24 @Pointcut("execution(public int com.aspectsAop.ari.ArithmeticCalculatorImpl.*(..))") 25 public void declareJointPointExpression() { 26 27 } 28 29 /** 30 * 环绕通知需要携带 ProceedingJoinPoint 类型的参数. 31 * 环绕通知类似于动态代理的全过程: ProceedingJoinPoint 类型的参数可以决定是否执行目标方法. 32 * 且环绕通知必须有返回值, 返回值即为目标方法的返回值 33 */ 34 /** 35 * 在 ArithmeticCalculator 接口的每一个实现类的每一个方法开始之前执行一段代码 36 */ 37 @Around(value = "declareJointPointExpression()") 38 public Object aroundMethods(ProceedingJoinPoint point) { 39 40 Object result = null; 41 Object args = point.getArgs(); 42 String methodName = point.getSignature().getName(); 43 try { 44 // 1.前置通知 45 System.out.println("环绕前置通知信息Method:" + methodName + "<参数>==》" + Arrays.asList(args)); 46 // 2.执行目标方法 47 result = point.proceed(); 48 // 3.返回通知 49 System.out.println("环绕后置通知信息Method:" + methodName + "<参数>==》" + Arrays.asList(args) + "》》结果:" + result); 50 } catch (Throwable e) { 51 // 4.异常通知 52 System.out.println("环绕后置通知信息Method:" + methodName + "<参数>==》" + Arrays.asList(args) + "异常信息:" + e); 53 throw new RuntimeException(e); 54 } 55 // 5.方法完成后的返回通知 56 System.out.println("环绕方法执行完成通知信息Method:" + methodName + "<参数>==》" + Arrays.asList(args)); 57 return result; 58 } 59 }