下面主要讲述,springboot如何使用AOP功能
AOP(Aspect Oriented Programming),面向切面思想,是Spring的三大核心思想之一(两外两个:IOC-控制反转、DI-依赖注入)。
那么AOP为何那么重要呢?在我们的程序中,经常存在一些系统性的需求,比如权限校验、日志记录、统计等,这些代码会散落穿插在各个业务逻辑中,非常冗余且不利于维护。
简单地去理解,其实AOP要做三类事:
- 在哪里切入,也就是权限校验等非业务操作在哪些业务代码中执行。
- 在什么时候切入,是业务代码执行前还是执行后。
- 切入后做什么事,比如做权限校验、日志记录等。
一些概念详解:
Pointcut
:切点,决定处理如权限校验、日志记录等在何处切入业务代码中(即织入切面)。切点分为execution
方式和annotation
方式。前者可以用路径表达式指定哪些类织入切面,后者可以指定被哪些注解修饰的代码织入切面。Advice
:处理,包括处理时机和处理内容。处理内容就是要做什么事,比如校验权限和记录日志。处理时机就是在什么时机执行处理内容,分为前置处理(即业务代码执行前)、后置处理(业务代码执行后)等。Aspect
:切面,即Pointcut
和Advice
。Joint point
:连接点,是程序执行的一个点。例如,一个方法的执行或者一个异常的处理。在 Spring AOP 中,一个连接点总是代表一个方法执行。Weaving
:织入,就是通过动态代理,在目标对象方法中执行处理内容的过程。
使用 AOP,首先需要引入 AOP 的依赖。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
具体实现如下:
1. 创建一个AOP切面类,只要在类上加个 @Aspect 注解即可。@Aspect 注解用来描述一个切面类,定义切面类的时候需要打上这个注解。@Component 注解将该类交给 Spring 来管理。
package com.fourthgroup.sms.aop; import com.google.gson.Gson; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.context.annotation.Configuration; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; @Slf4j //下面两个注解是必须的,少一个都不行哦 @Aspect @Configuration public class InformationAop { //标记切入点,为指定包下的所有类的所有public方法 @Pointcut("within(com.fourthgroup.sms.controller..*)&& !within(com.fourthgroup.sms.controller.InformationController)") public void informationLog() { } @Around(value = "informationLog()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); //打印入参 log.info("请求入参 {}", new Gson().toJson(joinPoint.getArgs())); Object object = joinPoint.proceed(); //打印出参 log.info("请求出参 {}", new Gson().toJson(object)); return object; } }
测试:
打印成功