@TransactionalEventListener注解的原理

@TransactionalEventListener的使用

@Component
public class EsSaveTransactionalEventListener {
	@Resource
	private EsDocumentDao esDocumentDao;
    @Resource
    private PushMessageSender pushMessageSender;

	// 事务提交前触发的方法
    @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
    public void commitBefore(MyTransactionEvent myTransactionEvent) {
    	// 从Es的ThreadLocal里边取出之前放进去的数据
        List<DocWriteRequest<?>> docWriteRequests = EsBatchSaveUtils.getAndRemove();
        if (CollectionUtils.isNotEmpty(docWriteRequests)) {
            log.info("获取待存储数据,数量 :{}", docWriteRequests.size());
            // 事务提交前,批量存储数据,保证es和mysql数据的一致性
            documentDao.bulk(Lists.newArrayList(docWriteRequests));
        }
    }

	// 事务提交后
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void afterCommit(TransactionEvent transactionEvent) {
    	// 从消息的ThreadLocal中取出数据
        Map<PushMessageUniqueKey, BaseMessage> pushMessageParams = MessageNotifyUtils.getAndRemove();
        if (MapUtils.isNotEmpty(pushMessageParams)) {
            log.info("获取待通知消息,数量 :{}", pushMessageParams.size());
            // 事务提交之后,发送mq,进行数据的异步处理,保证数据的一致性
            pushMessageParams.forEach((key, message)-> pushMessageSender.send(key.getTopicType(), message));
        }
    }

	// 事务完成处理
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)
    public void afterCompletion(TransactionEvent transactionEvent) {
    	// 从redis的threadlocal里取出锁
        List<RedissionLock> redissonLocks = LockReleaseUtils.getAndRemoveRedissonLock();
        if (CollectionUtils.isNotEmpty(redissonLocks)) {
            log.info("获取待释放RedissonLock锁数,数量 :{}", redissonLocks.size());
            try {
            	// 释放需要释放的锁
                redisLockService.unLock(redissonLocks);
            } catch (Exception e) {
                log.error("释放RedissonLock锁失败", e);
            }
        }
    }
}

从上面的这个类可以看出,通过事务注解可以保证数据的一致性,也能保证在事务完成之后,锁能够释放.

1、监听器初始化
因为@TransactionalEventListener注解和事务相关,所以从Spring boot开启事务注解的地方开始分析,@EnableTransactionManagement:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
	//是否直接代理目标类
	boolean proxyTargetClass() default false;
	//通知模式,默认是代理
	AdviceMode mode() default AdviceMode.PROXY;
	//顺序
	int order() default Ordered.LOWEST_PRECEDENCE;
}

@EnableTransactionManagement导入了选择器TransactionManagementConfigurationSelector:

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

	
	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			// 默认
			case PROXY:
				return new String[] {AutoProxyRegistrar.class.getName(),
						ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {determineTransactionAspectClass()};
			default:
				return null;
		}
	}

	private String determineTransactionAspectClass() {
		return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
				TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
				TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
	}
}

这里主要对ProxyTransactionManagementConfiguration进行分析

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

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

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource);
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}
}

ProxyTransactionManagementConfiguration定义的这几个基础设施类,来实现事务逻辑织入的.
在这里插入图片描述
从上面的继承关系可以看到ProxyTransactionManagementConfiguration继承自AbstractTransactionManagementConfiguration类.
AbstractTransactionManagementConfiguration类定义了一个bean:


	@Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
		return new TransactionalEventListenerFactory();
	}

这个bean所在的类定义了创建事件监听器的方法:

	
	@Override
	public boolean supportsMethod(Method method) {
		// 指定目标方法是否是支持的监听器的类型,
		// 这里的判断逻辑就是如果目标方法上包含有TransactionalEventListener
		// 则说明是一个事务监听器
		return AnnotatedElementUtils.hasAnnotation(method, TransactionalEventListener.class);
	}

	@Override
	public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
		// 根据用户使用@TransactionalEventListener注解的方法创建事件监听器代理
		// 在应用启动的时候EventListenerMethodProcessor中调用
		return new ApplicationListenerMethodTransactionalAdapter(beanName, type, method);
	}

下面看一下ApplicationListenerMethodTransactionalAdapter的创建实现:

class ApplicationListenerMethodTransactionalAdapter extends ApplicationListenerMethodAdapter {

	private final TransactionalEventListener annotation;

	// 构造方法
	public ApplicationListenerMethodTransactionalAdapter(String beanName, Class<?> targetClass, Method method) {
		super(beanName, targetClass, method);
		TransactionalEventListener ann = AnnotatedElementUtils.findMergedAnnotation(method, TransactionalEventListener.class);
		if (ann == null) {
			throw new IllegalStateException("No TransactionalEventListener annotation found on method: " + method);
		}
		this.annotation = ann;
	}

