杨老师课堂之springAOP事务控制源码解析

spring AOP基于动态代理实现,想看懂源码必须了解动态代理和字节码增强方面的知识。

基于对spring各种配置的了解,首先我们先从DataSourse由谁来管理入手。了解AOP。

一般来讲首先会配置一个datasource,至于你配置什么连接池还是用JNDI这里就不提到细节,总之我们认为配置的spring的全局名称为dataSource就可以了。

接下来会将datasource交给各种连接池的操作类,如:ibatis、jdbcTemplate等等,这些不是我们关心的重点,我们需要关心的是dataSource是谁来管理了,在spring中配置了给一个DataSourceTransactionManager的对象:

[html] view
plain
 copy

  1. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  2. <property name="dataSource">
  3. <ref bean="dataSource" />
  4. </property>
  5. </bean>

ok,先记录下来,至于下面的NameMatchTransactionAttributeSource描述了那些情况要进行事务管理,我们将它理解为一种属性配置,在运行时需要解析即可,所以他也并不是我们特别需要的重点。

接下里看看:TransactionInterceptor,它看起来有点像拦截器了,他将transactionManager包装进去了;

[html] view
plain
 copy

  1. <bean id="txInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
  2. <property name="transactionManager">
  3. <ref bean="transactionManager"/>
  4. </property>
  5. <property name="transactionAttributeSource">
  6. <ref bean="txAttributes"/>
  7. </property>
  8. </bean>

这里是一个点,再继续看,BeanNameAutoProxyCreator,这个看名字就知道是自动代理的类了,并且包装了TransactionInterceptor的对象进去,也就是这个地方就是代理,然后会将事务的处理交给TransactionInterceptor拦截器来完成,可能这个不是我们的重点,不过简单看看也无妨,这个类细节代码就不贴了,进去你会看到就是讲拦截器包装后,然后通过beanName设置哪些类需要被拦截,根据你的配置来完成,spring 后来基于annotation实现的就不是这样,他会扫描类中的annotation来实现类似的功能。

一起来简单看看TransactionInterceptor吧:

细节代码太多,看关键代码,红色部分表示出来了,其实在AOP调用中,我们比较关注invoke、intercept这类代码关联字的方法,因为proxy调用的就是他们,由他们自己去调用其他的方法,这里invoke首先发现在事务下,首先调用了createTranscationIfNecessary这个方法。

跟踪进去看看:

这里看到开始获取TransactionManager了,get方法没啥好看的,配置文件注入进去了,我们看看tm.getTranscation里头做了啥。

也就是跟踪到你set的那个TranscationManager里头去了,PlatformTransactionManager有多个实现类,注意选择自己实现的那部分:本程序中叫:DataSourceTransactionManager,跟踪进去看看getTransaction方法

这个代理类,需要注意几个加红色的地方:

1、目前看来应该是获事务的方法

2、部分如果发现事务对象获取到就直接返回

3、做一个doBegin的操作,这i类关键字一般是指切入时的预先操作,那么闲看看这个doBegin干啥了

我们想要的东西来了,相信看到第二个红色区域部分,大家都会很熟悉自己做事务是怎么做的,发现spring也是这样做的。

将connection做了一个setAutoCommit(false);非自动提交模式,接下来就要看如何和框架结合起来了,如何让调用的时候使用到这个connection,调用方如何知道使用这个connection;

看另外两个红色的部分:

第一个红色部分可以看出是获取事务对象若为空(不是事务或已经是事务),则从datasource对象中获取一个connection,包装成一个handle,放入事务对象中(事务对象内部的包装请自己去看下)。

而第三个额部分是,如果是一个新的ConnectionHandler(其实判定的是一些状态,使用中,spring会修改handler的状态,这也是为什么spring要包装一个handler了,因为需要自定义的很多状态信息);他执行了一个

[java] view
plain
 copy

  1. TransactionSynchronizationManager.bindResource(getDatasource() , txObject.getConnectionHolder());

这样一个操作,可见:TransactionSynchronizationManager提供了一个静态方法getDatasource(),看名称是绑定的意思,那么绑定什么呢?我们跟踪进去看看:

咦,resouces貌似里面有一个map,如果为空,就put一个进去,那么resouce是个什么东西呢?他会不会有线程冲突的问题?

看看resouces是什么:

ThreadLocal,对了,就是它了,有关ThreadLocal的原理和细节,我这不想多提,也不是这里的重点,这里明确的就是,虽然它是全局的一个静态属性,不过他是线程安全的,不论是get还是set还是remove。

我们知道这个connection被绑定到当前运行的线程中了,接下来只需要在使用时从这个里面获取出来即可。

我们再回到上面看到的doTransaction方法还没看细节,这里来看看。

可以看到,它果然是从这里来获取保存到当前线程的connection。

貌似看得差不多了,好像少了一半,那一半,datasouces是各个厂家的,他们的各自的datasouce方法是自己的,getConnection内部有自己的算法,如何做到他们在getConnection的时候,执行相应的,这个时候,我们来看看一个拦截connection的方式:TransactionAwareDataSourceProxy,

他内部有啥道理所在:

这里可以看到使用了动态代理,获取相应的datasouces,那么就找到对应的代理类里面去看看他的invoke方法是什么:

TransactionAwareInvocationHandler里面,可以跟踪这个是一个内部类了,进去看看他的invoke方法:

可以看到切入的位置,向上看到两个红色部分是要去获取connection,我们跟踪进去看看:

接下来的就不用多说了吧,回到刚才的代码,不论是doGetConnection还是doReleaseConnection内部都会调用

