spring ioc源碼,spring5源碼-事務

 2023-10-18 阅读 30 评论 0

摘要:Spring的事務機制包括聲明式事務和編程式事務。 編程式事務管理:Spring推薦使用TransactionTemplate,實際開發中使用聲明式事務較多。 聲明式事務管理:將我們從復雜的事務處理中解脫出來,獲取連接,關閉連接、事務提交、回滾、異常處理等這

Spring的事務機制包括聲明式事務和編程式事務。

編程式事務管理:Spring推薦使用TransactionTemplate,實際開發中使用聲明式事務較多。

聲明式事務管理:將我們從復雜的事務處理中解脫出來,獲取連接,關閉連接、事務提交、回滾、異常處理等這些操作都不用我們處理了,Spring都會幫我們處理。

聲明式事務管理使用了AOP面向切面編程實現的,本質就是在目標方法執行前后進行攔截。在目標方法執行前加入或創建一個事務,在執行方法執行后,根據實際情況選擇提交或是回滾事務。

如何管理的:

spring ioc源碼,Spring事務管理主要包括3個接口,Spring的事務主要是由他們三個共同完成的。

1)PlatformTransactionManager接口:事務管理器–主要用于平臺相關事務的管理

public interface PlatformTransactionManager {TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;void commit(TransactionStatus status) throws TransactionException;void rollback(TransactionStatus status) throws TransactionException;}

2)TransactionDefinition接口:事務定義信息–用來定義事務相關的屬性,給事務管理器PlatformTransactionManager使用

public interface TransactionDefinition {int PROPAGATION_REQUIRED = 0;int PROPAGATION_SUPPORTS = 1;int PROPAGATION_MANDATORY = 2;int PROPAGATION_REQUIRES_NEW = 3;int PROPAGATION_NOT_SUPPORTED = 4;int PROPAGATION_NEVER = 5;int PROPAGATION_NESTED = 6;/*** Use the default isolation level of the underlying datastore.* All other levels correspond to the JDBC isolation levels.* @see java.sql.Connection*/int ISOLATION_DEFAULT = -1;int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;int TIMEOUT_DEFAULT = -1;int getPropagationBehavior();int getIsolationLevel();int getTimeout();boolean isReadOnly();String getName();}

Connection接口

    /*** A constant indicating that transactions are not supported.*/int TRANSACTION_NONE             = 0;int TRANSACTION_READ_UNCOMMITTED = 1;int TRANSACTION_READ_COMMITTED   = 2;int TRANSACTION_REPEATABLE_READ  = 4;int TRANSACTION_SERIALIZABLE     = 8;

這個接口有下面四個主要方法:

getIsolationLevel:獲取隔離級別;

spring的事務管理、getPropagationBehavior:獲取傳播行為;

getTimeout:獲取超時時間;

isReadOnly:是否只讀(保存、更新、刪除時屬性變為false–可讀寫,查詢時為true–只讀)

事務管理器能夠根據這個返回值進行優化,這些事務的配置信息,都可以通過配置文件進行配置。

3)TransactionStatus接口:事務具體運行狀態–事務管理過程中,每個時間點事務的狀態信息。

public interface TransactionStatus extends SavepointManager, Flushable {boolean isNewTransaction();boolean hasSavepoint();void setRollbackOnly();boolean isRollbackOnly();void flush();boolean isCompleted();
}

例如它的幾個方法:

spring事務注解,hasSavepoint():返回這個事務內部是否包含一個保存點,

isCompleted():返回該事務是否已完成,也就是說,是否已經提交或回滾

isNewTransaction():判斷當前事務是否是一個新事務

聲明式事務的優缺點:

優點

不需要在業務邏輯代碼中編寫事務相關代碼,只需要在配置文件配置或使用注解(@Transaction),這種方式沒有侵入性。

Spring揭秘、缺點

聲明式事務的最細粒度作用于方法上,如果像代碼塊也有事務需求,只能變通下,將代碼塊變為方法。

注解事務

Spring 支持三個不同的事務注解 :

Spring 事務注解 org.springframework.transaction.annotation.Transactional
JTA事務注解 javax.transaction.Transactional
EJB 3 事務注解 javax.ejb.TransactionAttribute

當遇到以上三種注解的某一個時,Spring會使用AnnotationTransactionAttributeSource分析該事務注解,最終組織成一個TransactionAttribute供隨后使用。本文將基于源代碼解析該過程。
在這里插入圖片描述
TransactionAttributeSource接口,通過類和方法,獲取事務注解,封裝成TransactionAttribute

public interface TransactionAttributeSource {/*** Return the transaction attribute for the given method,* or {@code null} if the method is non-transactional.* @param method the method to introspect* @param targetClass the target class (may be {@code null},* in which case the declaring class of the method must be used)* @return TransactionAttribute the matching transaction attribute,* or {@code null} if none found*/@NullableTransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass);}

TransactionAttribute接口,繼承了事務定義,在事務隔離級別,傳播級別上,添加了異常回滾

public interface TransactionAttribute extends TransactionDefinition {/*** Return a qualifier value associated with this transaction attribute.* <p>This may be used for choosing a corresponding transaction manager* to process this specific transaction.*/@NullableString getQualifier();/*** Should we roll back on the given exception?* @param ex the exception to evaluate* @return whether to perform a rollback or not*/boolean rollbackOn(Throwable ex);}

