Управление транзакциями Spring для приложений Spring AOP

Java Spring

Версия фреймворка Spring 5.3.x

1. Связь между основными объектами

//tu

Как видно на рисунке выше, аннотации@EnableTransactionManagementОтвечает за открытие управления транзакциями, а затемTransactionManagementConfigurationSelectorВнедрите следующие два класса:

  • AutoProxyRegistrar

    Отвечает за создание прокси-классов

  • ProxyTransactionManagementConfiguration

    Логика, отвечающая за создание управления транзакциями (Spring AOP)

    • BeanFactoryTransactionAttributeSourceAdvisor

      Советник в Spring AOP

    • TransactionAttributeSource

      Pointcut в Spring AOP

    • TransactionInterceptor

      совет в Spring AOP

Таким образом, можно увидеть, что управление транзакциями на самом деле является прикладной реализацией Spring AOP.

2. Аннотировать процесс выполнения транзакции

Блок-схема операции управления транзакциями Spring:

3. Анализ исходного кода

Исходный код анализируется по трем компонентам АОП управления транзакциями следующим образом:

  • TransactionAttributeSource (Poincut)
  • TransactionInterceptor(Advice)
  • BeanFactoryTransactionAttributeSourceAdvisor(Advisor)

3.1 Анализ исходного кода TransactionAttributeSource

public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
		implements Serializable {
    
    private final boolean publicMethodsOnly;
    
	//省略代码
    public AnnotationTransactionAttributeSource() {
		this(true);
	}
    
    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());
		}
	}
}

ПроверятьProxyTransactionManagementConfigurationСоздайтеAnnotationTransactionAttributeSourceиспользуется конструктор без аргументов.

Советы: здесь вызывается конструктор AnnotationTransactionAttributeSource(boolean publicMethodsOnly). Вот что управление транзакциями может обрабатывать только общедоступные методы

Самый важный класс этоSpringTransactionAnnotationParserКлассы анализа аннотаций, два других предназначены для поддержки других спецификаций Java. Основная функция состоит в том, чтобы определить, содержит ли текущий выполняемый метод или класс@javax.transaction.Transactional,@javax.ejb.TransactionAttribute, @org.springframework.transaction.annotation.Transactionalаннотация.

Кто-то спросил, если я увидел это здесь.TransactionAttributeSourceэквивалентноPointcutНет необходимости видеть, как это реализованоPointcutинтерфейс. Не волнуйтесь, давайте посмотримProxyTransactionManagementConfigurationКласс имеет этот фрагмент кода:

	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
			TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {

		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource);
		advisor.setAdvice(transactionInterceptor);
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}

будетTransactionAttributeSourceПараметры класса реализацииBeanFactoryTransactionAttributeSourceAdvisorатрибут . (На самом деле это экземпляр AnnotationTransactionAttributeSource). Посмотрите нижеBeanFactoryTransactionAttributeSourceAdvisorКласс имеет этот фрагмент кода:

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

Это становитсяPointcut. Не наследование интерфейса напрямуюPointcutВместо этого он становится Poincut косвенно через приведенный выше код. посмотри**TransactionAttributeSourcePointcut** код

abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
	//省略代码
}

через упаковкуAnnotationTransactionAttributeSourceСтать Pointcut

3.2 Анализ исходного кода TransactionInterceptor

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
    //省略代码
}

Из приведенного выше видно, что интерфейс реализованMethodInterceptor, то основная логикаMethodInterceptor#invokeметод. TransactionInterceptor реализует интерфейс вызова:

@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
	//获取到目标类
	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();
		}
	});
}

Найдите целевой класс вызова, затем вызовитеTransactionAspectSupportКатегорияinvokeWithinTransactionметод.这个方法也是主要的处理逻辑:

в соответствии сTransactionAttributeSourceрешить использоватьReactiveTransactionManagerвсе ещеPlatformTransactionManager(Здесь анализируется только PlatformTransactionManager).

TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

В соответствии с методами PlatformTransactionManager, TransactionAttributeSource и pointcut для создания управления транзакциями, давайте взглянем на метод TransactionAspectSupport#createTransactionIfNecessary, который содержит фрагмент кода:

	protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
		//省略部分代码
		TransactionStatus status = null;
		if (txAttr != null) {
			if (tm != null) {
                //这段代码
				status = tm.getTransaction(txAttr);
			}
			else {
				
			}
		}
		return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
	}

