SpringBoot启动源码解读(13)

Spring事务的代码:

    总体来说,Spring的事务主要是基于 切面AOP实现。在调用方法之前,创建事务,等方法执行完成,提交事务。主要涉及2个注解:@EnableTransactionManagement 和 @Transactional。

    1:注解@EnableTransactionManagement里 ,引入TransactionManagementConfigurationSelector,在Spring的启动过程中,会执行 TransactionManagementConfigurationSelector 的 selectImports 方法,会返回AutoProxyRegistrar 和ProxyTransactionManagementConfiguration类。代码如下:

    2:在AutoProxyRegistrar类里,会注册InfrastructureAdvisorAutoProxyCreator,该类继承 SmartInstantiationAwareBeanPostProcessor 接口,这个bean后置器处理器在创建bean实例的时候会调用该接口的函数:postProcessAfterInitialization。

    3:在配置类ProxyTransactionManagementConfiguration中,会创建实例 PointcutAdvisor 切面观察者接口实例,类名:BeanFactoryTransactionAttributeSourceAdvisor 。会添加属性:TransactionAttributeSource 和 TransactionInterceptor。

    4:在bean创建过程中,可能会创建 getEarlyBeanReference 和 postProcessAfterInitialization 方法,这两个方法的的内容差不多,如下:

    5:wrapIfNecessary 方法会调用方法 getAdvicesAndAdvisorsForBean,该方法调用findEligibleAdvisors 方法查找当前合适的 Advisor。在 findAdvisorBeans 里会从IOC中查找到 Advisor 类型的bean定义。这个时候会找到第3部分注册的信息。类型为:BeanFactoryTransactionAttributeSourceAdvisor。

    6:BeanFactoryTransactionAttributeSourceAdvisor 实例的 pointcut 属性对象的类型是:TransactionAttributeSourcePointcut 。其继承了StaticMethodMatcherPointcut。再上一步获取到定义的 Advisor之后,会调用 AopUtils#findAdvisorsThatCanApply 方法进行匹配过滤。由于 继承了PointcutAdvisor,所以会调用 AopUtils#canApply(Pointcut,Class<?>, boolean) 方法。

    7:TransactionAttributeSourcePointcut 的属性classFilter 是 ClassFilter.TRUE 实例,其matches 方法只会返回true。getMethodMatcher 方法获取到的是其本身,所以最终会获取该类所有申明的方法,对每个方法调用 TransactionAttributeSourcePointcut#matches 方法判断是否匹配。如果获取到了TranscationalAttribute对象,则匹配成功。该方法实现如下:

    8:matches方法调用getTransactionAttributeSource 方法获取到的是这个类的对象:AnnotationTransactionAttributeSource。然后调用 getTransactionAttribute 方法获取注解 @Transcational。该方法的核心是调用 computeTransactionAttribute 方法。

    9:computeTransactionAttribute 方法里,首先会判断方法是不是public,如果不是,则返回null。所有默认情况下,@Transcational注解在非public方法上不生效。代码如下:

        9.1:调用方法 determineTransactionAttribute 解析@Transcational 注解,代码如下:

        9.2:在parseTransactionAnnotation方法里会解析 @Transcational 的属性,比如propagation,isolation,timeout,rollbackFor等,并生成RuleBasedTransactionAttribute 类型的对象返回。

    10:和 @Transcational 匹配成功后,就要创建创建AOP代理对象,代码如下:

    11:AbstractAutoProxyCreator#createProxy 方法里,主要是创建proxyFactory对象。其proxyTargetClass 属性值为true,targetSource是当前bean对象。advisors列表里的值是:BeanFactoryTransactionAttributeSourceAdvisor 对象实例。默认情况下,createProxy 使用的是 JdkDynamicAopProxy 类型代理。如果@Transcational所在类没有继承接口,则返回的是ObjenesisCglibAopProxy类型代码。

    12:JdkDynamicAopProxy 是利用JDK的反正机制,使用 Proxy.newProxyInstance 创建代理类:代码如下:

    13:在 ObjenesisCglibAopProxy 的createProxy方法里,使用了CGLIB的Enhancer来创建代理对象。其中设置的callbacks 是 DynamicAdvisedInterceptor,其继承了接口:MethodInterceptor。代码如下:

    14:以JdkDynamicAopProxy为例子看下有注解@Transcational的方法被调用时发生了什么。当方法被调用的时候,首先进入的是 JdkDynamicAopProxy#invoke 方法。在该invoke方法里,比较核心的是调用 AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice 方法 ,而里面调用了DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice。所以调用关系是:JdkDynamicAopProxy#invoke --->  AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice   --->  DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice。

    15:DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice 方法实际上得到的是 TransactionInterceptor 对象列表(只有)一个实例。

    16:得到 TransactionInterceptor 对象后,生成ReflectiveMethodInvocation对象,并调用其process方法。如下:

    17:在process 方法里,会调用TransactionInterceptor 的invoke方法。在invoke方法里,调用 invokeWithinTransaction 方法。该方法就会进行事务的操作。说明,该方法里会获取PlatformTransactionManager 接口的实例,各个数据库连接框架均会有实现,比如:JPA,JDBC,MyBatis等都有实现,比如:JtaTransactionManager。在使用事务的时候,这个事务管理器必须配置。
```
protected ObjectinvokeWithinTransaction(Method method, Class targetClass, final InvocationCallback invocation) throws Throwable {

    // If the transaction attribute is null, the method is non-transactional.
        // 获取注解@Trasactional的配置属性,是RuleBasedTransactionAttribute类型
       final TransactionAttribute txAttr =             getTransactionAttributeSource().getTransactionAttribute(method, targetClass);

       // 获取配置的TransactionManager。如果在@Trasactional注解中指定了名称,则
        // 从IOC中获取指定的TransactionManager。不同的数据库持久层框架,其实现的
        // TransactionManager不同,所以这个需要配置正确。
       final PlatformTransactionManager tm = determineTransactionManager(txAttr);
       final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
       if (txAttr ==null || !(tminstanceof CallbackPreferringPlatformTransactionManager)) {

              // Standard transaction demarcation with getTransaction and commit/rollback calls.
               // 创建并获取事务。
              TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
              Object retVal =null;

              try {
                // This is an around advice: Invoke the next interceptor in the chain.
                // This will normally result in a target object being invoked
                 retVal = invocation.proceedWithInvocation();
                 }
                catch (Throwable ex) {
                    // target invocation exception
                    // 提交或者回滚事务。这里会判断异常类型,如果类型和@Transactional配置的一致,则回滚,否则事务会提交
                    completeTransactionAfterThrowing(txInfo, ex);
                     throw ex;
                  }
                  finally {
                        cleanupTransactionInfo(txInfo);
                  }
                // 提交事务
                commitTransactionAfterReturning(txInfo);
              return retVal;
           }
    }
```

    18:方法createTransactionIfNecessary里会调用AbstractPlatformTransactionManager#getTransaction 方法获取事务(AbstractPlatformTransactionManager抽象类供各数据库持久层继承)。其主要逻辑是获取该类的数据库连接Connection, 拿到连接后,设置连接的autoCommit 属性为 false。事务内代码执行后,调用 Connection 的 commit 方法。 如果有满足条件的异常,执行rollback方法。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,175评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,674评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,151评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,597评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,505评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,969评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,455评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,118评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,227评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,213评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,214评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,928评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,512评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,616评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,848评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,228评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,772评论 2 339