《Spring》AOP实现原理

  • 1. 概述
  • 2. 代理类型
    • 2.1 静态代理
    • 2.2 动态代理
      • 2.2.1 JDK动态代理
      • 2.2.2 CGLIB动态代理
    • 2.3 何时使用JDK动态代理还是CGLIB?
  • 3. 相关术语
  • 4. 织入方式
  • 5. 通知类型
  • 6. 事务的特性
  • 7. 事务的隔离级别
  • 8. 事务的传播行为
  • 9. 事务的管理方式

1. 概述

SpringAOP(Aspect Orient Programming)是一种设计思想,称为面向切面编程,利用横切技术剖析对象内部,将业务之间共同调用的逻辑提取并封装为一个可复用的模块,这个模块被命名为切面(Aspect),该模块减少系统中的重复代码,降低模块间的耦合度,可用于日志、权限认证、事务管理等。

SpringAOP思想的实现一般都是基于代理模式 ,在Java中采用JDK动态代理模式,但是JDK动态代理模式只能代理接口而不能代理类。因此SpringAOP会在CGLIBJDK动态代理之间进行切换。

2. 代理类型

SpringAOP的实现是基于代理模式 ,代理类型包括:静态代理、动态代理。

2.1 静态代理

AspectJ编译时增强)使用的是静态代理。所谓静态代理指的是,AOP框架会在编译阶段生成AOP代理类,它会在编译阶段将AspectJ植入到Java字节码中,运行的时候就是增强后的AOP对象。

AspectJ实现方式上依赖于特殊的AJC编译器,它并非是SpringAOP框架的一部分,而是SpringAOP使用了AspectJ的Annotation(注解),用来定义切面、切点等功能。

2.2 动态代理

SpringAOP使用的是动态代理。所谓动态代理指的是,AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

2.2.1 JDK动态代理

JDK动态代理要求被代理类必须实现一个接口,核心是InvocationHandler接口和Proxy类。JDK动态代理调用了Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h),通过该方法生成字节码,动态的创建一个代理类。interfaces参数是该动态类所继承的所有接口,而继承InvocationHandler接口的类则是实现在调用代理接口方法前后的具体逻辑。当

我们调用代理类对象的方法时,都会委托到InvocationHandler.invoke(Object proxy, Method method, Object[] args)方法,代理类对象作为proxy参数传入,参数method标识了我们具体调用的是代理类的哪个方法,args为这个方法的参数。

public interface PersonService {void speak(String content);
}public class UserServiceImpl implements PersonService {@Overridepublic void speak(String content) {System.out.println("speak被调用了===" + content);}
}public class JDKProxy implements InvocationHandler {private Object proxy;public JDKProxy(Object proxy) {this.proxy = proxy;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object object = method.invoke(this.proxy, args);return object;}public static void main(String[] args) {PersonService person = (PersonService) Proxy.newProxyInstance(PersonService.class.getClassLoader(), new Class[]{PersonService.class}, new JDKProxy(new UserServiceImpl()));person.speak("我是用户");}
}
2.2.2 CGLIB动态代理

CGLIB(Code Generation Library)底层使用了ASM(一个短小精悍的字节码操作框架)来操作字节码生成新的类,除了CGLIB库外,脚本语言(如Groovy何BeanShell)也使用ASM生成字节码。

CGLIB既能代理接口也能代理类,如果某个类被标记为final,是无法使用CGLIB做动态代理。

相关核心API:

  • net.sf.cglib.proxy.Enhancer:增强类,用来创建动态代理类。
  • net.sf.cglib.proxy.MethodProxy:可以方便的调用代理对象的方法。
  • net.sf.cglib.proxy.MethodInterceptor:方法拦截类,它是Callback接口的子接口需要用户实现。

2.3 何时使用JDK动态代理还是CGLIB?

  • 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP。
  • 如果目标对象实现了接口,可以强制使用CGLIB实现AOP。
  • 如果目标对象没有实现了接口,必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB之间转换。

如果目标类没有实现接口,那么SpringAOP会选择使用CGLIB动态代理目标类

3. 相关术语

  • 切面(Aspect):切面是通知和切点的结合,通知和切点共同定义了切面的全部内容,一般使用@Aspect实现切面的定义;
  • 通知(Advice):通知定义了切面是什么以及何时使用,如Before、After;
  • 切点(PonitCut):切点定义了在何处应用连接点(JoinPonit),通常使用明确的类和方法名称,或是利用正则表达式定义所匹配的类和方法名称来指定这些切点;
  • 连接点(JoinPonit):连接点是在应用执行过程中能够插入切面的一个点,这个点可以是调用方法时、抛出以异常时、甚至修改一个字段时;
  • 目标对象(Target):需要被代理的类,如UserService;
  • 织入(Weaving):织入是把切面应用到目标对象并创建新的代理对象的过程。

