Spring事務管理(四)-@Transactional和聲明式事務

在前幾篇中,介紹了Spring事務中核心的原理,如事務AOP代理TransactionProxyFactoryBean及事務管理器PlatformmTransactionManager,而最終以@Transactional註解這種非侵入式甚至近乎無感知的方式運行在咱們的大大小小的項目中,只須要在配置文件中加上簡單的配置,所以也就稱爲聲明式事務:事務與業務解耦。java

在spring配置文件中加上事務註解驅動,以及事務管理器spring

<!-- 事務註解驅動 -->
<tx:annotation-driven transaction-manager="transactionManager"/>

<!-- 事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

此時,在須要事務的方法上加上@Transactional便可(前提是類被spring容器管理)。要分析其運行的原理,得從事務註解驅動的配置開始。根據Spring解析xml Namespace的規則,直接查找TxNamespaceHandler,對annotation-driven的解析由AnnotationDrivenBeanDefinitionParser執行。緩存

public BeanDefinition parse(Element element, ParserContext parserContext) {
    registerTransactionalEventListenerFactory(parserContext);
    String mode = element.getAttribute("mode");
    if ("aspectj".equals(mode)) {
        // mode="aspectj"
        registerTransactionAspect(element, parserContext);
    }
    else {
        // mode="proxy"
        AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
    }
    return null;
}

默認狀況下,不用配置mode,即由其內部靜態類AopAutoProxyConfigurer完成配置ide

public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
	// 配置AOP自動代理
    AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
	// 事務切面名稱爲org.springframework.transaction.config.internalTransactionAdvisor
    String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
    if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
        Object eleSource = parserContext.extractSource(element);

        // Create the TransactionAttributeSource definition.
        // 定義事務屬性源爲AnnotationTransactionAttributeSource
        RootBeanDefinition sourceDef = new RootBeanDefinition(
                "org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
        sourceDef.setSource(eleSource);
        sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

        // Create the TransactionInterceptor definition.
        // 定義事務攔截器
        RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
        interceptorDef.setSource(eleSource);
        interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        registerTransactionManager(element, interceptorDef);
        interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
        String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

        // Create the TransactionAttributeSourceAdvisor definition.
        // 定義事務切面爲BeanFactoryTransactionAttributeSourceAdvisor
        RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
        advisorDef.setSource(eleSource);
        advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
        advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
        if (element.hasAttribute("order")) {
            advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
        }
        parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);

        CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
        compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
        compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
        compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
        parserContext.registerComponent(compositeDef);
    }
}

主要配置的有三部分:ui

  1. 事務屬性源TransactionAttributeSource
  2. 事務攔截器TransactionInterceptor
  3. 事務切面TransactionAttributeSourceAdvisor

事務屬性源

這裏配置的事務屬性源是AnnotationTransactionAttributeSource,支持根據類和方法獲取事務屬性。this

@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Method method) {
    return determineTransactionAttribute(method);
}

@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
    return determineTransactionAttribute(clazz);
}

統一調用determineTransactionAttribute方法spa

protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
	// 註解解析器解析事務註解
    for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
        TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae);
        if (attr != null) {
            return attr;
        }
    }
    return null;
}

在AnnotationTransactionAttributeSource的構造方法中,初始化了註解解析器.net

public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
    this.publicMethodsOnly = publicMethodsOnly;
    this.annotationParsers = new LinkedHashSet<>(2);
    // 支持Spring的@Transactional
    this.annotationParsers.add(new SpringTransactionAnnotationParser());
    // 支持javax.transaction.Transactional
    if (jta12Present) {
        this.annotationParsers.add(new JtaTransactionAnnotationParser());
    }
    // 支持javax.ejb.TransactionAttribute
    if (ejb3Present) {
        this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
    }
}

SpringTransactionAnnotationParser中判斷類和方法上是否有@Transactional,而後解析註解的屬性scala

public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
	// 判斷類和方法上的@Transactional
    AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
            ae, Transactional.class, false, false);
    if (attributes != null) {
    	// 解析@Transactional
        return parseTransactionAnnotation(attributes);
    }
    else {
        return null;
    }
}

建立事務屬性對象RuleBasedTransactionAttribute,獲取事務屬性配置debug

protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
    RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
    Propagation propagation = attributes.getEnum("propagation");
    rbta.setPropagationBehavior(propagation.value());
    Isolation isolation = attributes.getEnum("isolation");
    rbta.setIsolationLevel(isolation.value());
    rbta.setTimeout(attributes.getNumber("timeout").intValue());
    rbta.setReadOnly(attributes.getBoolean("readOnly"));
    // value指定哪一個事務管理器
    rbta.setQualifier(attributes.getString("value"));
    ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<>();
    Class<?>[] rbf = attributes.getClassArray("rollbackFor");
    for (Class<?> rbRule : rbf) {
        RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
        rollBackRules.add(rule);
    }
    String[] rbfc = attributes.getStringArray("rollbackForClassName");
    for (String rbRule : rbfc) {
        RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
        rollBackRules.add(rule);
    }
    Class<?>[] nrbf = attributes.getClassArray("noRollbackFor");
    for (Class<?> rbRule : nrbf) {
        NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
        rollBackRules.add(rule);
    }
    String[] nrbfc = attributes.getStringArray("noRollbackForClassName");
    for (String rbRule : nrbfc) {
        NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
        rollBackRules.add(rule);
    }
    rbta.getRollbackRules().addAll(rollBackRules);
    return rbta;
}