менеджер по сделкам согласноTransactionAttributeSourceПолучает статус транзакцииTransactionStatus.

status = tm.getTransaction(txAttr)Этот код показывает, что согласно аннотации@TransactionalКак создать транзакцию среди свойств, лучше всего обернуть ее какTransactionStatus. Давайте проанализируем этот фрагмент кода,AbstractPlatformTransactionManagerреализованный методgetTransaction.

	@Override
	public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException {

		// 没有事务定义给出就使用默认的
		TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());

        //获取事务
		Object transaction = doGetTransaction();
		boolean debugEnabled = logger.isDebugEnabled();
		
        //判断事务是否存在
		if (isExistingTransaction(transaction)) {
			// Existing transaction found -> check propagation behavior to find out how to behave.
			return handleExistingTransaction(def, transaction, debugEnabled);
		}

		// 检查新的事务配置
		if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
		}

		// No existing transaction found -> check propagation behavior to find out how to proceed.
		if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
			}
			try {
				return startTransaction(def, transaction, debugEnabled, suspendedResources);
			}
			catch (RuntimeException | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		else {
			// Create "empty" transaction: no actual transaction, but potentially synchronization.
			if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
				logger.warn("Custom isolation level specified but no actual transaction initiated; " +
						"isolation level will effectively be ignored: " + def);
			}
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
		}
	}

Приведенная выше транзакция должна рассматриваться в соответствии с распространением набора транзакций. Распространение транзакции заключается в следующем:

  • @Transaction (Propagation = PropAgation.required): если есть транзакция, добавить транзакцию, нет, создать новую (по умолчанию)

  • @Transactional(propagation=Propagation.NOT_SUPPORTED): выполнить нетранзакционным способом, приостановить текущую транзакцию, если она есть.

  • @Transactional(propagation=Propagation.REQUIRES_NEW): независимо от того, есть ли транзакция, создается новая транзакция, исходная приостанавливается, выполняется новая, а старая продолжает выполняться.

  • @Transactional(propagation=Propagation.MANDATORY): должен выполняться в существующей транзакции, иначе будет выдано исключение

  • @Transactional(propagation=Propagation.NEVER) : выполняется нетранзакционным образом, вызывая исключение, если есть транзакция.

  • @Transactional(propagation=Propagation.SUPPORTS): если другие компоненты вызывают этот метод и объявляют транзакции в других компонентах, используйте транзакции.Если другие компоненты не объявляют транзакции, не используйте транзакции.

  • @Transactional(propagation=Propagation.NESTED) : выполняется во вложенной транзакции, если транзакция уже существует. Если текущей транзакции нет, сделайте что-нибудь вроде PROPAGATION_REQUIRED.

СозданныйTransactionInfoЗатем начните выполнять метод бизнес-логики, если выполнение бизнес-логики сообщает об ошибке, выполните:

completeTransactionAfterThrowing(txInfo, ex);

Затем в блоке finally выполните:

cleanupTransactionInfo(txInfo);

Очистите информацию о транзакции и зафиксируйте транзакцию. На этом вся транзакция в основном завершена.

3.3 Анализ исходного кода BeanFactoryTransactionAttributeSourceAdvisor

public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

	@Nullable
	private TransactionAttributeSource transactionAttributeSource;

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


	/**
	 * Set the transaction attribute source which is used to find transaction
	 * attributes. This should usually be identical to the source reference
	 * set on the transaction interceptor itself.
	 * @see TransactionInterceptor#setTransactionAttributeSource
	 */
	public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
		this.transactionAttributeSource = transactionAttributeSource;
	}

	/**
	 * Set the {@link ClassFilter} to use for this pointcut.
	 * Default is {@link ClassFilter#TRUE}.
	 */
	public void setClassFilter(ClassFilter classFilter) {
		this.pointcut.setClassFilter(classFilter);
	}

	@Override
	public Pointcut getPointcut() {
		return this.pointcut;
	}

}

Этот класс относительно просто собрать Advice и Pointcut в Advisor.

4. Резюме

Нижний уровень управления транзакциями Spring реализован по принципу АОП. Объединение транзакций базы данных.

Если статья полезна для вас, вы можете поставить лайк и подписаться на меня.Ваши лайки и внимание являются движущей силой для меня двигаться вперед.Если статья неверна, пожалуйста, оставьте комментарий~ Спасибо!