Loading... > 简单说下AOP **AOP 是指通过预编译方式和运行期动态代理的方式,在不修改源代码的情况下对程序进行功能增强的一种技术。AOP 不是面向对象编程(OOP)的替代品,而是 OOP 的补充和扩展。它是一个新的维度,用来表达横切问题,并提供一个声明式的处理方案。AOP 是 Spring 框架中的一个重要特性。** 使用场景很多很多 只要你想不到 就没有AOP做不到的! - 日志记录:在应用程序中,可以通过 AOP 对方法调用进行拦截,在方法调用前后记录日志信息。 - 安全处理:通过 AOP 实现安全方案,例如在应用程序中对某些敏感方法添加权限验证。 - 性能监控:对应用程序进行性能监控,实现性能分析和调优。 - 事物管理:通过 AOP 对事物进行管理,例如实现事物的回滚和提交。 - 缓存管理:对应用程序进行缓存管理,例如在读写操作中进行缓存。 > AOP 的核心概念 在实现AOP有一些核心的东西 (简单 但是很重要!) 1. 连接点(JointPoint) 连接点是程序中可能被拦截的方法。在 AOP 中,连接点是指所有被拦截到的方法。连接点包含两个信息:一个是方法的位置信息,另一个是方法的名称。 2. 切点(Pointcut) 切点是一组连接点的集合,是要被拦截的连接点。在 Spring AOP 中,切点采用 AspectJ 的切点表达式进行描述,格式如 @Pointcut("execution(public * com.likefr.demo.controller.*.*(..))") (其中public 可以省略不写 默认就是public) 3. 通知(Advice) 通知是指拦截到连接点后要执行的代码,包括 @Before、@AfterReturning、@AfterThrowing、@After 和 @Around 五种类型。(其中 @Around 是最强大的类型 可以实现前面4种) 4. 切面(Aspect) 切面是一个包含通知和切点的对象,主要用来维护切点和通知之间的关系。 5.织入(Weaving) 织入是将切面应用到目标对象来创建新的代理对象的过程。在 Spring AOP 中,织入可以在编译时、类加载时和运行时进行。 > AOP 的实现方式 在 SpringBoot 中,AOP 的实现方式主要有两种:Java 代理(JDK Proxy)和字节码增强(CGLIB)。 1. Java 代理(JDK Proxy) Java 代理是一种基于接口的代理,通过实现 Java 动态代理接口 InvocationHandler 来实现对代理类方法的调用。Java 代理只能代理实现了接口的类,在运行时通过生成代理类的方式来实现。Java 代理的优点是操作简单,劣势是只能代理接口。 2. 字节码增强(CGLIB) 字节码增强是一种基于继承的代理,通过生成代理类来完成对目标对象方法的调用。CGLIB 代理不需要实现接口,对目标对象进行继承并重写其中的方法,从而实现对方法的调用拦截。字节码增强的优点是能够代理非接口的类,劣势是需要引入 CGLIB 依赖包。 > Spirngboot AOP 例子 我们创建一个日志切面来记录调用方法开始时间、结束时间、持续时间等(方法名、参数、返回值......)。 首先需要导入核心依赖包 ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <version>${spring-boot.version}</version> </dependency> ``` 首先 声明一个注解 后期就可以在接口 目标方法上定义 定义后将被jdk 动态代理注入我们的日志记录 **注解无非就是一个接口** ```java @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface SysLog { String name() default ""; } ``` 然后定义AOP切面类 LogAspect - 总共分为三部 1 . 在该类上声明 注解 @Aspect 2. 定义切面 3.需要以什么形式去通知 ``` @Aspect // @Component 注解 注入spring容器中 @Component public class LogAspect { // 定义需要被拦截的切点 @Pointcut("execution(public * com.example.demo.controller.*.*(..))") public void pointcut() { } // 在方法执行时进行通知 @Around("pointcut()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); SysLog sysLog = method.getAnnotation(SysLog.class); if (sysLog != null) { System.out.println("日志名称:" + sysLog.name()); } System.out.println("开始时间:" + LocalDateTime.now()); System.out.println("执行方法 " + joinPoint.getSignature().getName() + " 前置环绕通知"); Object o = joinPoint.proceed(); System.out.println("结束时间:" + LocalDateTime.now()); System.out.println("执行方法 " + joinPoint.getSignature().getName() + " 后置环绕通知"); return o; } // 在方法执行之前进行通知 @Before("pointcut()") public void before(JoinPoint joinPoint) { System.out.println("执行方法 " + joinPoint.getSignature().getName() + " 前置通知"); } // 在方法执行之后进行通知 @After("pointcut()") public void after(JoinPoint joinPoint) { System.out.println("执行方法 " + joinPoint.getSignature().getName() + " 后置通知"); } // 在方法执行之后返回结果时进行通知 @AfterReturning(returning = "result", pointcut = "pointcut()") public void afterReturning(JoinPoint joinPoint, Object result) { System.out.println("执行方法 " + joinPoint.getSignature().getName() + " 返回通知,返回值:" + result); } // 在方法抛出异常时进行通知 @AfterThrowing(throwing = "ex", pointcut = "pointcut()") public void afterThrowing(JoinPoint joinPoint, Exception ex) { System.err.println("执行方法 " + joinPoint.getSignature().getName() + " 异常通知,异常:" + ex.getMessage()); } } ``` 使用 @SysLog注解 ```java @RestController() @RequestMapping("user") public class UserController { @SysLog(name = "这是一个日志名称") @GetMapping("test") public String test() { return "hello world"; } ``` 调用接口 会得到如下信息 ``` 日志名称:这是一个日志名称 开始时间:2023-07-17T16:33:11.935 执行方法 test 前置环绕通知 执行方法 test 前置通知 执行方法 test 返回通知,返回值:hello world 执行方法 test 后置通知 结束时间:2023-07-17T16:33:11.940 执行方法 test 后置环绕通知 ``` 整个流程如下: ![2024-01-17T12:35:33.png][1] > 总结 以上就是 SpringBoot AOP 的基本用法,通过使用 SpringBoot AOP,我们可以在不修改源代码的情况下对程序进行功能增强,实现对方法的拦截、日志记录、权限验证、性能监控等功能。 [1]: http://likefr.com/usr/uploads/2024/01/1752408975.png 最后修改:2024 年 01 月 17 日 © 允许规范转载 赞 1 如果觉得我的文章对你有用,请随意赞赏