4. 织入方式

  • 编译时织入:需要特殊的编译器,如AspectJ;
  • 类加载时织入:需要特殊的类加载器,如ClassLoader;
  • 运行时织入:Spring采用动态代理的方式实现运行时织入,如SpringAOP。

5. 通知类型

  1. 前置通知(Before):在目标方法被调用之前调用通知功能;
  2. 后置通知(After):在目标方法执行完成之后调用通知,此时不会关心方法的输出是什么;
  3. 返回通知(After-returning):在目标方法成功执行之后调用通知;
  4. 异常通知(After-throwing):在目标方法抛出异常后调用通知;
  5. 环绕通知(Around):在被通知的方法调用之前和调用之后执行自定义的行为。

6. 事务的特性

  1. 原子性(Atomacity):事务包含的操作要么全部成功,要么全部失败,即使回滚也不会对数据库产生影响。
  2. 一致性(Consistency):事务必须使数据从一个一致性状态变换到另一个一致性状态,也就是说当一个系统在一致状态下更新后,系统中所有数据都保持一致。
  3. 隔离性(Isolation):当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间相互隔离。
  4. 持久性(Durability):事务一旦被提交,对数据库中的数据的改变就是永久性的,即使数据库系统遇到故障也不会丢失提交事务的操作。

7. 事务的隔离级别

  • TransactionDefinition.ISOLATION_DEFAULT:使用后端数据库默认的隔离级别,MySQL默认采用的REPEATABLE_READ隔离级别。Oracle默认采用的READ_COMMITTED隔离级别。
  • 读未提交TransactionDefinition.ISOLATION_READ_UNCOMMITTED):在这种隔离级别下可能会出现脏读,事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。
  • 读已提交TransactionDefinition.ISOLATION_READ_COMMITTED):在这种隔离级别下可能会出现不可重复读,指事务A多次读取同一条数据,事务B在事务A多次读取的过程中,对数据做了更新并提交,导致事务A多次读取的数据不一致。(可避免脏读的发生,MySQL默认的隔离级别)
  • 可重复读(TransactionDefinition.ISOLATION_REPEATABLE_READ):在这种隔离级别下可能会出现幻读。指在一个事务内,多次读取一个范围内的数据,发现多次读取的结果不一致(记录可能会增多或减少)。例如事务T1在读取一个范围内数据时结果为空,然后事务T2插入了N条数据并提交事务,事务T1再次读取时结果依然为空,然后事务T1插入了M条数据之后再次查询时结果为N+M条数据,这就发生了幻读。(可避免脏读、不可重复读的发生)
  • 可串行化TransactionDefinition.ISOLATION_SERIALIZABLE):就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待。(可避免脏读、不可重复读、幻读的发生)

8. 事务的传播行为

  • 支持事务
    1. PROPAGATION_REQUIRED:如果当前存在事务,则加入事务;反之,则新建事务。
    2. PROPAGATION_SUPPORTS:如果当前存在事务,则加入事务;反之,则以非事务方式执行。
    3. PROPAGATION_MANDATORY:如果当前存在事务,则加入事务;反之,则抛出异常。
  • 不支持事务
    1. PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,则挂起事务。
    2. PROPAGATION_NOT_SUPPORTED:如果当前存在事务,则挂起事务,以非事务方式执行。
    3. PROPAGATION_NEVER:如果当前存在事务,则抛出异常,以非事务方式执行。
  • 其他情况
    1. PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行;反之,则创建一个新事务。

9. 事务的管理方式

  • 编程式事务管理:使用TransactionTemplate。
  • 声明式事务管理:建立在AOP之上的,其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,Spring是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。

