Spring AOP构成
切面(Aspect)
在程序中处理具体问题的类,包含切点和通知。
在 AOP 中,横切关注点(横跨多个模块的关注点)被定义为与核心业务逻辑无关的关注点,如日志记录、安全性检查、事务管理等。这些横切关注点通常跨越了多个模块或类,并且可能在程序的不同部分重复出现。为了将这些横切关注点与核心业务逻辑分离,AOP 引入了切面(Aspect)的概念。切面是一个独立的模块,包含了与横切关注点相关的逻辑。在运行时,AOP 框架会动态地将切面中的逻辑切入到程序的特定点上,从而实现对程序执行过程的拦截和干预。
切点(Pointcut)
用来进行指定主动拦截的规则(决定哪些方法需要被增强)
通知(Advice)
用于实现切面的具体逻辑。并且也是需要增加到业务方法中的公共代码。
前置通知(@Before):在切点方法执行之前执行的通知。可以在方法执行之前做一些准备工作或参数校验等操作。
后置通知(@AfterReturning):在切点方法成功执行后执行的通知。可以获取切点方法的返回值,并进行一些后续处理。
异常通知(@AfterThrowing):在切点方法抛出异常时执行的通知。可以捕获异常并进行相应的处理操作,例如日志记录或异常处理。
最终通知(@After):无论切点方法正常执行还是抛出异常,最终通知都会在切点方法执行完毕后执行。它类似于finally块中的代码,不管是否发生异常都会执行。
环绕通知(@Around):环绕通知是最为灵活的通知类型,它可以完全控制切点方法的执行。在切点方法执行之前和之后都可以插入自定义的逻辑。需要在环绕通知中显式地调用 proceed() 方法来触发切点方法的执行。
这些通知注解可以与切点(Pointcut)注解一起使用,来定义在哪些方法或类上应用通知。通过在切面(Aspect)类中结合使用这些注解,可以实现对目标方法的增强功能。
连接点(Join Point)
可能触发APO规则的点(请求),指定被增强的业务方法就是连接点
添加依赖
创建切面
使用注解@Aspect搭配Spring中的五大注解
@Aspect//切面类
@Component//随着Spring的启动而启动
public class UserAspect {
}
创建切点
/**
* 切点————配置拦截规则
*/
@Pointcut("execution(* com.example.demoapo.controller.UserController.*(..))")
public void pointcut(){
}
execution是最常见的切点函数:创建通知
/**
* 前置通知
* */
@Before("pointcut()")
public void beforeAdvice(){
System.out.println("执行了前置通知");
}
/**
*
* */
@After("pointcut()")
public void afterAdvice(){
System.out.println("执行了后置通知");
}
注意环绕通知写法
/**
* 环绕通知
* */
@Around("pointcut()")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("执行环绕");
Object obj=null;
//执行目标方法;
obj=joinPoint.proceed();
System.out.println("退出环绕");
return obj;
}
原理实现
Spring AOP的实现原理主要基于动态代理机制和反射。
动态代理:
Spring AOP使用动态代理来生成代理对象,并将切面逻辑织入到目标对象的方法中。通过代理对象,可以在目标对象的方法执行前、执行后或异常抛出时插入额外的逻辑,即通知(Advice)。Spring AOP提供了两种动态代理方式:基于JDK动态代理和基于CGLib动态代理。
spring对aop的拦截仅仅局限于方法,
织入
为目标对象创建动态代理的过程被称为织入
编译期:AspectJ织入的编译器就是这种
类加载期:切面在目标类被加载到JVM的时候进行织入
运行期
springaop被织入的方式就是动态代理
动态代理
是指在程序运行时动态生成代理对象的机制。它可以在不修改目标对象的情况下,通过代理对象来对目标对象进行间接访问和控制。
动态代理vs静态代理
静态代理:静态代理是指在编译时就已经确定了代理类和目标类之间的关系,代理类通过实现目标类的接口来拦截目标方法的调用。在运行时,代理类会被直接实例化,并通过调用目标类的接口方法来实现对目标方法的拦截和处理。
动态代理:动态代理是指在运行时动态生成代理类,并通过该代理类来拦截目标方法的调用。动态代理通常使用 Java 的反射机制来实现,通过动态生成字节码来创建代理类,并在运行时将其加载到内存中。
jdk动态代理(默认使用)
jdk只提供接口的代理,不提供类的代理
CGLib动态代理
如果代理类没有实现接口,Spring AOP会选择CGlib来动态代理目标类,代理对象通过继承目标类来拦截方法调用。
无法对final类,praivate方法,static方法实现代理。
需要注意的是,对于 private 方法和 static 方法,虽然无法通过动态代理来实现拦截,但可以通过其他方式来实现类似的功能,例如使用拦截器、过滤器等技术来实现对方法调用的拦截和处理。static 方法是指不需要实例化对象就可以直接调用的方法,它属于类而不是对象。由于动态代理是通过实例化代理类来实现对目标方法的拦截,而 static 方法不需要实例化对象就可以直接调用,因此无法通过动态代理来拦截 static 方法。
Spring的AOP在哪里创建的动态代理
1.bean的生命周期初始化之后;
2.在Bean属性注入时存在的循环依赖的情况下;
AOP 的工作原理
是发生在 Bean 的生命周期过程中的:
Spring 生成 bean 对象时,先实例化出来一个对象,也就是 target 对象
再对 target 对象进行属性填充
在初始化后步骤中,会判断 target 对象有没有对应的切面
如果有切面,就表示当前 target 对象需要进行 AOP
通过 Cglib 或 JDK 动态代理机制生成一个代理对象,作为最终的 bean 对象
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现