Версия фреймворка Spring 5.3.x
1. Связь между основными объектами
Как видно на рисунке выше, аннотации@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 реализован по принципу АОП. Объединение транзакций базы данных.
Если статья полезна для вас, вы можете поставить лайк и подписаться на меня.Ваши лайки и внимание являются движущей силой для меня двигаться вперед.Если статья неверна, пожалуйста, оставьте комментарий~ Спасибо!