Spring笔记 06:面向切面编程

it2025-10-24  9

1. 实例

切面类

@Component @Aspect public class LoggingAspect { @Before("execution(public int com.dudu.aspect.*.*(int,int))") public void beforeMethod(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); List<Object> args = Arrays.asList(joinPoint.getArgs()); System.out.println(methodName + "方法执行开始:" + args); } }

配置

<aop:aspectj-autoproxy/>

2. 说明

使用 @Aspect 注解将类声明为一个切面切面类中的方法叫做通知,方法上的注解有五种,指明通知开始的时机

@Before 在方法执行之前执行 @After 在方法执行之后执行,不管方法是否正常结束,且此时无法访问目标方法的返回值 @AfterReturning 在方法正常执行后执行,此时可以获取目标方法的返回值 @AfterThrowing 在方法产生异常后执行,可以指定异常类型 @Around 环绕通知,类似于动态代理的全过程,必须有返回值,返回值即为目标方法的返回值


AfterReturning通知

@AfterReturning(value = "execution(* com.dudu.aspect.CalculatorImpl.*(..))" , returning = "result") public void afterMethodReturn(JoinPoint joinPoint, Object result) { String methodName = joinPoint.getSignature().getName(); System.out.println("AfterReturning === " + methodName + "方法执行结束;" + result); }

AfterThrowing通知

@AfterThrowing(value = "execution(* com.dudu.aspect.CalculatorImpl.*(..))" , throwing = "ex") //此处指定的异常类型也是限定条件,只有在出现对应异常时,通知才会执行 public void afterMethodThrow(JoinPoint joinPoint, Throwable ex) { String methodName = joinPoint.getSignature().getName(); System.out.println("AfterThrowing === " + methodName + "方法执行结束;" + ex); }

Around通知

@Around(value = "execution(* com.dudu.aspect.CalculatorImpl.*(..))") public Object aroundMethod(ProceedingJoinPoint point) {//必要的参数 String methodName = point.getSignature().getName(); List<Object> args = Arrays.asList(point.getArgs()); Object result = null; try { System.out.println("Before === " + methodName + "方法执行开始:" + args); result = point.proceed();//执行目标方法 System.out.println("AfterReturning === " + methodName + "方法执行结束;" + result); } catch (Throwable throwable) { System.out.println("AfterThrowing === " + methodName + "方法执行结束;" + throwable); throw new RuntimeException(throwable); } System.out.println("After === " + methodName + "方法执行结束;"); return result; }

注解内的参数为切入点表达式,指明通知对哪些方法生效

表达式格式:访问修饰符 返回值 包名.类名.方法名(参数列表) 标准写法:public int com.dudu.aspect.CalculatorImpl.add(int, int) 访问修饰符可以省略:int com.dudu.aspect.CalculatorImpl.add(int, int) 返回值可以使用通配符:* com.dudu.aspect.CalculatorImpl.add(int, int) 包名也可以使用通配符,但是包的层数必须对应:* *.*.*.CalculatorImpl.add(int, int) 也可以使用 … 来表示当前包及其子包:* *…CalculatorImpl.add(int, int) 类名和方法名都可以使用通配符:* *…*.* (int, int) 参数列表可以使用通配符,但是参数的个数必须对应,也可以使用 … 来表示有无参数均可 全通配写法为:* *…*.*(…)

JoinPoint类:可以获取一些连接细节

joinPoint.getArgs() 获取参数列表 joinPoint.getSignature().getName() 获取方法名

切面的优先级(@Order注解) 数字越小,优先级越高

@Order(2) @Component @Aspect public class LoggingAspect { } 重用切入点表达式 //声明 @Pointcut(value = "execution(* com.dudu.aspect.CalculatorImpl.*(..))") public void desc(){} //使用,使用全限定类名加方法名可以跨包使用 @AfterReturning("desc()") public void afterMethodReturn(JoinPoint joinPoint, Object result) { //方法体 }

3. XML版本的配置

<aop:config> <aop:pointcut id="desc" expression="execution(* com.dudu.xml.CalculatorImpl.*(..))"/> <aop:aspect ref="loggingAspect" order="2"> <!--<aop:around pointcut-ref="desc" method="aroundMethod"/>--> <aop:before pointcut-ref="desc" method="beforeMethod"/> <aop:after method="afterMethod" pointcut-ref="desc"/> <aop:after-returning method="afterMethodReturn" pointcut-ref="desc" returning="result"/> <aop:after-throwing method="afterMethodThrow" pointcut-ref="desc" throwing="ex"/> </aop:aspect> <aop:aspect ref="validationAspect" order="1"> <aop:before method="check" pointcut-ref="desc"/> </aop:aspect> </aop:config>
最新回复(0)