1. 什么是 AOP?

AOP(Aspect-Oriented Programming)面向切面编程,是一种编程范式,旨在将程序中的横切关注点(如日志、安全、事务)从业务逻辑中分离出来,进行统一管理。

  • 切面(Aspect):模块化关注点,比如日志切面。
  • 连接点(Join point):程序执行中的点,如方法调用。
  • 通知(Advice):切面在连接点执行的动作。
  • 切入点(Pointcut):定义在哪些连接点执行通知。
  • 目标对象(Target Object):被代理的业务对象。
  • 代理对象(Proxy):增强后的业务对象。

2. Spring AOP 的工作原理

  • Spring 使用 动态代理(JDK代理或CGLIB代理)为目标对象创建代理。
  • 代理对象在调用方法时,根据切入点匹配,执行对应通知。
  • 通过切面和通知,实现方法增强。

3. Spring AOP 术语解析

术语说明
Aspect切面,包含通知和切点的模块化代码
Join Point连接点,程序执行的点(通常是方法)
Pointcut切入点,定义一组连接点的表达式
Advice通知,切面执行的动作(前置、后置等)
Target目标对象,业务逻辑对象
Proxy代理对象,增强目标对象的对象

4. Spring AOP 常见通知类型

通知类型说明
Before方法调用前执行
After方法调用后执行(无论是否异常)
AfterReturning方法成功返回后执行
AfterThrowing方法抛异常后执行
Around环绕通知,包裹方法执行

5. 简单 Spring AOP 示例代码

5.1 定义切面类

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

@Aspect
public class LoggingAspect {

    @Before("execution(* com.example.service.*.*(..))")
    public void beforeAdvice() {
        System.out.println("方法执行前 - 记录日志");
    }

    @After("execution(* com.example.service.*.*(..))")
    public void afterAdvice() {
        System.out.println("方法执行后 - 释放资源");
    }

    @Around("execution(* com.example.service.*.*(..))")
    public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕通知 - 方法执行前");
        Object retVal = pjp.proceed();  // 调用目标方法
        System.out.println("环绕通知 - 方法执行后");
        return retVal;
    }
}

5.2 业务类

package com.example.service;

public class UserService {
    public void addUser() {
        System.out.println("执行添加用户业务");
    }
}

5.3 Spring 配置(基于注解)

<context:component-scan base-package="com.example"/>
<aop:aspectj-autoproxy/>

5.4 测试调用

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = ctx.getBean(UserService.class);
userService.addUser();

运行输出:

环绕通知 - 方法执行前
方法执行前 - 记录日志
执行添加用户业务
环绕通知 - 方法执行后
方法执行后 - 释放资源

6. Spring AOP 代理类型

代理类型说明适用情况
JDK 动态代理基于接口,代理实现接口的类目标类实现接口
CGLIB 代理基于子类,生成目标类的子类代理目标类未实现接口

7. @Pointcut 复用切入点表达式

@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethods() {}

@Before("serviceMethods()")
public void beforeAdvice() {
    System.out.println("前置通知");
}

8. 常用切入点表达式示例

表达式说明
execution(* com.example..*.*(..))匹配 com.example 包及子包的所有方法
within(com.example.service.*)匹配 com.example.service 包内所有类
args(java.lang.String)匹配参数是字符串的方法

9. 总结

  • Spring AOP 用于解耦横切关注点,增强代码复用与维护性。
  • 通过切面(Aspect)、切入点(Pointcut)、通知(Advice)实现灵活控制。
  • 代理机制分为 JDK 动态代理和 CGLIB 代理。
  • 注解配置和 XML 配置都支持。