spring Transaction之不求甚解

在:http://www.reibang.com/p/c8412579fe1a
不那么詳細(xì)的分析了spring aop整個(gè)運(yùn)轉(zhuǎn)的流程逸贾,本篇文章再來稍微深入下,看看spring是如何通過aop實(shí)現(xiàn)Transaction的功能的还栓。

在AbstractAutoProxyCreator中瓷胧,會找到合適的Advisor從而對bean做增強(qiáng):

//AbstractAutoProxyCreator

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
            return bean;
        }
        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        }
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }

        // Create proxy if we have advice.
        // 查找到屬于該bean的advisor
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            Object proxy = createProxy(
                    bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }

        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }


//AbstractAdvisorAutoProxyCreator
    protected Object[] getAdvicesAndAdvisorsForBean(
            Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
        // 獲取合適的Advosor
        List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
        if (advisors.isEmpty()) {
            return DO_NOT_PROXY;
        }
        return advisors.toArray();
    }

    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
        // 獲取所有advisors
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
        // 獲取適用于該類的Advisor
        List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
            eligibleAdvisors = sortAdvisors(eligibleAdvisors);
        }
        return eligibleAdvisors;
    }

    protected List<Advisor> findCandidateAdvisors() {
        Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
        return this.advisorRetrievalHelper.findAdvisorBeans();
    }


//BeanFactoryAdvisorRetrievalHelper
    public List<Advisor> findAdvisorBeans() {
        // Determine list of advisor bean names, if not cached already.
        String[] advisorNames = this.cachedAdvisorBeanNames;
        if (advisorNames == null) {
            // Do not initialize FactoryBeans here: We need to leave all regular beans
            // uninitialized to let the auto-proxy creator apply to them!
            // 這個(gè)都很熟悉了吧  直接從bean容器中獲取所有Advisor的實(shí)例
            advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                    this.beanFactory, Advisor.class, true, false);
            this.cachedAdvisorBeanNames = advisorNames;
        }
        if (advisorNames.length == 0) {
            return new ArrayList<>();
        }

        List<Advisor> advisors = new ArrayList<>();
        for (String name : advisorNames) {
            if (isEligibleBean(name)) {
                if (this.beanFactory.isCurrentlyInCreation(name)) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Skipping currently created advisor '" + name + "'");
                    }
                }
                else {
                    try {
                        // 通過advisor的名稱獲取到對應(yīng)的bean實(shí)例
                        advisors.add(this.beanFactory.getBean(name, Advisor.class));
                    }
                    catch (BeanCreationException ex) {
                        Throwable rootCause = ex.getMostSpecificCause();
                        if (rootCause instanceof BeanCurrentlyInCreationException) {
                            BeanCreationException bce = (BeanCreationException) rootCause;
                            String bceBeanName = bce.getBeanName();
                            if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
                                if (logger.isTraceEnabled()) {
                                    logger.trace("Skipping advisor '" + name +
                                            "' with dependency on currently created bean: " + ex.getMessage());
                                }
                                // Ignore: indicates a reference back to the bean we're trying to advise.
                                // We want to find advisors other than the currently created bean itself.
                                continue;
                            }
                        }
                        throw ex;
                    }
                }
            }
        }
        return advisors;
    }

大體上獲取Advisor就是這么個(gè)邏輯吃型,先找出所有對應(yīng)Advisor的類的beanName,再通過beanFactory.getBean方法獲取這些bean并返回。

上面我們知道了在實(shí)現(xiàn)AOP的時(shí)候會找到所有的Advisor酗钞,而Transaction的一個(gè)主要的類BeanFactoryTransactionAttributeSourceAdvisor其實(shí)就是一個(gè)Advisor:


image.png

所以 在findCandidateAdvisors方法中,就會找到Transaction的核心類BeanFactoryTransactionAttributeSourceAdvisor谢鹊,從而實(shí)現(xiàn)Transaction邏輯算吩。
而判斷是否需要Transaction邏輯其實(shí)是在findAdvisorsThatCanApply中實(shí)現(xiàn)的,大體的模式就是看bean的方法或者類上是否含有@Transaction佃扼,如果有則代表需要Transaction增強(qiáng)偎巢,關(guān)于findAdvisorsThatCanApply的代碼,這里暫時(shí)按下不表兼耀,主要的邏輯在AbstractFallbackTransactionAttributeSource中的computeTransactionAttribute()方法中压昼,關(guān)于整個(gè)調(diào)用鏈路可以自行跟蹤下:

    protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
        // Don't allow no-public methods as required.
        if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
            return null;
        }

        // The method may be on an interface, but we need attributes from the target class.
        // If the target class is null, the method will be unchanged.
        Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

        // First try is the method in the target class.
        // 方法中是否存在事務(wù)聲明
        TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
        if (txAttr != null) {
            return txAttr;
        }

        // Second try is the transaction attribute on the target class.
        // 查看方法所在類中是否存在事務(wù)聲明
        txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
        if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
            return txAttr;
        }

        if (specificMethod != method) {
            // Fallback is to look at the original method.
            // 接口方法中是否存在事務(wù)聲明
            txAttr = findTransactionAttribute(method);
            if (txAttr != null) {
                return txAttr;
            }
            // Last fallback is the class of the original method.
            // 接口類中是否存在事務(wù)聲明
            txAttr = findTransactionAttribute(method.getDeclaringClass());
            if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
                return txAttr;
            }
        }

        return null;
    }

