新手入门之SpringAOP

学习目标:

了解SpringAOP的基本概念、原理以及使用,帮助初学者入门。


学习内容:

Spring AOP 基本概念

Spring AOP 是 Spring 框架的一个重要组件,它允许你在不修改现有代码的情况下,通过"切面"(Aspect)来添加新的行为或责任。Spring AOP 主要用于实现诸如日志记录、事务管理、权限检查等功能,而这些功能通常被称为"横切关注点"(Cross-Cutting Concerns)。

Spring AOP 支持多种实现方式,主要包括:

动态代理

当目标对象实现了接口时,Spring 会使用 JDK 动态代理来创建代理对象。这种方式利用了 java.lang.reflect.Proxy 类来生成一个实现了目标接口的代理类。这个代理类可以拦截对目标对象的方法调用,并在调用前后添加额外的行为。

**优点:**如果目标对象实现了接口,那么使用 JDK 动态代理通常更轻量,因为不需要生成新的类。

**缺点:**只能用于实现了接口的对象

CGLIB 字节码增强

当目标对象没有实现接口时,Spring 会使用 CGLIB(Code Generation Library)来生成一个继承自目标类的新子类。这个子类同样可以拦截方法调用,并在调用前后添加行为。

**优点:**可以用于任何对象,不论其是否实现了接口。

**缺点:**生成新的子类,可能会导致类的数量增加,以及潜在的性能开销。

AOP核心概念

在 Spring AOP 中,AOP 的核心概念包括切入点(Pointcut)、连接点(Joinpoint)、通知(Advice)、切面(Aspect)等。下面将详细介绍这些概念:

连接点(Joinpoint)

定义: 连接点是指程序执行中的某个特定点,如方法调用、字段访问、异常抛出等。它是一个程序中的具体位置,在这个位置可以插入通知(Advice),连接点是程序中可以插入切面逻辑的位置,是切入点所匹配的具体位置。
作用: 连接点是切入点所匹配的具体位置。每一个切入点实际上匹配了一组连接点,即一组方法调用或事件。

切入点(Pointcut)

定义: 切入点是 AOP 中的一个术语,用于描述哪些地方(即哪些方法调用或类)会被 AOP 的通知所影响。简单来说,就是指明了那些地方将会应用切面的逻辑。切入点是一个或多个连接点的集合,它定义了哪些连接点将应用切面的逻辑。
作用: 切入点决定了通知何时何地执行。它可以是方法执行、异常抛出、构造函数调用等多种类型的连接点。
表达方式: 切入点可以通过表达式来定义,通常使用 Spring 的切入点表达式语言。例如:

(1) execution( com.example.service.. (...)) ** 这个切入点表达式表示匹配 com.example.service 包下的所有类的所有方法,可以通过多个||与execution组合。
(2)
@annotation(org.springframework.stereotype.Service) * 这个切入点表达式表示匹配带有 @Service 注解的方法或类。也可以用自定义注解的方式来实匹配切入点方法,使用时只需要在对于类上加上该注解就可以。


注意: @PointCut注解是将公共的切入点表达式抽取出来,需要用到时引用该切入点表达式即可。

通知(Advice)

定义: 通知是 AOP 中执行的代码块,它在切入点所匹配的连接点处被调用。通知定义了切面在特定连接点上执行的行为。

通知类型:

前置通知(@Before): 在方法调用之前执行的通知。
后置通知(@After): 在方法调用之后执行的通知,无论方法是否成功执行。
返回后通知(@After Returning ): 在方法成功执行后执行的通知。
抛出异常后通知(@After Throwing ): 在方法抛出异常后执行的通知。
环绕通知(@Around 重点): 在方法调用前后都执行的通知,可以控制是否继续执行方法。
注意: @Around环绕通知需要自己调用ProceedingJoinPoint.proceed()来让原始方法执行,其他通知不需要考虑目标方法执行。

@Around环绕通知方法的返回值,必须指定为Object,来接收原始方法的返回值。

通知执行顺序:

