目录
实现步骤:
1 导入AOP依赖
2 编写切面Aspect
3 编写通知方法
4 指定切入点表达式
5 测试AOP动态织入
图示:
一 实现步骤:
1 导入AOP依赖
<!-- Spring Boot AOP依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>
2 编写切面Aspect
@Aspect // 标记为切面类
@Component // 由Spring容器管理
public class LogAspect {// 切入点表达式和通知方法在此定义
}
3 编写通知方法
通知方法(Advice) 是面向切面编程(AOP)中的核心概念,表示在目标方法(或切入点)的某个执行阶段插入的增强逻辑。通俗来说,就是“在某个地方(切入点)做某件事(增强逻辑)”。
通知方法的类型
Spring AOP 提供了5种通知类型,对应不同的执行时机:
注解 | 执行时机 | 典型场景 |
---|---|---|
@Before | 目标方法执行前 | 参数校验、权限验证 |
@After | 目标方法执行后(无论是否抛出异常) | 资源清理、日志记录 |
@AfterReturning | 目标方法正常返回后(无异常时执行) | 记录结果、缓存数据 |
@AfterThrowing | 目标方法抛出异常后 | 异常处理、告警通知 |
@Around | 包围目标方法(可自定义方法执行前后逻辑,甚至阻止方法执行) | 性能监控、事务管理 |
代码实现:
package org.example.spring02.aspect;import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;@Component
@Aspect
public class LogAspect {public void logStart() {System.out.println("【切面-日志】开始");}public void logEnd() {System.out.println("【切面-日志】结束");}public void logReturn() {System.out.println("【切面-日志】返回");}public void logException() {System.out.println("【切面-日志】异常:");}}
4 指定切入点表达式
作用:通过表达式定义哪些方法需要被拦截。
语法结构:
execution([访问权限] 返回类型 包名.类名.方法名(参数类型) [异常类型])
代码实现:
精确指定接口的路径:
@Before("execution(int org.example.spring02.MathMethod.MathCalculator.*(..))")public void logStart() {System.out.println("【切面-日志】开始");}
package org.example.spring02.aspect;import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;@Component
@Aspect
public class LogAspect {@Before("execution(int *(int,int))")public void logStart() {System.out.println("【切面-日志】开始");}@After("execution(int *(int,int))")public void logEnd() {System.out.println("【切面-日志】结束");}@AfterReturning("execution(int *(int,int))")public void logReturn() {System.out.println("【切面-日志】返回");}@AfterThrowing("execution(int *(int,int))")public void logException() {System.out.println("【切面-日志】异常:");}}
5 测试AOP动态织入
package org.example.spring02;import org.example.spring02.MathMethod.MathCalculator;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
public class AopTest {@AutowiredMathCalculator mc;@Testpublic void test01() {int add = mc.add(1, 2);System.out.println(add);}}
二 说说你对AOP的理解?
AOP全称叫做 Aspect Oriented Programming(面向切面编程)。它是为解耦而生的,解耦是程序员编码开发过程中一直追求的境界。AOP在业务类的隔离上,做到了解耦,其核心概念包括:
核心概念
-
切面(Aspect)
指关注点的模块化,这些关注点可能会横切多个对象。例如,事务管理是企业级Java应用中常见的横切关注点。在Spring AOP中,切面可以通过以下方式实现:-
通用类基于模式的方式(schema-based approach)。
-
在普通类中使用
@Aspect
注解(@AspectJ 注解方式)。
-
-
连接点(Join Point)
在程序执行过程中某个特定的点,例如方法调用的时间点或异常处理的时间点。在Spring AOP中,连接点仅表示方法的执行。 -
通知(Advice)
在切面的特定连接点上执行的动作。通知类型包括:-
around
(环绕通知):包裹目标方法执行。 -
before
(前置通知):在目标方法执行前触发。 -
after
(后置通知):在目标方法执行后触发。
许多AOP框架(包括Spring)通过拦截器模型实现通知,并维护以连接点为中心的拦截器链。
-
-
切点(Pointcut)
匹配连接点的断言。通知通过切点表达式与连接点关联,并在满足条件的连接点上执行。Spring默认使用AspectJ切点语义,切点表达式与连接点的匹配是AOP的核心机制。 -
引入(Introduction)
向目标对象声明额外的方法或字段。Spring允许向被通知的对象引入新接口(及其实现)。例如,可通过引入使Bean实现IsModified
接口以简化缓存机制(在AspectJ社区中,引入也称为“内部类型声明”)。 -
目标对象(Target Object)
被一个或多个切面通知的对象,也称为“被通知对象”。由于Spring AOP基于运行时代理实现,目标对象始终是被代理的对象。 -
AOP代理(AOP Proxy)
AOP框架创建的对象,用于实现切面契约(如通知方法的执行)。在Spring中,AOP代理可以是以下两种类型:-
JDK动态代理(基于接口)。
-
CGLIB代理(基于子类继承)。
-
总结
AOP通过解耦横切关注点(如日志、事务、安全等),提升代码复用性和可维护性。其核心思想是通过代理机制和动态织入,将公共逻辑与业务逻辑分离,最终实现高内聚、低耦合的系统设计。
任何一个系统都是由不同的组件组成的,每个组件负责一块特定的功能。当然,会存在很多与业务无关的组件,例如日志、事务、权限等核心服务组件。这些核心服务组件经常融入到具体的业务逻辑中。如果我们为每一个具体业务逻辑操作都添加这样的代码,很明显会导致代码冗余过多。因此,我们需要将这些公共的代码逻辑抽象出来,变成一个切面,然后注入到目标对象(具体业务)中去。正是基于这样的一个思路实现的。通过动态代理的方式,将需要注入切面的对象进行代理。在进行调用的时候,将公共的逻辑直接添加进去,而不需要修改原有业务的逻辑代码。只需要在原来的业务逻辑基础之上做一些增强功能即可。