AOP
概念 : AOP为Aspect Oriented Programming的缩写, 意思为切面编程。
他是一种可以在不修改原来核心代码的情况下给程序动态统一进增强的一种技术
springAOP : 批量对spring容器中的bean的方法做增强,并且这种增强不会与原来方法中的代码耦合
依赖
<dependency> <groupId>org.aspect</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.13</version> </dependency>
快速入门实现
定义切面类
@Component //将类交给容器去管理 @Aspect //作用 : 告诉Spring容器,这是一个切面类 public class MyAspect{ }
切入点
@Component //将类交给容器去管理 @Aspect //作用 : 告诉Spring容器,这是一个切面类 public class MyAspect{ //定义切入点 @Pointcut("execution("需要增强的路径地址")") public void pt(){} //在被调用的方法之前执行 @Before("pt()") //增强是针对哪些方法 public void methodbefore(){ } }
aop核心概念
连接点 : 【joinpoint】所谓的连接点就是能够被增强到的点,在spring中 只支持方法类型的连接点
切入点 : 【pointcut】所谓的切入点,就是指被增强的连接点
**通知/增强 :【Advice】 **所谓的通知是指jurisdiction增强的代码
**目标对象 : 【Target】 **被增强的对象就是目标对象
切面: 【Aspect】: 是指切入点 和通知(引介) 的 结合
**代理 : 【Proxy】 **一个类被aop增强后,所产生一个结果的代理类
切入点
1.**切入点表达式: **
举例:
2.切点函数(用的不多)
我们可以在要增强的方法上加上注解。然后使用@annotation来表示对加了什么注解的方法进行增强。
/** * 自定义注解 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface SystemLog { String businessName(); }
1.在自定义注解上需要加
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
2.在需要被注解增强的相关方法上加上我们自定义的注解的注解名就可以实现增强
3.在切面类上进行添加切入点等信息
通知
几种通知的分类
package tech.pdai.springframework.aspect; import org.aspectj.lang.ProceedingJoinPoint; /** * @author pdai */ public class LogAspect { /** * 环绕通知. * * @param pjp pjp * @return obj * @throws Throwable exception */ public Object doAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("-----------------------"); System.out.println("环绕通知: 进入方法"); Object o = pjp.proceed(); System.out.println("环绕通知: 退出方法"); return o; } /** * 前置通知. */ public void doBefore() { System.out.println("前置通知"); } /** * 后置通知. * * @param result return val */ public void doAfterReturning(String result) { System.out.println("后置通知, 返回值: " + result); } /** * 异常通知. * * @param e exception */ public void doAfterThrowing(Exception e) { System.out.println("异常通知, 异常: " + e.getMessage()); } /** * 最终通知. */ public void doAfter() { System.out.println("最终通知"); } }
环绕通知
如何使用 ?
@Around("pt()") public Object doAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("-----------------------"); System.out.println("环绕通知: 进入方法前"); Object o = pjp.proceed(); System.out.println("环绕通知: 退出方法后"); return o; }
注意点 : 如果目标方法有返回值 ,那么对应的切面类中的环绕通知的方法也必须有返回值
AspectJ注解方式
基于XML的声明式AspectJ存在一些不足,需要在Spring配置文件配置大量的代码信息,为了解决这个问题,Spring 使用了@AspectJ框架为AOP的实现提供了一套注解。
获取被增强方法相关信息
我们实际对方法进行增强时往往还需要获取到被增强方法的相关信息,比如 : 方法名,参数,返回值,异常信息….
我们除了在环绕通知外的所有通知方法中增加一个JoinPoint类型的参数。这个参数封装了被增强方法的相关信息 。我们还可以通过这个参数获取到除了异常对象 和返回值 之外的所有信息。
//对于controller层的方法增强 private void handleBefore(ProceedingJoinPoint joinPoint) { ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = requestAttributes.getRequest(); //获取被增强方法上的注解对象 SystemLog systemLog = getSystemLog(joinPoint); log.info("============Start============"); // 打印请求 URL log.info("URL : {}",request.getRequestURL()); // 打印描述信息 log.info("BusinessName : {}",systemLog.businessName()); // 打印 Http method log.info("HTTP Method : {}",request.getMethod()); // 打印调用 controller 的全路径以及执行方法 log.info("Class Method : {}.{}",joinPoint.getSignature().getDeclaringTypeName(),((MethodSignature) joinPoint.getSignature()).getName()); // 打印请求的 IP log.info("IP : {}",request.getRemoteHost()); // 打印请求入参 log.info("Request Args : {}", JSON.toJSONString(joinPoint.getArgs()) ); }
//对于service层的方法增强 private void handleBefore(ProceedingJoinPoint joinPoint) { String className = joinPoint.getSignature().getDeclaringTypeName(); System.out.println("获取 类名: " + className); String methodName = joinPoint.getSignature().getName(); System.out.println("获取方法名 : " + methodName); Object[] args = joinPoint.getArgs(); System.out.println("获取参数;" + Arrays.toString(args)); System.out.println("获取参数(转为json格式);" + JSON.toJSONString(args)); }
异常
多切面增强顺序
通过@Order的大小来规定多个切面的顺序
参考学习说明:
视频学习 : 三更springAOP
相关资料参考 :https://pdai.tech/md/spring/spring-x-framework-aop.html