Spring事務,AnnotationTransactionAttributeSource

public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSourceimplements Serializable {private static final boolean jta12Present = ClassUtils.isPresent("javax.transaction.Transactional", AnnotationTransactionAttributeSource.class.getClassLoader());private static final boolean ejb3Present = ClassUtils.isPresent("javax.ejb.TransactionAttribute", AnnotationTransactionAttributeSource.class.getClassLoader());private final boolean publicMethodsOnly;private final Set<TransactionAnnotationParser> annotationParsers;/*** Create a default AnnotationTransactionAttributeSource, supporting* public methods that carry the {@code Transactional} annotation* or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.*/public AnnotationTransactionAttributeSource() {this(true);}/*** Create a custom AnnotationTransactionAttributeSource, supporting* public methods that carry the {@code Transactional} annotation* or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.* @param publicMethodsOnly whether to support public methods that carry* the {@code Transactional} annotation only (typically for use* with proxy-based AOP), or protected/private methods as well* (typically used with AspectJ class weaving)*/public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {this.publicMethodsOnly = publicMethodsOnly;if (jta12Present || ejb3Present) {this.annotationParsers = new LinkedHashSet<>(4);this.annotationParsers.add(new SpringTransactionAnnotationParser());if (jta12Present) {this.annotationParsers.add(new JtaTransactionAnnotationParser());}if (ejb3Present) {this.annotationParsers.add(new Ejb3TransactionAnnotationParser());}}else {this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());}}/*** Create a custom AnnotationTransactionAttributeSource.* @param annotationParser the TransactionAnnotationParser to use*/public AnnotationTransactionAttributeSource(TransactionAnnotationParser annotationParser) {this.publicMethodsOnly = true;Assert.notNull(annotationParser, "TransactionAnnotationParser must not be null");this.annotationParsers = Collections.singleton(annotationParser);}/*** Create a custom AnnotationTransactionAttributeSource.* @param annotationParsers the TransactionAnnotationParsers to use*/public AnnotationTransactionAttributeSource(TransactionAnnotationParser... annotationParsers) {this.publicMethodsOnly = true;Assert.notEmpty(annotationParsers, "At least one TransactionAnnotationParser needs to be specified");this.annotationParsers = new LinkedHashSet<>(Arrays.asList(annotationParsers));}/*** Create a custom AnnotationTransactionAttributeSource.* @param annotationParsers the TransactionAnnotationParsers to use*/public AnnotationTransactionAttributeSource(Set<TransactionAnnotationParser> annotationParsers) {this.publicMethodsOnly = true;Assert.notEmpty(annotationParsers, "At least one TransactionAnnotationParser needs to be specified");this.annotationParsers = annotationParsers;}@Override@Nullableprotected TransactionAttribute findTransactionAttribute(Class<?> clazz) {return determineTransactionAttribute(clazz);}@Override@Nullableprotected TransactionAttribute findTransactionAttribute(Method method) {return determineTransactionAttribute(method);}/*** Determine the transaction attribute for the given method or class.* <p>This implementation delegates to configured* {@link TransactionAnnotationParser TransactionAnnotationParsers}* for parsing known annotations into Spring's metadata attribute class.* Returns {@code null} if it's not transactional.* <p>Can be overridden to support custom annotations that carry transaction metadata.* @param element the annotated method or class* @return the configured transaction attribute, or {@code null} if none was found*/@Nullableprotected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {for (TransactionAnnotationParser annotationParser : this.annotationParsers) {TransactionAttribute attr = annotationParser.parseTransactionAnnotation(element);if (attr != null) {return attr;}}return null;}/*** By default, only public methods can be made transactional.*/@Overrideprotected boolean allowPublicMethodsOnly() {return this.publicMethodsOnly;}@Overridepublic boolean equals(Object other) {if (this == other) {return true;}if (!(other instanceof AnnotationTransactionAttributeSource)) {return false;}AnnotationTransactionAttributeSource otherTas = (AnnotationTransactionAttributeSource) other;return (this.annotationParsers.equals(otherTas.annotationParsers) &&this.publicMethodsOnly == otherTas.publicMethodsOnly);}@Overridepublic int hashCode() {return this.annotationParsers.hashCode();}}

僅僅通過protected的方法實現類如何找到指定類/方法的事務注解屬性,但是自身并沒有提供public方法供調用者使用。實際上,類 AnnotationTransactionAttributeSource提供給調用者的服務方法是public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass),而該方法定義在其父類AbstractFallbackTransactionAttributeSource中

AbstractFallbackTransactionAttributeSource

	private final Map<Object, TransactionAttribute> attributeCache = new ConcurrentHashMap<>(1024);private static final TransactionAttribute NULL_TRANSACTION_ATTRIBUTE = new DefaultTransactionAttribute() {@Overridepublic String toString() {return "null";}};@Override@Nullablepublic 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);TransactionAttribute 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 cached;}}else {// We need to work it out.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;}}

事務屬性先從緩存查詢,沒有計算出來,放入緩存

DefaultTransactionAttribute結構圖
在這里插入圖片描述

AbstractFallbackTransactionAttributeSource計算事務屬性,只有public方法才使用事務

	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.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;}

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/148934.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息