@Transactional的value值定義的是由哪一個事務管理器管理,若是沒有配置rollbackFor和noRollbackFor屬性,由RuleBasedTransactionAttribute的父類DefaultTransactionAttribute默認定義異常回滾規則:遇到運行時異常和Error回滾事務。

public boolean rollbackOn(Throwable ex) {
    return (ex instanceof RuntimeException || ex instanceof Error);
}

至此,事務屬性的解析很清晰了,那麼又是在何處調用事務屬性源的findTransactionAttribute方法?

事務切面

BeanFactoryTransactionAttributeSourceAdvisor繼承自AbstractBeanFactoryPointcutAdvisor,重要的是定義了切點爲TransactionAttributeSourcePointcut。

public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

    @Nullable
    private TransactionAttributeSource transactionAttributeSource;

    private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
        @Override
        @Nullable
        protected TransactionAttributeSource getTransactionAttributeSource() {
            return transactionAttributeSource;
        }
    };
}

切點須要的事務屬性源即上面建立的AnnotationTransactionAttributeSource。匹配是否事務管理由TransactionAttributeSourcePointcut中的matches方法決定。

@Override
public boolean matches(Method method, @Nullable Class<?> targetClass) {
    if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
        return false;
    }
    TransactionAttributeSource tas = getTransactionAttributeSource();
    // 判斷是否事務管理
    return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}

getTransactionAttribute方法執行的是AnnotationTransactionAttributeSource父類AbstractFallbackTransactionAttributeSource中的方法

public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    if (method.getDeclaringClass() == Object.class) {
        return null;
    }

    // First, see if we have a cached value.
    Object cacheKey = getCacheKey(method, targetClass);
    Object cached = this.attributeCache.get(cacheKey);
    if (cached != null) {
        // Value will either be canonical value indicating there is no transaction attribute,
        // or an actual transaction attribute.
        if (cached == NULL_TRANSACTION_ATTRIBUTE) {
            return null;
        }
        else {
            return (TransactionAttribute) cached;
        }
    }
    else {
        // We need to work it out.
        // 沒有緩存,根據方法和Class對象計算事務屬性
        TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
        // Put it in the cache.
        if (txAttr == null) {
            this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
        }
        else {
            String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
            if (txAttr instanceof DefaultTransactionAttribute) {
                ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
            }
            this.attributeCache.put(cacheKey, txAttr);
        }
        return txAttr;
    }
}

這裏增長了一層緩存,第一次調用時執行computeTransactionAttribute方法

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

    // Ignore CGLIB subclasses - introspect the actual user class.
    // 忽略CGLIB生成的對象,找到實際用戶使用的Class
    Class<?> userClass = (targetClass != null ? ClassUtils.getUserClass(targetClass) : 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 = ClassUtils.getMostSpecificMethod(method, userClass);
    // If we are dealing with method with generic parameters, find the original method.
    // 若是方法上存在泛型,轉換獲取真正的方法
    specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);

    // First try is the method in the target class.
    // 從方法上獲取事務對象
    TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
    if (txAttr != null) {
        return txAttr;
    }

    // Second try is the transaction attribute on the target class.
    // 方法不存在的話,從類上獲取事務對象
    txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
    if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
        return txAttr;
    }

    if (specificMethod != method) {
        // Fallback is to look at the original method.
        txAttr = findTransactionAttribute(method);
        if (txAttr != null) {
            return txAttr;
        }
        // Last fallback is the class of the original method.
        txAttr = findTransactionAttribute(method.getDeclaringClass());
        if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
            return txAttr;
        }
    }

    return null;
}

@Transactional的優先級是:方法註解 > 類註解,這裏的findTransactionAttribute執行的類就是AnnotationTransactionAttributeSource。

切面類配置完成後,須要綁定到Bean的生命週期中,這樣在Bean建立時執行AOP代理,所以咱們須要自動代理配置(關於自動代理,請見Spring源碼-AOP(六)-自動代理與DefaultAdvisorAutoProxyCreator)。

基礎自動代理

tx:annotation-driven解析的開始,就註冊了AOP的自動代理。

AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);

由AopConfigUtils統一配置

public static void registerAutoProxyCreatorIfNecessary(
        ParserContext parserContext, Element sourceElement) {

	// 註冊自動代理BeanDefinition
    BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(
            parserContext.getRegistry(), parserContext.extractSource(sourceElement));
    // aop屬性配置
    useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
    registerComponentIfNecessary(beanDefinition, parserContext);
}

自動代理BeanDefinition配置爲InfrastructureAdvisorAutoProxyCreator,只對Advisor的role爲ROLE_INFRASTRUCTURE代理

public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
        @Nullable Object source) {

    return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}

InfrastructureAdvisorAutoProxyCreator繼承AbstractAdvisorAutoProxyCreator,重寫isEligibleAdvisorBean方法,判斷適合的Advisor。

protected boolean isEligibleAdvisorBean(String beanName) {
    return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&
            this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
}

自動代理的核心基類AbstractAutoProxyCreator實現了SmartInstantiationAwareBeanPostProcessor接口,在Bean初始化完成後,查找全部Advisor,並過濾切點包含本身的Advisor,詳細時間見Spring源碼-AOP(六)-自動代理與DefaultAdvisorAutoProxyCreator)。

對於事務攔截器TransactionInterceptor的實現過程已經在Spring事務管理(二)-TransactionProxyFactoryBean原理說明了,這裏就不贅述了。

相關文章
相關標籤/搜索