[java] view
plain
 copy

  1. TransactionSynchronizationManager.getResource(datasouce)

来获取当前线程的connection。

当然各种连接操作对象也会有自己的transaction操作,他们也会去做setAutoCommit等相应的操作。不过最外层设置后,getConnection方法保证后,内部的操作几乎就可以跳过了。

时间: 2024-10-12 00:44:49

杨老师课堂之springAOP事务控制源码解析的相关文章

杨老师课堂由杨亦涛主讲

杨老师课堂由杨亦涛主讲,他是资深网站工程师和UI设计讲师,10年网站开发与教学经验,上百个网站项目成功案例. 擅长技术:UI界面视觉.UI界面交互.网站设计及开发. 曾担任高级网站工程师,主持各种大型网站设计与开发,主攻UI界面视觉.UI界面交互. 曾就职大业工业设计公司.四川九洲电子集团等知名企业. 曾自主创建亦涛工作室,专门从事网站建设.软件开发等业务. 原文地址:https://www.cnblogs.com/yangsir0576/p/10712432.html

Spring事务源码解析(二)获取增强

在上一篇文章@EnableTransactionManagement注解解析中,我们搭建了源码阅读的环境,以及解析了开启Spring事务功能的注解@EnableTransactionManagement的实现逻辑 在进行接下来的源码解析之前我想大家应该知道,当我们使用传统的jdbc应用事务的时候是不是做了如下操作: 开启事务 save.update.delete等操作 出现异常进行回滚 正常情况提交事务 而在Spring中我们好像只需要关心第三步,也就是我们的业务,而其他的操作都不需要关心.那么

杨老师课堂之ArrayList集合常用方法解析

ArrayList集合常用方法的解析 1.概述 ? 在前面我们学习了数组,数组可以保存多个元素,但在某些情况下无法确定到底要保存多少个元素,此时数组将不再适用,因为数组的长度不可变.例如,要保存一个学校的学生,由于不停有新生来报道,同时也有学生毕业离开学校,这时学生的数目很难确定.为了保存这些数目不确定的元素,JDK中提供了一系列特殊的类,这些类可以存储任意类型的元素,并且长度可变,统称为集合.在这里,我们先介绍ArrayList集合,其他集合在后续课程中学习. ? ArrayList集合是程序

结合ThreadLocal来看spring事务源码,感受下清泉般的洗涤!

在我的博客spring事务源码解析中,提到了一个很关键的点:将connection绑定到当前线程来保证这个线程中的数据库操作用的是同一个connection.但是没有细致的讲到如何绑定,以及为什么这么绑定:另外也没有讲到连接池的相关问题:如何从连接池获取,如何归还连接到连接池等等.那么下面就请听我慢慢道来. ThreadLocal 讲spring事务之前,我们先来看看ThreadLocal,它在spring事务中是占据着比较重要的地位:不管你对ThreadLocal熟悉与否,且都静下心来听我唐僧

spring事务源码研读1

转载摘录自:Spring事务源码分析(一)Spring事务入门 有时为了保证一些操作要么都成功,要么都失败,这就需要事务来保证. 传统的jdbc事务如下: @Test public void testAdd(){ Connection con=null; try { con=DriverManager.getConnection(url , username , password ) con.setAutoCommit(false); //操作一 PreparedStatement ps = c

互评Alpha版本——杨老师粉丝群——Pinball

一.基于NABCD评论作品,及改进建议 1.根据(不限于)NABCD评论作品的选题 (1)N(Need,需求) 成语学习对除汉语言专业外的大学生的需求并不是很高,初中生和高中生因为在升学时需要参加语文科目考试,虽然有一定的需求但是在课堂上的学习量就已足够.儿童和小学生对成语学习的需求是最大的,我国正在大力进行基础教育课程改革,并且包括成语在内的国学也越来越受到重视.而<Pinball>项目主要目标即是儿童,因此我认为这个选题准确的. (2)A(Approach,做法) <弹球学成语>

消息中间件 RocketMQ源码解析:事务消息

关注微信公众号:[芋艿的后端小屋]有福利: RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表 RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址 您对于源码的疑问每条留言都将得到认真回复.甚至不知道如何读源码也可以请教噢. 新的源码解析文章实时收到通知.每周更新一篇左右. 1. 概述 2. 事务消息发送 2.1 Producer 发送事务消息 2.2 Broker 处理结束事务请求 2.3 Broker 生成

COJ 0500 杨老师的路径规划(MST)最小生成树

杨老师的路径规划(MST) 难度级别:B: 运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 为满足同学们需求,杨老师在实验楼4层新建了好多个计算机教室供同学们使用.可是这样的话,由于路径很长,杨老师发现越来越难亲自走到每一个机房看看同学们有没有在玩游戏了.请你现在帮杨老师设计一个程序,给你每个教室间的路径长,设计出一条路线使每两个教室间都能联通且总长度最小,你只需要输出这个最小值即可.(裸MST) 输入 测试用例的第1行给出教室数目N ( 

勤奋的杨老师

题目描述 杨老师认为他的学习能力曲线是一个拱形.勤奋的他根据时间的先后顺序罗列了一个学习清单,共有n个知识点.但是清单中的知识并不是一定要学习的,可以在不改变先后顺序的情况下有选择的进行学习,而每一个知识点都对应一个难度值.杨老师希望,后学习的知识点的难度一定不低于前一个知识点的难度(i<j时ai<=aj),而可能存在一个临界点,在临界点以后,他希望后学习的知识点的难度一定不高于前一个知识点的难度(i<j时ai>=aj).杨老师想尽可能多的学习知识.请问:杨老师最多可以学习多少知识