在bean配置文件中,所有的Spring AOP配置都必须定义在<aop:config>
元素内部。对于每个切面而言,都要创建一个<aop:aspect>
元素来为具体的切面实现引用后端bean实例。
切面bean必须有一个标识符,供<aop:aspect>
元素引用。
<bean id="calculatorLoggingAspect" class="com.jdy.spring2020.aop.CalculatorLoggingAspect"/> <aop:config> <aop:aspect id="calculatorLoggingAspect" order="0" ref="calculatorLoggingAspect"> </aop:aspect> </aop:config>
二、xml配置
-
切入点使用<aop:pointcut>元素声明。
-
切入点必须定义在<aop:aspect>元素下,或者直接定义在<aop:config>元素下。
-
定义在<aop:aspect>元素下:只对当前切面有效
-
定义在<aop:config>元素下:对所有切面都有效
-
-
基于XML的AOP配置不允许在切入点表达式中用名称引用其他切入点。
-
在aop名称空间中,每种通知类型都对应一个特定的XML元素。
-
通知元素需要使用<pointcut-ref>来引用切入点,或用<pointcut>直接嵌入切入点表达式。
-
method属性指定切面类中通知方法的名称
<?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.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--定义目标类--> <bean id="arithmeticCalculator" class="com.jdy.spring2020.scan.service.impl.ArithmeticCalculatorImpl"/> <!--定义切面类--> <bean name="arithmeticCalculatorLog" class="com.jdy.spring2020.aop.ArithmeticCalculatorLog"/> <!--aop配置--> <aop:config> <!--定义切点,其中匹配的是com.jdy.spring2020.scan.service.impl.ArithmeticCalculatorImpl类下面所有参数返回值任意的方法--> <aop:pointcut id="pointcut" expression="execution(* com.jdy.spring2020.scan.service.impl.ArithmeticCalculatorImpl.*(..))"/> <aop:aspect ref="arithmeticCalculatorLog"> <!--前置通知,method必须与切面类中的方法名相同(下同),并指定切点--> <aop:before method="before" pointcut-ref="pointcut"></aop:before> <!--后置通知--> <aop:after method="after" pointcut-ref="pointcut"></aop:after> <!--返回通知,返回值名与方法返回值名相同--> <aop:after-returning method="afterRunning" pointcut-ref="pointcut" returning="result"/> <!--异常通知,异常名与方法返回的异常名相同--> <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="ex"/> </aop:aspect> </aop:config> </beans>
三、切面类
package com.jdy.spring2020.aop; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; public class ArithmeticCalculatorLog { /** * 前置通知: * @Before("execution( com.jdy.spring2020.scan.service.impl.ArithmeticCalculatorImpl.add(int,int))") * 在ArithmeticCalculatorImpl.add方法前之前前置通知 * */ public void before(){ System.out.println("AO....前置通知"); } /** * * @param joinPoint:连接点对象 */ public void after(JoinPoint joinPoint){ //方法的名字 String name = joinPoint.getSignature().getName(); System.out.println("后置通知方法名字:" + name); } /** * 返回通知:目标方法执行结束后,得到方法的返回值 * 获取方法的返回值:通过returnning来指定一个名字,必须要与方法的一个参数名成一致。 * @param joinPoint * @param result */ public void afterRunning(JoinPoint joinPoint,Object result){ //方法的名字 String name = joinPoint.getSignature().getName(); System.out.println("返回通知方法名字:" + name); System.out.println("返回通知方法返回值:" + result); } /** * 异常通知:目标方法执行结束后,目标方法抛出异常 * 获取方法的异常:通过Throwing来指定一个名字,必须要与方法的一个参数名一致 * 可以通过形参中异常的类型来设置抛出指定异常才会执行异常通知 * @param joinPoint */ public void afterThrowing(JoinPoint joinPoint,Exception ex){ //方法的名字 String name = joinPoint.getSignature().getName(); System.out.println("异常通知方法名字:" + name); System.out.println("异常通知方法返回异常:" + ex); } //可以通过形参中异常的类型来设置抛出指定异常才会执行异常通知 public void afterThrowing1(JoinPoint joinPoint, NullPointerException ex){ //方法的名字 String name = joinPoint.getSignature().getName(); System.out.println("异常通知方法名字" + name); System.out.println("异常通知方法返回异常" + ex); } /** * 环绕通知 * @param joinPoint */ public Object around(ProceedingJoinPoint joinPoint) { //方法的名字 Object obj = null; //前置 try { //执行目标方法,相当于动态代理的invoke方法 System.out.println("环绕通知---->方法名字" + joinPoint.getSignature().getName()); obj = joinPoint.proceed(); System.out.println("环绕通知---->方法proceed" + obj); } catch (Throwable throwable) { throwable.printStackTrace(); }finally { //后置 } return obj; } }