關於spring事務原始碼的一些小理解
1、spring事務的簡單概述
由於實現事務功能的方式各不相同,Spring進行了統一的抽象,形成了PlatformTransactionManager事務管理器頂級介面(平臺事務管理器),事務的提交、回滾等操作全部交給它來實現
先來看下三大介面
-
PlatformTransactionManager
: 事務管理器 -
TransactionDefinition
: 事務的一些基礎資訊,如超時時間、隔離級別、傳播屬性等 -
TransactionStatus
: 事務的一些狀態資訊,如是否是一個新的事務、是否已被標記為回滾
2、 PlatformTransactionManager
相關類方法:
public interface PlatformTransactionManager { //獲取事務狀態 TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException; //事務提交 void commit(TransactionStatus status) throws TransactionException; //事務回滾 void rollback(TransactionStatus status) throws TransactionException; }複製程式碼
繼承關係:
PlatformTransactionManager AbstractPlatformTransactionManager DataSourceTransactionManager(重點) HibernateTransactionManager JpaTransactionManager複製程式碼
觸發不同的事物管理器
springboot對PlatformTransactionManager的預設配置實現(引用 spring-boot-starter-web中jdbc相關jar )
public class DataSourceTransactionManagerAutoConfiguration { @Configuration @ConditionalOnSingleCandidate(DataSource.class) static class DataSourceTransactionManagerConfiguration { private final DataSource dataSource; private final TransactionManagerCustomizers transactionManagerCustomizers; DataSourceTransactionManagerConfiguration(DataSource dataSource, ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) { this.dataSource = dataSource; this.transactionManagerCustomizers = transactionManagerCustomizers .getIfAvailable(); } @Bean @ConditionalOnMissingBean(PlatformTransactionManager.class) public DataSourceTransactionManager transactionManager( DataSourceProperties properties) { DataSourceTransactionManager transactionManager = new DataSourceTransactionManager( this.dataSource); if (this.transactionManagerCustomizers != null) { this.transactionManagerCustomizers.customize(transactionManager); } return transactionManager; } } }複製程式碼
通過@ConditionalOnMissingBean(PlatformTransactionManager.class)這個註解可以直到如果沒有手動配置
PlatformTransactionManager即使用預設的子類DataSourceTransactionManager來管理實務
3、事務傳播特性和隔離級別
public interface TransactionDefinition { 事務傳播特性: 1、支援事務,如果當前執行緒沒有事務,新建一個事務 int PROPAGATION_REQUIRED = 0; 2、支援事務,如果當前執行緒沒有事務,則以非事務執行 int PROPAGATION_SUPPORTS = 1; 3、 當前如果有事務,Spring就會使用該事務;否則會丟擲異常 int PROPAGATION_MANDATORY = 2; 4、如果當前執行緒存在事務,或者不存在事務,都會新建一個事務,並且新建事務與當前事務是相互隔離的,如果新建事務執行時,會先將當前事務掛起,等新建事務執行完成後,再將放行當前事務,如果新事物出現異常,會正常回滾,但不會影響當前事務 int PROPAGATION_REQUIRES_NEW = 3; 5、 不支援事務,如果存在事務,則會將當前事務掛起,以非事務執行 int PROPAGATION_NOT_SUPPORTED = 4; 6、不支援事務,如果當前執行緒存在事務,將會拋異常 int PROPAGATION_NEVER = 5; 7、如果當前執行緒存在事務,則新建一個回滾點,如果出現異常,則會回滾到上一個回滾點,對於當前事務是不受任何影響的。 int PROPAGATION_NESTED = 6; //隔離級別:預設的隔離級別(對mysql資料庫來說就是ISOLATION_ READ_COMMITTED,可以重複讀) 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(); @Nullable String getName(); } 複製程式碼
4、為什麼說spring事務是aop的一種實現
finishBeanFactoryInitialization(beanFactory);一路向後debug最後可以看到下面的程式碼 複製程式碼
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. //這裡就是獲取需要代理的類(如果存在advice)複製程式碼
//獲取bean對應的advice集合。 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); //將獲取到的advice集合儲存到代理物件中並返回。 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; }複製程式碼
這裡是建立代理的方法 protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { evaluateProxyInterfaces(beanClass, proxyFactory); } } //將advice封裝到 advisors中 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); //這裡的targetSource就是目標物件,在後面呼叫的時候會用到 proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } return proxyFactory.getProxy(getProxyClassLoader()); } specificInterceptors是攔截器(如果是aop則是前置後置這些過濾器,如果是事務,則是事務攔截器) BeanFactoryCacheOperationSourceAdvisor(儲存了增強的資訊)切面記錄是前置,後置等增強攔截器鏈而事務相關記錄的是事務攔截器private final Map<Object, TransactionAttribute> attributeCache = new ConcurrentHashMap<>(1024);儲存方法對應的事務資訊private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);儲存這個bean是否為增強beanif (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}判斷這個bean是否為代理類,如果不是直接返回單例和多例的區別: protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}將獲取到的bean儲存到singletonObjects中private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);在每次呼叫的時候,直接從singletonObjects這個ConcurrentHashMap中獲取即可。如果是Prototype在從走一遍單例的流程else if (mbd.isPrototype()) {// It's a prototype -> create a new instance.Object prototypeInstance = null;try {beforePrototypeCreation(beanName);prototypeInstance = createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}複製程式碼
5、事務方法呼叫
和aop呼叫一樣,最後會呼叫TransactionInterceptor的invock方法
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, invocation::proceed); }複製程式碼
然後會呼叫父類TransactionAspectSupport 的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 PlatformTransactionManager tm = determineTransactionManager(txAttr); final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); if (txAttr == null || !(tm instanceof 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 completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); } commitTransactionAfterReturning(txInfo); return retVal; } else { final ThrowableHolder throwableHolder = new ThrowableHolder(); // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in. try { Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> { TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status); try { return invocation.proceedWithInvocation(); } 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); } }); // Check result state: It might indicate a Throwable to rethrow. if (throwableHolder.throwable != null) { throw throwableHolder.throwable; } return result; } 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; } } }複製程式碼