Spring-AOP理解
Spring 框架的一个关键组件是面向方面的编程(AOP)框架。面向方面的编程需要把程序逻辑分解成不同的部分称为所谓的关注点。跨一个应用程序的多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样的常见的很好的方面的例子,如日志记录、审计、声明式事务、安全性和缓存等。
在 OOP 中,关键单元模块度是类,而在 AOP 中单元模块度是方面。依赖注入帮助你对应用程序对象相互解耦和 AOP 可以帮助你从它们所影响的对象中对横切关注点解耦。AOP 是像编程语言的触发物,如 Perl,.NET,Java 或者其他。
AOP 术语
在我们开始使用 AOP 工作之前,让我们熟悉一下 AOP 概念和术语。这些术语并不特定于 Spring,而是与 AOP 有关的。
项 | 描述 |
---|---|
Aspect(切面) | 一个模块具有一组提供横切需求的 APIs。例如,一个日志模块为了记录日志将被 AOP 方面调用。应用程序可以拥有任意数量的方面,这取决于需求。 |
Join point(连接点) | 在你的应用程序中它代表一个点,你可以在插件 AOP 方面。你也能说,它是在实际的应用程序中,其中一个操作将使用 Spring AOP 框架。 |
Advice (通知) | 这是实际行动之前或之后执行的方法。这是在程序执行期间通过 Spring AOP 框架实际被调用的代码。 |
Pointcut (切入点) | 这是一组一个或多个连接点,通知应该被执行。你可以使用表达式或模式指定切入点正如我们将在 AOP 的例子中看到的。 |
Introduction(引入) | 引用允许你添加新方法或属性到现有的类中。 |
Target object(目标) | 被一个或者多个方面所通知的对象,这个对象永远是一个被代理对象。也称为被通知对象。 |
Weaving(织入) | Weaving 把方面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时,类加载时和运行时完成。 |
Spring AOP 模块提供拦截器来拦截一个应用程序,例如,当执行一个方法时,你可以在方法执行之前或之后添加额外的功能。AOP 不是 OOP 的对立面,它是对 OOP 的一种补充。OOP 是纵向的,AOP 是横向的,两者相结合方能构建出良好的程序结构。AOP 技术,让我们能够不修改原有代码,便能让切面逻辑在所有业务逻辑中生效。其实现原理在切点处生成一个代理类,从而对原接口进行方法的增强。
关于动态代理查看此篇动态代理内容:代理模式
通知(Advice)的类型
Spring 方面可以使用下面提到的五种通知工作:
通知 | 描述 |
---|---|
前置通知(Before) | 在一个方法执行之前,执行通知。 |
后置通知 (After) | 在一个方法执行之后,不考虑其结果,执行通知。 |
返回后通知 (AfterReturning) | 在一个方法执行之后,只有在方法成功完成时,才能执行通知。 |
抛出异常后通知 (AfterThrowing) | 在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。 |
环绕通知 (Around) | 在建议方法调用之前和之后,执行通知。 |
切点(PointCut)的类型
指示器 | 描述 |
---|---|
execution() | 用于匹配方法执行的连接点 |
within() | 用于匹配指定的类及其子类中的所有方法 |
this() | 匹配可以向上转型为this指定的类型的代理对象中的所有方法 |
target() | 匹配可以向上转型为target指定的类型的目标对象中的所有方法 |
args() | 用于匹配运行时传入的参数列表的类型为指定的参数列表类型的方法 |
@within() | 用于匹配持有指定注解的类的所有方法 |
@target() | 用于匹配的持有指定注解目标对象的所有方法 |
@args() | 用于匹配运行时 传入的参数列表的类型持有 注解列表对应的注解的方法 |
@annotation() | 用于匹配持有指定注解的方法 |
bean | bean(Bean的id或名字通配符)匹配特定名称的Bean对象 |
使用实例:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import java.util.Arrays;
/**
* @author: xiaoyin
* @date: 2021/12/1 16:11
* @description:
*/
public class LogAspect {
//配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点
/**定义切点, **/
@Pointcut("execution(* com.xy.designmodel.proxy..*(..))")
public void aspect(){
}
@Before("aspect()")
public void before(JoinPoint joinPoint){
System.out.println("before " + joinPoint);
}
@After("aspect()")
public void after(JoinPoint joinPoint){
System.out.println("after " + joinPoint);
}
@Around("aspect()")
public void around(ProceedingJoinPoint joinPoint){
try {
System.out.println("方法执行前。。");
joinPoint.proceed();
System.out.println("方法执行后。。");
} catch (Throwable e) {
e.printStackTrace();
}
}
@AfterReturning("aspect()")
public void afterReturn(JoinPoint joinPoint){
System.out.println("方法返回后执行。。"+joinPoint);
}
@AfterThrowing(pointcut="aspect()", throwing="ex")
public void afterThrow(JoinPoint joinPoint, Exception ex){
System.out.println("抛出异常后执行。。"+joinPoint);
}
}
Leave a Reply