Transaction如何通過AOP實(shí)現(xiàn)的

通過JDK動態(tài)代理做的增強(qiáng)求冷,在調(diào)用類方法的時(shí)候,都會通過InvocationHandler的invoke方法來執(zhí)行窍霞,而JdkDynamicAopProxy這個(gè)東西自己就是個(gè)InvocationHandler.匠题,在執(zhí)行代理類的目標(biāo)方法時(shí),會調(diào)用Advisor的getAdvice獲取MethodInterceptor并執(zhí)行其invoke方法但金,也就是在這個(gè)位置:

// ReflectiveMethodInvocation
    public Object proceed() throws Throwable {
        // We start with an index of -1 and increment early.
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }

        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            // Evaluate dynamic method matcher here: static part will already have
            // been evaluated and found to match.
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
            if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
                return dm.interceptor.invoke(this);
            }
            else {
                // Dynamic matching failed.
                // Skip this interceptor and invoke the next in the chain.
                return proceed();
            }
        }
        else {
            // It's an interceptor, so we just invoke it: The pointcut will have
            // been evaluated statically before this object was constructed.
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

也就是在最后一個(gè)else中的return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);去執(zhí)行的韭山,不難看出這里通過責(zé)任鏈模式去執(zhí)行所有MethodInterceptor的invoke方法。
說了這么多冷溃,這些跟Transaction有什么關(guān)系呢钱磅?
在之前提到的BeanFactoryTransactionAttributeSourceAdvisor中,它的getAdvice方法會返回TransactionInterceptor:


image.png

不難看出似枕,它是個(gè)MethodInterceptor盖淡,所以TransactionInterceptor的invoke方法,就是實(shí)現(xiàn)事務(wù)的重要邏輯了凿歼。

TransactionInterceptor

    public Object invoke(MethodInvocation invocation) throws Throwable {
        // Work out the target class: may be {@code null}.
        // The TransactionAttributeSource should be passed the target class
        // as well as the method, which may be from an interface.
        Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

        // Adapt to TransactionAspectSupport's invokeWithinTransaction...
        return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
            @Override
            @Nullable
            public Object proceedWithInvocation() throws Throwable {
                return invocation.proceed();
            }
            @Override
            public Object getTarget() {
                return invocation.getThis();
            }
            @Override
            public Object[] getArguments() {
                return invocation.getArguments();
            }
        });
    }

來聚焦下invokeWithinTransaction方法:

    protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
                                             final InvocationCallback invocation) throws Throwable {

        // If the transaction attribute is null, the method is non-transactional.
        TransactionAttributeSource tas = getTransactionAttributeSource();
        final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
        final TransactionManager tm = determineTransactionManager(txAttr);

        // ...

        if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
            // Standard transaction demarcation with getTransaction and commit/rollback calls.
            // 如果需要的話 開啟一個(gè)事務(wù)
            TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

            Object retVal;
            try {
                // This is an around advice: Invoke the next interceptor in the chain.
                // This will normally result in a target object being invoked.
                // 執(zhí)行目標(biāo)方法
                retVal = invocation.proceedWithInvocation();
            }
            catch (Throwable ex) {
                // target invocation exception
                // 異常處理
                completeTransactionAfterThrowing(txInfo, ex);
                throw ex;
            }
            finally {
                // 清空事務(wù)信息
                cleanupTransactionInfo(txInfo);
            }

            if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
                // Set rollback-only in case of Vavr failure matching our rollback rules...
                TransactionStatus status = txInfo.getTransactionStatus();
                if (status != null && txAttr != null) {
                    retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
                }
            }
            // 提交事務(wù)
            commitTransactionAfterReturning(txInfo);
            return retVal;
        }

        else {
            Object result;
            final ThrowableHolder throwableHolder = new ThrowableHolder();

            // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
            try {
                result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
                    TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
                    try {
                        Object retVal = invocation.proceedWithInvocation();
                        if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
                            // Set rollback-only in case of Vavr failure matching our rollback rules...
                            retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
                        }
                        return retVal;
                    }
                    catch (Throwable ex) {
                        if (txAttr.rollbackOn(ex)) {
                            // A RuntimeException: will lead to a rollback.
                            if (ex instanceof RuntimeException) {
                                throw (RuntimeException) ex;
                            }
                            else {
                                throw new ThrowableHolderException(ex);
                            }
                        }
                        else {
                            // A normal return value: will lead to a commit.
                            throwableHolder.throwable = ex;
                            return null;
                        }
                    }
                    finally {
                        cleanupTransactionInfo(txInfo);
                    }
                });
            }
            catch (ThrowableHolderException ex) {
                throw ex.getCause();
            }
            catch (TransactionSystemException ex2) {
                if (throwableHolder.throwable != null) {
                    logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                    ex2.initApplicationException(throwableHolder.throwable);
                }
                throw ex2;
            }
            catch (Throwable ex2) {
                if (throwableHolder.throwable != null) {
                    logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                }
                throw ex2;
            }

            // Check result state: It might indicate a Throwable to rethrow.
            if (throwableHolder.throwable != null) {
                throw throwableHolder.throwable;
            }
            return result;
        }
    }