《Spring》AOP实现原理相关推荐

  1. Spring AOP实现原理,从代理说起

    前言 为了理解Spring AOP,我们先来了解一下Java的代理模式 什么是代理? 举个例子来说明代理的作用: 假设我们想邀请一位明星,那么并不是直接联系明星,而是联系明星的经纪人,来达到同样的目的 ...

  2. spring注解驱动开发-6 Spring AOP实现原理

    Spring AOP实现原理 前言 1.@EnableAspectJAutoProxy注解原理 2.AnnotationAwareAspectJAutoProxyCreator 分析 1.分析前工作, ...

  3. ppst——技术视频spring AOP 的原理讲解和简单实现

    ppst 技术视频--spring AOP 的原理讲解和简单实现:请访问ppst 技术视频分享平台 , www.ppst.cc,上面有最新的技术视频,推荐大家把博客录制成视频吧,可以获取收益哦 1.s ...

  4. 灵魂画手图解Spring AOP实现原理!

    本篇旨在让读者对Spring AOP实现原理有一个宏观上的认识,因此会丢失一些细节,具体实现参考:老实人Spring源码目录 阅读本篇文章前,希望读者对Spring Ioc以及Spring AOP的使 ...

  5. 探秘Spring AOP (六) Spring AOP 实现原理 1

    2019独角兽企业重金招聘Python工程师标准>>> 探秘Spring AOP 一.织入的时机原理概述 1.编译期(AspectJ) 2.类加载时(AspectJ 5+) 3.运行 ...

  6. Spring AOP 实现原理与 CGLIB 应用--转

    AOP(Aspect Orient Programming),作为面向对象编程的一种补充,广泛应用于处理一些具有横切性质的系统级服务,如事务管理.安全检查.缓存.对象池管理等.AOP 实现的关键就在于 ...

  7. Spring AOP 实现原理与 CGLIB 应用

    WeiboGoogle+用电子邮件发送本页面 10 AOP(Aspect Orient Programming),作为面向对象编程的一种补充,广泛应用于处理一些具有横切性质的系统级服务,如事务管理.安 ...

  8. spring aop实现原理_Spring 异步实现原理与实战分享

    最近因为全链路压测项目需要对用户自定义线程池 Bean 进行适配工作,我们知道全链路压测的核心思想是对流量压测进行标记,因此我们需要给压测的流量请求进行打标,并在链路中进行传递,那么问题来了,如果项目 ...

  9. Spring AOP:原理、 通知、连接点、切点、切面、表达式

    0:Spring AOP 原理 简单说说 AOP 的设计: 每个 Bean 都会被 JDK 或者 Cglib 代理.取决于是否有接口. 每个 Bean 会有多个"方法拦截器".注意 ...

  10. 常见面试题 | Spring AOP 实现原理

    实现AOP的技术,主要分为两大类: 一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执 行:二是采用静态织入的方式,引入特定的语法创建"方面",从而 ...

最新文章

  1. java异常(机制和捕捉(常见异常类))详解 +练习题
  2. Could not find artifact com.sun:tools:jar:1.5.0 解决办法
  3. 成功解决raise XGBoostError(_LIB.XGBGetLastError()) xgboost.core.XGBoostError: b'[22:08:00] C:\\Users\\Ad
  4. spring cloud(三) config
  5. java 释放指针_C库释放来自Rust的指针
  6. 网易自动化UI测试解决方案Airtest Project亮相GDC
  7. 信息安全工程师笔记-网络安全漏洞防护技术原理与应用
  8. 吴恩达深度学习 ——深层神经网络(选择题)
  9. 用python写三角形_python写个三角形的问题
  10. linux编译时开启宏,【spec】Linux上编译安装的spec文件中的常用路径以及宏变量
  11. 使 JavaScript 更加简洁的小技巧
  12. 转换和删除重复命令tr
  13. 双指针 -- 验证回文串
  14. MOQL—筛选器(Selector)(一)
  15. Android 插件化 动态升级
  16. 使用Maven导入MySQL驱动包遇到的问题
  17. php寻仙记,【网站搭建】寻仙记+天空之城两款文字游戏PHP源码
  18. r9270公版bios_显卡成功刷入UEFI GOP BIOS 彻底解决开机扁苹果
  19. database2sharp mysql_Database2Sharp免费版
  20. Dbeaver在公司内网情况下进行编辑驱动

热门文章

  1. 【室内/外设计】天正T20V3.0软件安装教程
  2. 西南大学计算机考研学硕,西南大学心理学学硕343分考研经验
  3. Coap协议学习(二)
  4. matlab二重定积分_MATLAB计算二重数值积分(dblquad)
  5. python3 爬虫 HTTP Error 403:Forbidden
  6. 下载mysql那个版本好_Mysql各个版本区别及官网下载
  7. 发那科机器人示教器按键解读
  8. STM32——电容触摸按键
  9. 强化学习——A3C,GA3C
  10. flame linux mac,Autodesk版蓝宝石插件 GenArts Sapphire V10.0 (Mac/Linux)