【spring】05 spring AOP的深入理解

Spring框架的AOP机制就是面向切面,它可以让开发者把业务流程中的通用功能抽取出来,单独编写功能代码,AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。
在这里插入图片描述
知识网
在这里插入图片描述

术语

Aspect(切面)
在这里插入图片描述

切面就是通知和切点的结合,简单的说使用@Aspect的类就是切面

advice(增强,又叫通知)
在这里插入图片描述

切面有必须要完成的工作,在AOP中,切面的工作被称为通知。我理解的通知就是切面的具体逻辑,通知定义了切面是什么以及何时使用,除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题,它应该在某个方法之前?之后?之前和之后都调用?还是只在方法抛出异常时调用?

类型

  • Before - 这些类型的 Advice 在 JoinPoint 方法之前执行,并使用 @Before 注解标记进行配置。
  • After Returning - 这些类型的 Advice 在连接点方法正常执行后执行,并使用 @AfterReturning 注解标记进行配置。
  • After Throwing - 这些类型的 Advice 仅在 JoinPoint 方法通过抛出异常退出并使用 @AfterThrowing 注解标记配置时执行。
  • After Finally - 这些类型的 Advice 在连接点方法之后执行,无论方法退出是正常还是异常返回,并使用 @After 注解标记进行配置。
  • Around - 这些类型的 Advice 在连接点之前和之后执行,并使用 @Around 注解标记进行配置。

对于Spring AOP,会将advice模拟为一个拦截器,并在jion point上维护多个advise,层层拦截,比如http鉴权,我们可以为每个@RequestMapping标注的方法织入advise,当请求发过来的时候首先进入advise,进行鉴权,如果有就执行controller,没有就抛出异常。

jion point(连接点)

连接点是应用程序执行过程中,能够插入切面的一个点。

point cut(切点)

是在连接点的基础上定义切点,比方说一个类由十几个方法,每个方法的调用前和调用后都可以插入通知,但是你只想选择几个方法插入通知,因此你定义一个切点来选择你想插入的通知的方法。

weaving(织入)

织入是将增强处理添加到目标对象中,并创建一个新的被增强的对象,切面在指定的连接点被织入到目标对象中。在目标对象的生命周期里有多个点可以进行织入

  • 编译期,编译器织入需要特殊的编译器
  • 类加载期,类加载器织入需要特殊的类加载器
  • 运行期,在运行期为目标类添加增强生成子类的方式,spring的AOP 是在运行期织入通知的

深入理解AOP

AOP 的实现方式

AOP 具体是如何实现的呢?
① 静态代理 - 指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强。
编译时编织(特殊编译器实现)
类加载时编织(特殊的类加载器实现)。

② 动态代理 - 在运行时在内存中“临时”生成 AOP 动态代理类,因此也被称为运行时增强。目前 Spring 中使用了两种动态代理库:
JDK 动态代理
CGLIB

jdk和cglib的区别

// From 《Spring 源码深度解析》P172
// Spring AOP 部分使用 JDK 动态代理或者 CGLIB 来为目标对象创建代理。
(建议尽量使用 JDK 的动态代理)
// 如果被代理的目标对象实现了至少一个接口,则会使用 JDK 动态代理。
所有该目标类型实现的接口都讲被代理。
// 若该目标对象没有实现任何接口,则创建一个 CGLIB 代理。
// 如果你希望强制使用 CGLIB 代理,(例如希望代理目标对象的所有方法,
而不只是实现自接口的方法)那也可以。但是需要考虑以下两个方法:
//      1> 无法通知(advise) Final 方法,因为它们不能被覆盖。
//      2> 你需要将 CGLIB 二进制发型包放在 classpath 下面。
// 为什么 Spring 默认使用 JDK 的动态代理呢?笔者猜测原因如下:
//      1> 使用 JDK 原生支持,减少三方依赖
//      2> JDK8 开始后,JDK 代理的性能差距 CGLIB 的性能不会太多。

JDK 动态代理

JDK 动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是 InvocationHandler 接口和 Proxy 类。

CGLIB 动态代理

如果目标类没有实现接口,那么 Spring AOP 会选择使用 CGLIB 来动态代理目标类。当然,Spring 也支持配置,强制使用 CGLIB 动态代理。
CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB 是通过继承的方式做的动态代理,因此如果某个类被标记为 final ,那么它是无法使用 CGLIB 做动态代理的。

实战

以下例子来自:https://segmentfault.com/a/1190000007469982,通过例子说下自己的理解

sring aop的方式有两种:(1)xml文件配置方式(2)注解的方式实现,下面的例子都是通过注解方式实现的

例子:权限认证

需求:通过AOP实现HTTP鉴权

1. 写一个AuthChecker的注解

AuthChecker.java:
在这里插入图片描述
2. 实现切面

HttpAopAdviseDefine.java:
在这里插入图片描述

切面中的advise
在这里插入图片描述

通过匹配com.xys.demo1这个路径下的类里面的方法(有AuthChecker注解的方法)
在这里插入图片描述
也就是匹配到了callSomeInterface()方法
在这里插入图片描述

小结

在这里插入图片描述
这也就实现了请求通过/aop/http/user_info的时候首先会被advise拦截,然后进行权限认证,如果有权限就继续执行controller,如果没有就返回

总结

首先编写需要切入业务流程的独立模块(也称为切面)和切入点(模块中的方法);然后在Spring配置文件中配置AOP,添加切入面、切入点以及需要切入的目标Bean;最后编写测试代码。

猜你喜欢

转载自blog.csdn.net/yujing1314/article/details/107439923