新手入门之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 注解定义了一个环绕通知,它在方法调用前后都执行,并且可以控制方法的执行流程。

`

相关推荐
DEARM LINER10 分钟前
mysql 巧妙的索引
数据库·spring boot·后端·mysql
liuyang-neu1 小时前
力扣 简单 70.爬楼梯
java·算法·leetcode
喵手1 小时前
Java 与 Oracle 数据泵实操:数据导入导出的全方位指南
java·开发语言·oracle
硬汉嵌入式2 小时前
H7-TOOL的LUA小程序教程第16期:脉冲测量,4路PWM,多路GPIO和波形打印(2024-10-25, 更新完毕)
开发语言·junit·小程序·lua
Wx120不知道取啥名2 小时前
C语言之长整型有符号数与短整型有符号数转换
c语言·开发语言·单片机·mcu·算法·1024程序员节
开心工作室_kaic3 小时前
ssm010基于ssm的新能源汽车在线租赁管理系统(论文+源码)_kaic
java·前端·spring boot·后端·汽车
Python私教3 小时前
Flutter颜色和主题
开发语言·javascript·flutter
代码吐槽菌3 小时前
基于SSM的汽车客运站管理系统【附源码】
java·开发语言·数据库·spring boot·后端·汽车
Ws_3 小时前
蓝桥杯 python day01 第一题
开发语言·python·蓝桥杯
zdkdchao3 小时前
jdk,openjdk,oraclejdk
java·开发语言