目录

AOP:Aspect Oriented Programming(面向切面编程、面向方面编程)

AOP有几个核心概念:连接点、通知、切入点、切面、目标对象

1. 连接点(Join Point)

2. 切入点(Pointcut)

 3. 通知(Advice)

 4. 切面(Aspect)

 5. 目标对象(Target Object)

概念总结图

举个生活中的例子帮助理解

✅ 总结:

✅ 1. @Before 前置通知

参数说明:

✅ 示例:

✅ 2. @AfterReturning 返回后通知

参数说明:

✅ 示例:

✅ 3. @AfterThrowing 异常通知

参数说明:

✅ 示例:

✅ 4. @After 最终通知

参数说明:

✅ 示例:

✅ 5. @Around 环绕通知

参数说明:

✅ 示例:

⚠️ 注意事项总结


AOP:Aspect Oriented Programming(面向切面编程、面向方面编程)

面向切面编程就是面向特定方法编程。

举个栗子:当我们开发了很多的功能后,我想统计每个方法的执行的时长,从而看看哪些功能需要优化,那么那么多方法,我难道要在每个方法开始时都记录时间,再在结束时再记录时间最后相减吗?这太繁琐了,那么能不能不修改原本的业务代码还能便捷的统计时间呢,当然是可以的,这时候就可以使用aop,比如:

只需要定义一个切面类,就这样就可以实现这个功能,而且还支持自由的修改作用的范围,也能精确定位到需要使用的位置。

所以,AOP的优势主要体现在以下四个方面:

  • 减少重复代码:不需要在业务方法中定义大量的重复性的代码,只需要将重复性的代码抽取到AOP程序中即可。

  • 代码无侵入:在基于AOP实现这些业务功能时,对原有的业务代码是没有任何侵入的,不需要修改任何的业务代码。

  • 提高开发效率

  • 维护方便

AOP有几个核心概念:连接点、通知、切入点、切面、目标对象

✨ 如果你能理解这些概念的含义和它们之间的关系,AOP 基本上就入门了!


1. 连接点(Join Point)

定义:程序执行过程中明确的点,比如 方法的调用、异常的抛出、字段的修改,这些都是连接点。

Spring AOP 限制:Spring AOP 只支持方法级别的连接点(也就是方法调用)。

举例:一个 UserService 里有 login()register() 方法,这两个方法都是连接点。

连接点是你“有机会”织入增强逻辑的地方。


2. 切入点(Pointcut)

定义切入点是对连接点的筛选规则。也就是说:你选中了哪些连接点进行增强操作。

通俗理解:连接点是所有的方法,切入点是你“感兴趣”的那些方法。

常见语法

@Pointcut("execution(* com.sky.service..*.*(..))")

这表示:匹配 com.sky.service 包及子包下的所有方法。

切入点 ≈ 哪些方法需要被增强。


 3. 通知(Advice)

定义:你到底“在这些方法前后做了什么事”。

通知就是增强逻辑本身,比如:

  • 记录日志(Log)

  • 权限校验

  • 参数校验

  • 异常处理

  • 事务控制

类型有五种

类型描述
@Before方法执行前执行
@AfterReturning方法成功执行后执行
@AfterThrowing方法抛出异常后执行
@After无论方法是否异常,最终都会执行
@Around最强!方法执行的前后你都可以控制
@Slf4j
@Component
@Aspect
public class MyAspect1 {
    //前置通知
    @Before("execution(* com.itheima.service.*.*(..))")
    public void before(JoinPoint joinPoint){
        log.info("before ...");

    }

    //环绕通知
    @Around("execution(* com.itheima.service.*.*(..))")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("around before ...");

        //调用目标对象的原始方法执行
        Object result = proceedingJoinPoint.proceed();
        
        //原始方法如果执行时有异常,环绕通知中的后置代码不会在执行了
        
        log.info("around after ...");
        return result;
    }

    //后置通知
    @After("execution(* com.itheima.service.*.*(..))")
    public void after(JoinPoint joinPoint){
        log.info("after ...");
    }

    //返回后通知(程序在正常执行的情况下,会执行的后置通知)
    @AfterReturning("execution(* com.itheima.service.*.*(..))")
    public void afterReturning(JoinPoint joinPoint){
        log.info("afterReturning ...");
    }

    //异常通知(程序在出现异常的情况下,执行的后置通知)
    @AfterThrowing("execution(* com.itheima.service.*.*(..))")
    public void afterThrowing(JoinPoint joinPoint){
        log.info("afterThrowing ...");
    }
}

通知 = 我们到底要织入什么功能逻辑。


 4. 切面(Aspect)

定义切面是一个模块化的横切关注点,包含切入点 + 通知。

简单理解就是:一个切面类,把“哪些方法需要增强” + “增强的内容”组合在一起。

@Aspect
@Component
public class LogAspect {

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

    @Before("serviceMethods()")
    public void beforeLog(JoinPoint joinPoint) {
        System.out.println("方法执行前打印日志:" + joinPoint.getSignature());
    }
}

