文章目录
一、AOP是什么?
面向切面编程(AOP,Aspect-Oriented Programming)是一种编程范式,通过分离横切关注点来提高模块化程度。AOP 允许开发者定义可以在代码执行的某些点(切点)执行的额外行为(切面),从而避免代码的重复和冗余。
1. AOP的核心概念
切面(Aspect)
切面是 AOP 的核心概念之一,代表一个横切关注点的模块化。切面可以包含多个通知(Advice),这些通知定义了切面在特定切点(Join Point)上的行为。
连接点(Join Point)
连接点是在程序执行的过程中可以插入切面的具体点。Spring AOP 支持的方法执行连接点,意味着切面可以在方法调用前后或方法抛出异常时执行。
切点(Pointcut)
切点是一个表达式,定义了哪些连接点会被切面切入。切点表达式通常使用类名、方法名、参数等信息来指定需要织入的连接点。
通知(Advice)
通知是切面在切点处所执行的代码。通知有多种类型,包括前置通知(Before)、后置通知(After)、返回通知(After Returning)、异常通知(After Throwing)和环绕通知(Around)。
目标对象(Target Object)
目标对象是被一个或多个切面切入的对象。Spring AOP 使用 JDK 动态代理或 CGLIB 代理来为目标对象创建代理对象。
AOP代理(AOP Proxy)
AOP 代理是由 AOP 框架生成的对象,用于实现切面契约。Spring AOP 使用 JDK 动态代理来代理实现接口的类,使用 CGLIB 来代理没有实现接口的类。
2. AOP的优势
模块化
通过 AOP,可以将日志记录、事务管理、安全性等横切关注点与业务逻辑分离,提升代码的模块化程度,使得每个模块职责单一、清晰。
代码复用
AOP 使得相同的横切关注点代码可以在多个模块中复用,减少代码重复,提升代码的可维护性。
解耦
业务逻辑代码与横切关注点代码解耦,业务逻辑代码更加简洁、清晰,横切关注点的变化不会影响业务逻辑代码。
3. AOP的实现方式
编译时织入
在编译代码时将切面织入目标代码,使用编译器提供的机制将横切关注点的代码编译到目标类中。这种方式的代表是 AspectJ。
类加载时织入
在类加载时通过类加载器将切面织入目标类。这种方式需要定制类加载器,较为复杂。
运行时织入
在应用程序运行时通过动态代理技术将切面织入目标对象。这是 Spring AOP 采用的方式,通过 JDK 动态代理或 CGLIB 实现。
4. Spring AOP概述
Spring AOP 是 Spring 框架的一部分,提供了简单易用的 AOP 功能。Spring AOP 使用动态代理实现运行时织入,并支持基于注解和基于 XML 的配置方式。Spring AOP 主要用于处理方法级别的横切关注点,适用于大多数企业应用场景。
二、Spring Boot AOP 基础
1. 引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>
2. 创建切面
importorg.aspectj.lang.annotation.Aspect;importorg.aspectj.lang.annotation.Before;importorg.springframework.stereotype.Component;@Aspect@ComponentpublicclassLoggingAspect{@Before("execution(* com.example.service.*.*(..))")publicvoidlogBeforeMethod(){System.out.println("A method is about to be executed.");}}
@Aspect
注解表明该类是一个切面类,
@Component
注解将其注册为 Spring 容器的一个 Bean。
@Before
注解用于定义前置通知,在目标方法执行前执行。
3. 定义切点
切点定义了切面织入的具体位置,可以通过
@Pointcut
注解来定义。
importorg.aspectj.lang.annotation.Pointcut;@Pointcut("execution(* com.example.service.*.*(..))")publicvoidserviceLayer(){}
@Pointcut
注解定义了一个名为
serviceLayer
的切点,该切点匹配
com.example.service
包中的所有方法执行。
4. 应用通知
通知是在切点处执行的代码,可以在目标方法执行前后或抛出异常时执行。Spring AOP 提供了多种类型的通知,如前置通知、后置通知、返回通知、异常通知和环绕通知。
后置通知
后置通知在目标方法执行后执行:
importorg.aspectj.lang.annotation.After;@After("execution(* com.example.service.*.*(..))")publicvoidlogAfterMethod(){System.out.println("A method has just been executed.");}
环绕通知
环绕通知可以在目标方法执行前后执行,并且可以控制目标方法的执行:
importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.ProceedingJoinPoint;@Around("execution(* com.example.service.*.*(..))")publicObjectlogAroundMethod(ProceedingJoinPoint joinPoint)throwsThrowable{System.out.println("Method execution start.");Object result = joinPoint.proceed();// 执行目标方法System.out.println("Method execution end.");return result;}
@Around
注解定义了一个环绕通知,
ProceedingJoinPoint
对象用于执行目标方法。环绕通知在目标方法执行前后打印日志信息。
三、实战案例
1. 日志记录
创建一个记录日志的切面
importorg.aspectj.lang.JoinPoint;importorg.aspectj.lang.annotation.AfterReturning;importorg.aspectj.lang.annotation.Aspect;importorg.aspectj.lang.annotation.Before;importorg.springframework.stereotype.Component;@Aspect@ComponentpublicclassLoggingAspect{@Before("execution(* com.example.controller.*.*(..))")publicvoidlogBefore(JoinPoint joinPoint){System.out.println("Executing: "+ joinPoint.getSignature().getName());}@AfterReturning(pointcut ="execution(* com.example.controller.*.*(..))", returning ="result")publicvoidlogAfterReturning(JoinPoint joinPoint,Object result){System.out.println("Executed: "+ joinPoint.getSignature().getName()+", Returned: "+ result);}}
@Before
注解定义了前置通知,记录方法执行前的信息。@AfterReturning
注解定义了后置返回通知,记录方法执行后的返回结果。logBefore
方法在com.example.controller
包下的所有方法执行之前打印日志,记录即将执行的方法名称。logAfterReturning
方法在com.example.controller
包下的所有方法执行之后打印日志,记录方法名称和返回结果。
2. 事务管理
创建一个事务管理的切面
importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.annotation.Aspect;importorg.springframework.stereotype.Component;@Aspect@ComponentpublicclassTransactionAspect{@Around("@annotation(org.springframework.transaction.annotation.Transactional)")publicObjectmanageTransaction(ProceedingJoinPoint joinPoint)throwsThrowable{System.out.println("Transaction start.");Object result = joinPoint.proceed();System.out.println("Transaction end.");return result;}}
@Around
注解定义了环绕通知,用于在方法执行前后执行自定义逻辑。manageTransaction
方法在带有@Transactional
注解的方法执行前后打印事务开始和结束的日志。ProceedingJoinPoint
对象用于执行目标方法,并在目标方法执行前后插入自定义逻辑。
版权归原作者 武帝为此 所有, 如有侵权,请联系我们删除。