🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 一、AOP * **连接点(Join point)** 表示你想在什么地方插代码,比如方法执行的地方或者处理异常的地方; * **切入点(Pointcut)** 用来匹配一堆连接点; * **通知(Advice)** 在连接点上执行的代码; * **切面(Aspect)** 切面文件里具体指明在哪个切入点执行什么通知(Advice) * **引入(Introduction)** 给类新增方法或者成员 * **目标对象(Target object)** 在谁身上切 * **织入(weaving)** 将切面和目标对象绑一块儿 通知(Advice)的运行方式还有好几种: * 连接点之前 * 连接点之后 * 围绕连接点 * 发生异常的时候 * 管它正常还是异常 ## 二、引入步骤 在pom中引入依赖; ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> ``` >[danger] 当我们需要使用CGLIB来实现AOP的时候,需要配置spring.aop.proxy-target-class=true,不然默认使用的是标准Java的实现。 ## 三、使用方法 使用@Aspect注解将一个java类定义为切面类; 使用@Pointcut定义一个切入点,可以是一个规则表达式,也可以是一个注解等; 使用@Before在切入点开始处切入内容(基于切入点来定义); 使用@After在切入点结尾处切入内容(基于切入点来定义); 使用@AfterReturning在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理); 使用@Around在切入点前后切入内容,并自己控制何时执行切入点自身的内容; 使用@AfterThrowing用来处理当切入内容部分抛出异常之后的处理逻辑; ### **@Pointcut** execution:用于匹配方法执行的连接点 within:用于匹配指定类型内的方法执行 this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也* 类型匹配 target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配 args:用于匹配当前执行的方法传入的参数为指定类型的执行方法 @within:用于匹配所以持有指定注解类型内的方法 @target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解 @args:用于匹配当前执行的方法传入的参数持有指定注解的执行 @annotation:用于匹配当前执行方法持有指定注解的方法 bean:Spring AOP扩展的,AspectJ没有对于指示符,用于匹配特定名称的Bean对象的执行方法 ## 四、注意事项 1、切面中定义基本类型会有同步问题(多线程调用),使用ThreadLocal来解决; 2、使用@Order(seq)注解来标识切面的优先级,seq的值越小,优先级越高,在切入点前的操作,按order的值由小到大执行;在切入点后的操作,按order的值由大到小执行; ## 五、例子 ``` @Aspect @Order(1) @Component public class RayLoggerAspect { private Logger logger = LoggerFactory.getLogger(this.getClass()); private ThreadLocal<Long> mehtodStartTime = new ThreadLocal<>();// 这里定义基本类型会有同步问题 /** * 定义的切入点为org.ray包下面的所有函数; */ @Pointcut("execution(public * org.ray.rayframework.system.controller..*.*(..))") public void logPoint() { } /** * 通过@Before实现,对请求内容的日志记录 * @param joinPoint * @throws Throwable */ @Before("logPoint()") public void doActionBefore(JoinPoint joinPoint) throws Throwable { mehtodStartTime.set(System.currentTimeMillis()); ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attributes != null) { HttpServletRequest request = attributes.getRequest(); logger.error("request url is{}" + request.getRequestURL().toString()); logger.error("request ip is{}" + request.getRemoteAddr()); logger.error("request parameters is{}" + Arrays.toString(joinPoint.getArgs())); } } /** * 通过@AfterReturning 记录请求返回的对象 * @param returnObject * @throws Throwable */ @AfterReturning(returning = "returnObject", pointcut = "logPoint()") public void doActionAfterReturning(Object returnObject) throws Throwable { logger.warn("returnObject is {} " + returnObject); logger.warn("method cost time is {} " + (System.currentTimeMillis() - mehtodStartTime.get())); } } ```