切面 = 切入点 + 通知的集合,是 Spring AOP 的主角!


 5. 目标对象(Target Object)

定义:你真正要增强的“业务对象”,比如 UserServiceImpl

Spring 会基于它创建代理对象(AOP 代理),增强功能会织入到这个代理对象中。

目标对象 = 被切面增强的类。


概念总结图

        通知(Advice)     --->  你要做什么(增强逻辑)
              ↑
切面(Aspect)= 切入点 + 通知
              ↓
        切入点(Pointcut) --->  你对哪些方法做增强
              ↓
        连接点(JoinPoint)---> 程序里所有可能被增强的点
              ↓
        目标对象(Target) ---> 被增强的类(比如 UserServiceImpl)

举个生活中的例子帮助理解

比如你是个“智能门卫系统”:

  • 👁️‍🗨️ 所有住户都可以进出大门(连接点)

  • 🚪 你只想记录晚上 10 点以后的出入(切入点)

  • 📸 你在这些人经过时拍照/记录(通知)

  • 📦 这个系统打包成了一个完整模块(切面)

  • 👤 被监控的人就是住户本人(目标对象)


✅ 总结:

概念一句话解释
Join Point(连接点)程序中可以被增强的所有点(方法)
Pointcut(切入点)你选中了哪些方法
Advice(通知)你想干什么(增强逻辑)
Aspect(切面)通知 + 切入点的合集
Target Object(目标对象)被增强的业务类

 

不同类型的通知(Advice)在 Spring AOP 中,参数列表是有要求的,尤其是:

  • 你要使用 JoinPointProceedingJoinPoint

  • 想获取方法的返回值或异常信息

  • 想访问注解、目标类、参数等信息


✅ 1. @Before 前置通知

方法签名要求:

@Before("切点表达式")
public void 方法名(JoinPoint joinPoint)

参数说明:

参数类型说明
JoinPointorg.aspectj.lang.JoinPoint可选参数,用来获取方法名、参数等信息

✅ 示例:

@Before("execution(* com.sky.service.*.*(..))")
public void beforeAdvice(JoinPoint joinPoint) {
    System.out.println("方法名:" + joinPoint.getSignature().getName());
    System.out.println("参数:" + Arrays.toString(joinPoint.getArgs()));
}

✅ 2. @AfterReturning 返回后通知

方法签名要求:

@AfterReturning(value = "切点表达式", returning = "result")
public void 方法名(JoinPoint joinPoint, Object result)

参数说明:

参数类型说明
JoinPoint可选方法调用的上下文信息
result必须有,名称要和注解里的 returning 一致返回值

✅ 示例:

@AfterReturning(value = "execution(* com.sky.service.*.*(..))", returning = "result")
public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
    System.out.println("返回结果:" + result);
}

✅ 3. @AfterThrowing 异常通知

方法签名要求:

@AfterThrowing(value = "切点表达式", throwing = "ex")
public void 方法名(JoinPoint joinPoint, Throwable ex)

参数说明:

参数类型说明
JoinPoint可选方法上下文
exThrowable 或其子类抛出的异常对象,名称要和 throwing 对应

✅ 示例:

@AfterThrowing(value = "execution(* com.sky.service.*.*(..))", throwing = "ex")
public void afterThrowingAdvice(JoinPoint joinPoint, Exception ex) {
    System.out.println("发生异常:" + ex.getMessage());
}

✅ 4. @After 最终通知

方法签名要求:

@After("切点表达式")
public void 方法名(JoinPoint joinPoint)

参数说明:

参数类型说明
JoinPoint可选获取方法名、参数等

✅ 示例:

@After("execution(* com.sky.service.*.*(..))")
public void afterAdvice(JoinPoint joinPoint) {
    System.out.println("方法执行完毕:" + joinPoint.getSignature().getName());
}

✅ 5. @Around 环绕通知

方法签名要求:

@Around("切点表达式")
public Object 方法名(ProceedingJoinPoint joinPoint) throws Throwable

参数说明:

参数类型说明
ProceedingJoinPointJoinPoint 的子类,必须是唯一参数可通过 proceed() 控制方法执行

✅ 示例:

@Around("execution(* com.sky.service.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("方法执行前:" + joinPoint.getSignature().getName());
    Object result = joinPoint.proceed(); // 调用目标方法
    System.out.println("方法执行后:" + result);
    return result;
}

⚠️ 注意事项总结

通知类型是否可以写 JoinPoint是否可以获取返回值是否可以获取异常是否可以阻止执行
@Before
@AfterReturning✅(可选)✅(需配置 returning)
@AfterThrowing✅(可选)✅(需配置 throwing)
@After✅(可选)
@Around❌(只能是 ProceedingJoinPoint)

关于切入点表达式可自行搜索相关资料,在此不多赘述

注意:本文引用了黑马程序员javaweb+ai的文档的内容

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