方法很長褪迟,不過主要的邏輯還是比較清晰,可以看出其中比較關(guān)鍵的幾個(gè)點(diǎn):

  • createTransactionIfNecessary (需要的話)開啟事務(wù)
  • invocation.proceedWithInvocation(); 執(zhí)行目標(biāo)方法
  • completeTransactionAfterThrowing(txInfo, ex); 異常處理
  • cleanupTransactionInfo(txInfo); 清空事務(wù)信息
  • commitTransactionAfterReturning(txInfo); 提交事務(wù)
    這些點(diǎn)放在以后分析答憔。

connection

在createTransactionIfNecessary 中會有這么一段邏輯:

 status = tm.getTransaction(txAttr);

這里往下其實(shí)會走到DataSourceTransactionManager的doGetTransaction方法:

    protected Object doGetTransaction() {
        DataSourceTransactionManager.DataSourceTransactionObject txObject = new DataSourceTransactionManager.DataSourceTransactionObject();
        txObject.setSavepointAllowed(this.isNestedTransactionAllowed());
        ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.obtainDataSource());
        txObject.setConnectionHolder(conHolder, false);
        return txObject;
    }

在ConnectionHolder 中味赃,保存了一個(gè)Connection連接,而ConnectionHolder是通過(ConnectionHolder)TransactionSynchronizationManager.getResource(this.obtainDataSource());獲取的:

    protected Object doGetTransaction() {
        DataSourceTransactionManager.DataSourceTransactionObject txObject = new DataSourceTransactionManager.DataSourceTransactionObject();
        txObject.setSavepointAllowed(this.isNestedTransactionAllowed());
        ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.obtainDataSource());
        txObject.setConnectionHolder(conHolder, false);
        return txObject;
    }

    public static Object getResource(Object key) {
        Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
        return doGetResource(actualKey);
    }

    private static Object doGetResource(Object actualKey) {
        Map<Object, Object> map = resources.get();
        if (map == null) {
            return null;
        }
        Object value = map.get(actualKey);
        // Transparently remove ResourceHolder that was marked as void...
        if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
            map.remove(actualKey);
            // Remove entire ThreadLocal if empty...
            if (map.isEmpty()) {
                resources.remove();
            }
            value = null;
        }
        return value;
    }

可以看出最終是從resources中獲取的攀唯,而resources其實(shí)就是一個(gè)ThreadLocal:

    private static final ThreadLocal<Map<Object, Object>> resources =
            new NamedThreadLocal<>("Transactional resources");

    private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
            new NamedThreadLocal<>("Transaction synchronizations");

    private static final ThreadLocal<String> currentTransactionName =
            new NamedThreadLocal<>("Current transaction name");

    private static final ThreadLocal<Boolean> currentTransactionReadOnly =
            new NamedThreadLocal<>("Current transaction read-only status");

    private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
            new NamedThreadLocal<>("Current transaction isolation level");

    private static final ThreadLocal<Boolean> actualTransactionActive =
            new NamedThreadLocal<>("Actual transaction active");

參考文章:
http://www.linkedkeeper.com/1045.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末洁桌,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子侯嘀,更是在濱河造成了極大的恐慌另凌,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件戒幔,死亡現(xiàn)場離奇詭異吠谢,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)诗茎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門工坊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人敢订,你說我怎么就攤上這事王污。” “怎么了楚午?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵昭齐,是天一觀的道長。 經(jīng)常有香客問我矾柜,道長阱驾,這世上最難降的妖魔是什么就谜? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮里覆,結(jié)果婚禮上丧荐,老公的妹妹穿的比我還像新娘。我一直安慰自己喧枷,他們只是感情好虹统,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著割去,像睡著了一般窟却。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上呻逆,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機(jī)與錄音菩帝,去河邊找鬼咖城。 笑死,一個(gè)胖子當(dāng)著我的面吹牛呼奢,可吹牛的內(nèi)容都是我干的宜雀。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼握础,長吁一口氣:“原來是場噩夢啊……” “哼辐董!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起禀综,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤简烘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后定枷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體孤澎,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年欠窒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了覆旭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,163評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡岖妄,死狀恐怖型将,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情荐虐,我是刑警寧澤七兜,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站缚俏,受9級特大地震影響惊搏,放射性物質(zhì)發(fā)生泄漏贮乳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一恬惯、第九天 我趴在偏房一處隱蔽的房頂上張望向拆。 院中可真熱鬧,春花似錦酪耳、人聲如沸浓恳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽颈将。三九已至,卻和暖如春言疗,著一層夾襖步出監(jiān)牢的瞬間晴圾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工噪奄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留死姚,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓勤篮,卻偏偏與公主長得像都毒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子碰缔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容