	// 监听事务的处理方法
	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		// 检查当前上下文是否在事务中
		if (TransactionSynchronizationManager.isSynchronizationActive() &&
				TransactionSynchronizationManager.isActualTransactionActive()) {
			// 创建TransactionSynchronization
			TransactionSynchronization transactionSynchronization = createTransactionSynchronization(event);
			// 是则把监听器逻辑注册到事务同步器中,
			// 等待后续事务执行过程指定节点触发
			TransactionSynchronizationManager.registerSynchronization(transactionSynchronization);
		}
		else if (this.annotation.fallbackExecution()) {
			if (this.annotation.phase() == TransactionPhase.AFTER_ROLLBACK && logger.isWarnEnabled()) {
				logger.warn("Processing " + event + " as a fallback execution on AFTER_ROLLBACK phase");
			}
			// 如果没有在事务中,立即出发事件监听逻辑
			processEvent(event);
		}
		else {
			// No transactional event execution at all
			if (logger.isDebugEnabled()) {
				logger.debug("No transaction is active - skipping " + event);
			}
		}
	}
}

2.事务事件调用与监听器触发

@Autowired
protected ApplicationEventPublisher applicationEventPublisher;
@FunctionalInterface
public interface ApplicationEventPublisher {

	
	default void publishEvent(ApplicationEvent event) {
		publishEvent((Object) event);
	}


	void publishEvent(Object event);

}

调用ApplicationEventPublisher#publishEvent会调用AbstractApplicationContext#publishEvent:

	protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
		Assert.notNull(event, "Event must not be null");

		// Decorate event as an ApplicationEvent if necessary
		ApplicationEvent applicationEvent;
		if (event instanceof ApplicationEvent) {
			applicationEvent = (ApplicationEvent) event;
		}
		else {
			applicationEvent = new PayloadApplicationEvent<>(this, event);
			if (eventType == null) {
				eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
			}
		}

		// Multicast right now if possible - or lazily once the multicaster is initialized
		if (this.earlyApplicationEvents != null) {
			this.earlyApplicationEvents.add(applicationEvent);
		}
		else {
			getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
		}

		// Publish event via parent context as well...
		if (this.parent != null) {
			if (this.parent instanceof AbstractApplicationContext) {
				((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
			}
			else {
				this.parent.publishEvent(event);
			}
		}
	}

这里是一个递归调用,当前上下文先发布事件,然后递归找父上下文发布事件,最终会调用SimpleApplicationEventMulticaster#multicastEvent来发布事件:

	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		Executor executor = getTaskExecutor();
		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}

这里是从上下文中先获取监听器集合,然后如果有任务执行器就调用任务执行器执行监听器逻辑(多线程),否则当前线程调用监听器逻辑,然后看invokeListener实现:

	protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
		ErrorHandler errorHandler = getErrorHandler();
		if (errorHandler != null) {
			try {
				doInvokeListener(listener, event);
			}
			catch (Throwable err) {
				errorHandler.handleError(err);
			}
		}
		else {
			doInvokeListener(listener, event);
		}
	}

	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			// 调用监听器的onApplicationEvent方法
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
				// Possibly a lambda-defined listener which we could not resolve the generic event type for
				// -> let's suppress the exception and just log a debug message.
				Log logger = LogFactory.getLog(getClass());
				if (logger.isTraceEnabled()) {
					logger.trace("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				throw ex;
			}
		}
	}

到这里就比较清晰了,我们自定义事件监听器都实现了ApplicationListener接口,此处会调用监听器的onApplicationEvent方法执行自定义逻辑。
回顾下:

ApplicationListenerMethodTransactionalAdapter#onApplicationEvent
如果检测到当前上下文有活跃的事务,那么就把监听器逻辑注册到事务中,等到事务执行到指定的节点触发监听器逻辑,否则如果检测到TransactionalEventListener.fallbackExecution属性为true(如果没有事务,是否处理事件),则直接调用处理事件逻辑,否则返回调用。

我们直接看当前逻辑在事务中的逻辑:

	// 创建TransactionSynchronization
	private TransactionSynchronization createTransactionSynchronization(ApplicationEvent event) {
		return new TransactionSynchronizationEventAdapter(this, event, this.annotation.phase());
	}
	// 把事务监听器注册到事务生命周期中
	public static void registerSynchronization(TransactionSynchronization synchronization)
			throws IllegalStateException {

		Assert.notNull(synchronization, "TransactionSynchronization must not be null");
		Set<TransactionSynchronization> synchs = synchronizations.get();
		if (synchs == null) {
			throw new IllegalStateException("Transaction synchronization is not active");
		}
		synchs.add(synchronization);
	}