当有多个切面的切入点都匹配到了目标方法,目标方法运行时,多个通知方法都会被执行。那么就会有一个先后执行的顺序。
默认执行顺序: 按照切面类,类名的字母排名来确定的,排名越前的前置通知就先执行,相反它的后置通知就越靠后执行。
@Order注解: 加在切面类上来控制顺序,前置通知,数字越小越先执行,后置通知相反。

切面(Aspect)

定义: 切面是由一个或多个通知和相应的切入点组成的模块,它代表了一个横切关注点的实现。
作用: 切面是将横切关注点模块化的手段,它将与业务逻辑无关的代码(如日志记录、事务管理等)从业务逻辑中分离出来。

引入(Introduction)

定义: 引入允许我们在不修改类的情况下向其添加新的接口实现或方法。
作用: 通过引入,可以在不改变类的实现的情况下,让类拥有新的能力。例如,可以让一个类实现一个新的接口,或者添加新的方法。

下面通过一个简单的示例来说明这些概念的应用:

假设我们有一个日志记录的切面,它记录方法调用前后的信息。

切面类的定义

java 复制代码
@Aspect
@Component
public class LoggingAspect {
	/**通知,execution()切入点表达式*/
    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Before method call: " + joinPoint.getSignature().getName());
    }

    @AfterReturning(value = "execution(* com.example.service.*.*(..))", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("After method call: " + joinPoint.getSignature().getName() + ", Result: " + result);
    }

    @AfterThrowing(value = "execution(* com.example.service.*.*(..))", throwing = "exception")
    public void logAfterThrowing(JoinPoint joinPoint, Exception exception) {
        System.out.println("After method threw an exception: " + joinPoint.getSignature().getName() + ", Exception: " + exception.getMessage());
    }

    @After("execution(* com.example.service.*.*(..))")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("After method execution: " + joinPoint.getSignature().getName());
    }

    @Around("execution(* com.example.service.*.*(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Before method call (around): " + joinPoint.getSignature().getName());
        Object result = joinPoint.proceed();
        System.out.println("After method call (around): " + joinPoint.getSignature().getName());
        return result;
    }
}

在这个示例中:

@Before 注解定义了一个前置通知,它在方法调用之前执行。

@AfterReturning 注解定义了一个返回后通知,它在方法成功执行后执行。

@AfterThrowing 注解定义了一个抛出异常后通知,它在方法抛出异常后执行。

@After 注解定义了一个后置通知,它在方法调用之后执行,无论方法是否成功执行。

@Around 注解定义了一个环绕通知,它在方法调用前后都执行,并且可以控制方法的执行流程。

`

相关推荐
AC赳赳老秦6 分钟前
官方技术文档聚合实践:用 OpenClaw 批量抓取开源项目文档,构建离线可检索技术知识库
java·运维·服务器·python·信息可视化·deepseek·openclaw
RuoyiOffice8 分钟前
SpringBoot3+Vue3 会议室预订系统:时段冲突三模式检测 + 会前定时提醒与 cancelByBiz
spring boot·vue3·flowable·消息中心·spring boot 3·会议室·时段冲突
breeze jiang9 分钟前
Next.js App Router 全栈实战:从 SPA 的 SEO 痛点到服务端组件与 Hydration 水合机制
开发语言·javascript·ecmascript
程序员老陆13 分钟前
Qt::WidgetAttribute 常用属性详解
开发语言·qt
略略略咯咯14 分钟前
ActiveMQ
java·activemq·java-activemq
万亿少女的梦16818 分钟前
基于Spring Boot、Java与MySQL的同城宠物服务系统设计与实现
java·spring boot·mysql·系统设计·协同过滤
不才不才不不才19 分钟前
Spring 源码系列(20): @SpringBootApplication 三注解拆解
java·后端·spring
罗小爬EX19 分钟前
AI Chat 多类型流式事件处理方案(以AgentScope Java 2为例)
java·人工智能·状态模式
zhanghaha131423 分钟前
Python进阶教程:5_XML 解析 —— 新手完全指南
java·前端·数据库
andongni20323 分钟前
SpringBoot RESTful API 设计与实现
spring boot·后端·restful