SpringAOP

Spring AOP

不改变原有代码的情况下增强原有逻辑

实现方式

Spring支持两种AOP实现:

  • Spring AOP(基于Advisor):轻量级,仅支持方法拦截。这是 Spirng 自家的
  • AspectJ:功能完整,支持字段、构造器等拦截。这是三方框架
维度 Spring AOP(Advisor) AspectJ
拦截范围 仅 Spring Bean 的 public 方法 任意对象、字段、构造器等
性能 有代理调用开销 无运行时开销
配置复杂度 简单(注解驱动) 需配置织入器(LTW/CTW)
适用场景 事务、日志等常见需求 需要拦截非Spring对象的场景
底层实现 基于动态代理 基于字节码增强

优先用Spring AOP:适合大多数场景(如@Transactional

必要时用AspectJ:需要拦截非 Spring 对象或字段/构造器时

核心概念

概念 说明 人话
Aspect(切面) 封装横切逻辑的模块 @Aspect 注解的类,就是我们自己定义的类
Target(目标对象) 被增强的原始对象 目标对象
Join Point(连接点) 程序执行的点(如方法调用、异常抛出) 目标对象所有方法
Pointcut(切点) 选中的连接点 目标对象被增强的方法
Advice(通知) 切面在连接点执行的动作 前置、后置、返回、异常和环绕等
Proxy(代理对象) Advisor 特有 Advisor 基于动态代理实现
Weaving(织入) AspectJ 特有 AspectJ 需配置织入器(LTW 或 CTW 两种方式)

通知类型

通知类型 执行时机 说明
@Before 目标方法执行前 如果通知中 return 或抛出异常,目标方法不会执行
@AfterReturning 目标方法 成功返回后 通过连接点可以拿到目标方法的返回值做一些处理
目标方法如果抛出异常,本通知不会执行
@AfterThrowing 目标方法 抛出异常后 通过连接点可以拿到异常信息做一些处理
比如事物回滚,资源恢复等
@After 目标方法 结束后(无论成败) 无论目标方法是否异常都会执行
@Around 包围目标方法(需手动调用 ProceedingJoinPoint.proceed() 前面4种通知的合体

切点表达式

更详细的切点表达式介绍 看这里

  • execution:匹配方法执行(最常用)。

    @Before("execution(public * com.example.service.*.*(..))")
    
  • @annotation:匹配自定义注解标记的方法。

    @Around("@annotation(com.example.LogExecutionTime)")
    

增强 Spring bean 示例

JDK 和 cglib 动态代理增强

动态代理增强Spring bean

使用 Advisor 增强

@Aspect
@Component
public class LogAspect {
    @Around("* com.example.User.sayHello(..)") // 增强 sayHello 方法
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("执行前.....");
      	Object result = joinPoint.proceed();
      	System.out.println("执行后.....");
      	return result;
    }
}

Advisor 和 AspectJ 示例

Advisor

Advisor 更详细的介绍 看这里

@Aspect
@Component
public class LogAspect {
    // 拦截Service层所有方法
    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore(JoinPoint jp) {
        System.out.println("调用方法: " + jp.getSignature().getName());
    }
}

AspectJ

AspectJ 更详细的介绍 看这里

@Aspect // 无需@Component!
public class SecurityAspect {
    // 拦截 File 对象的构造方法调用
    @After("call(java.io.File.new(..))")
    public void logFileCreation() {
        System.out.println("文件被创建!");
    }
}
posted @ 2024-11-02 20:25  CyrusHuang  阅读(45)  评论(0)    收藏  举报