上面把监听器注册到了事务的生命周期中,那什么时候触发呢?
刚开始提到TransactionSynchronization的TransactionInterceptor这个类,这个类会对加事务注解的逻辑执行的时候进行拦截,然后执行invoke方法:

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

在invokeWithinTransaction逻辑中会调用commitTransactionAfterReturning方法:

	protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
		if (txInfo != null && txInfo.getTransactionStatus() != null) {
			if (logger.isTraceEnabled()) {
				logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
			}
			txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
		}
	}

然后会调用事务管理器执行事务状态的提交逻辑:

    public final void commit(TransactionStatus status) throws TransactionException {
        if (status.isCompleted()) {
            throw new IllegalTransactionStateException("Transaction is already completed - do not call commit or rollback more than once per transaction");
        } else {
            DefaultTransactionStatus defStatus = (DefaultTransactionStatus)status;
            if (defStatus.isLocalRollbackOnly()) {
                if (defStatus.isDebug()) {
                    this.logger.debug("Transactional code has requested rollback");
                }

                this.processRollback(defStatus, false);
            } else if (!this.shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
                if (defStatus.isDebug()) {
                    this.logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
                }

                this.processRollback(defStatus, true);
            } else {
                this.processCommit(defStatus);
            }
        }
    }

如果事务已结束,异常终止,如果事务需要回滚则执行processRollback,否则执行processCommit提交,
看一下回滚的代码:

private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
        try {
            boolean unexpectedRollback = unexpected;

            try {
            	//1.处理事务提交前事件监听逻辑
                this.triggerBeforeCompletion(status);
                //回滚逻辑
                if (status.hasSavepoint()) {
                    if (status.isDebug()) {
                        this.logger.debug("Rolling back transaction to savepoint");
                    }

                    status.rollbackToHeldSavepoint();
                } else if (status.isNewTransaction()) {
                    if (status.isDebug()) {
                        this.logger.debug("Initiating transaction rollback");
                    }

                    this.doRollback(status);
                } else {
                    if (status.hasTransaction()) {
                        if (!status.isLocalRollbackOnly() && !this.isGlobalRollbackOnParticipationFailure()) {
                            if (status.isDebug()) {
                                this.logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
                            }
                        } else {
                            if (status.isDebug()) {
                                this.logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
                            }

                            this.doSetRollbackOnly(status);
                        }
                    } else {
                        this.logger.debug("Should roll back transaction but cannot - no transaction available");
                    }

                    if (!this.isFailEarlyOnGlobalRollbackOnly()) {
                        unexpectedRollback = false;
                    }
                }
            } catch (Error | RuntimeException var8) {
                this.triggerAfterCompletion(status, 2);
                throw var8;
            }
			//2触发事务提交后监听逻辑
            this.triggerAfterCompletion(status, 1);
            if (unexpectedRollback) {
                throw new UnexpectedRollbackException("Transaction rolled back because it has been marked as rollback-only");
            }
        } finally {
            this.cleanupAfterCompletion(status);
        }

    }

看一下triggerAfterCompletion实现:

    protected final void triggerBeforeCompletion(DefaultTransactionStatus status) {
    	// 如果当前阶段没有事务或者新事务则执行后置回调逻辑invokeAfterCompletion:
        if (status.isNewSynchronization()) {
            if (status.isDebug()) {
                this.logger.trace("Triggering beforeCompletion synchronization");
            }

            TransactionSynchronizationUtils.triggerAfterCommit();
        }

    }

看一下triggerAfterCompletion实现:

	    private void triggerAfterCompletion(DefaultTransactionStatus status, int completionStatus) {
        if (status.isNewSynchronization()) {
            List<TransactionSynchronization> synchronizations = TransactionSynchronizationManager.getSynchronizations();
            TransactionSynchronizationManager.clearSynchronization();
            if (status.hasTransaction() && !status.isNewTransaction()) {
                if (!synchronizations.isEmpty()) {
                    this.registerAfterCompletionWithExistingTransaction(status.getTransaction(), synchronizations);
                }
            } else {
                if (status.isDebug()) {
                    this.logger.trace("Triggering afterCompletion synchronization");
                }
				// 如果当前阶段没有事务或者新事务则执行后置回调逻辑invokeAfterCompletion:
                this.invokeAfterCompletion(synchronizations, completionStatus);
            }
        }

    }

然后调用TransactionSynchronizationUtils#invokeAfterCompletion方法:

    protected final void invokeAfterCompletion(List<TransactionSynchronization> synchronizations, int completionStatus) {
        TransactionSynchronizationUtils.invokeAfterCompletion(synchronizations, completionStatus);
    }
    
	public static void invokeAfterCompletion(@Nullable List<TransactionSynchronization> synchronizations,
			int completionStatus) {

		if (synchronizations != null) {
			for (TransactionSynchronization synchronization : synchronizations) {
				try {
					synchronization.afterCompletion(completionStatus);
				}
				catch (Throwable tsex) {
					logger.error("TransactionSynchronization.afterCompletion threw exception", tsex);
				}
			}
		}
	}

获取到注册到当前事务的事件列表并执行,前边我们注册的是TransactionSynchronizationEventAdapter,直接看其afterCompletion实现:

        public void afterCompletion(int status) {
            if (this.phase == TransactionPhase.AFTER_COMMIT && status == 0) {
                this.processEvent();
            } else if (this.phase == TransactionPhase.AFTER_ROLLBACK && status == 1) {
                this.processEvent();
            } else if (this.phase == TransactionPhase.AFTER_COMPLETION) {
                this.processEvent();
            }

        }

从@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)可以看出我们注册事件监听的截断是TransactionPhase.AFTER_ROLLBACK,逻辑会进入第二个分支调用processEvent方法:

        protected void processEvent() {
            this.listener.processEvent(this.event);
        }

到这里就执行到我们自定义监听器的逻辑了.

	public void processEvent(ApplicationEvent event) {
		// 处理事务事件的相关参数,这里主要是判断TransactionalEventListener注解中是否配置了value或classes属性
		// 如果配置了,则将方法参数转换为该指定类型传给监听的方法;
		// 如果没有配置,则判断目标方法是ApplicationEvent类型还是PayloadApplicationEvent类型,是则转换为该类型传入
		Object[] args = resolveArguments(event);
		// 这里主要是获取TransactionalEventListener注解中的condition属性,
		// 然后通过 Spring expression language将其与目标类和方法进行匹配
		if (shouldHandle(event, args)) {
			// 通过处理得到的参数借助于反射调用事务监听方法
			Object result = doInvoke(args);
			if (result != null) {
				// 对方法的返回值进行处理
				handleResult(result);
			}
			else {
				logger.trace("No result object given - no result to handle");
			}
		}
	}

处理事务监听方法的参数

protected Object[] resolveArguments(ApplicationEvent event) {
	// 获取发布事务事件时传入的参数类型
	ResolvableType declaredEventType = getResolvableType(event);
	if (declaredEventType == null) {
    	return null;
	}
	// 如果事务监听方法的参数个数为0,则直接返回
	if (this.method.getParameterCount() == 0) {
	    return new Object[0];
	}
	// 如果事务监听方法的参数不为ApplicationEvent或PayloadApplicationEvent,则直接将发布事务
	// 事件时传入的参数当做事务监听方法的参数传入。从这里可以看出,如果事务监听方法的参数不是
	// ApplicationEvent或PayloadApplicationEvent类型,那么其参数必须只能有一个,并且这个
	// 参数必须与发布事务事件时传入的参数一致
	Class<?> eventClass = declaredEventType.getRawClass();
	if ((eventClass == null || !ApplicationEvent.class.isAssignableFrom(eventClass)) &&
    event instanceof PayloadApplicationEvent) {
	    return new Object[] {((PayloadApplicationEvent) event).getPayload()};
	} else {
	    // 如果参数类型为ApplicationEvent或PayloadApplicationEvent,则直接将其传入事务事件方法
	    return new Object[] {event};
	}
 }

判断事务事件方法方法是否需要进行事务事件处理

private boolean shouldHandle(ApplicationEvent event, @Nullable Object[] args) {
	if (args == null) {
	    return false;
	}
	String condition = getCondition();
	if (StringUtils.hasText(condition)) {
	    Assert.notNull(this.evaluator, "EventExpressionEvaluator must no be null");
	    EvaluationContext evaluationContext = this.evaluator.createEvaluationContext(
        event, this.targetClass, this.method, args, this.applicationContext);
	    return this.evaluator.condition(condition, this.methodKey, evaluationContext);
	}
	return true;
}

对事务事件方法的返回值进行处理,这里的处理方式主要是将其作为一个事件继续发布出去,这样就可以在
一个统一的位置对事务事件的返回值进行处理

protected void handleResult(Object result) {
	// 如果返回值是数组类型,则对数组元素一个一个进行发布
	if (result.getClass().isArray()) {
	    Object[] events = ObjectUtils.toObjectArray(result);
	    for (Object event : events) {
	        publishEvent(event);
	    }
	} else if (result instanceof Collection<?>) {
	    // 如果返回值是集合类型,则对集合进行遍历,并且发布集合中的每个元素
	    Collection<?> events = (Collection<?>) result;
	    for (Object event : events) {
	        publishEvent(event);
	    }
	} else {
	    // 如果返回值是一个对象,则直接将其进行发布
	    publishEvent(result);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值