Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >TransactionalEventListener使用场景与原理分析

TransactionalEventListener使用场景与原理分析

作者头像
叔牙
修改于 2021-12-07 15:14:16
修改于 2021-12-07 15:14:16
5.7K00
代码可运行
举报
运行总次数:0
代码可运行

一、背景

开发中有这样一个场景,客服业务需要接入在线能力,基于其他团队的IM底层能力构建业务层能力,也就是需要先调二方restful服务创建群聊,然后调用本地服务创建会话,并且创建会话依赖于二方服务返回的群聊信息,那么就会出现本地服务异常回滚,但是二方服务已经调用成功的情况,如果不做处理那么下次再尝试创建群聊,用户id已经存在,创建不成功,考虑到异构服务(二方服务可能是java、C++或者其他)或者异构数据(mysql、TiDB等), 分布式事务并不是一个很好的选择,这个时候我们就可以考虑在产生异常时候手动回滚二方服务的方式。

二、案例分析

今天我们要描述的是使用TransactionalEventListener来做业务补偿,TransactionalEventListener本质上是一个EventListener,依赖于Spring事件体系的支撑,我们要做的就是优先调用二方服务并返回结果,如果二方服务异常,流程终止不执行本地业务,如果二方服务正常,执行本地业务,如果本地执行成功,整个流程执行成功,如果本地执行异常,本地数据回滚,然后发出异常事件,由TransactionalEventListener执行二方数据的手动回滚或者订正。大致流程如下:

业务代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Transactional
public void createSession() {
    //1.创建群
    String groupId = restful api.createGroup
    //2.发布补偿事件
    this.applicationEventPublisher.publishEvent();
    //3.创建会话
    this.createSession(groupId);   
}

首先调用二方服务,然后发送补偿事件,最后调用本地服务,2和3的顺序不能颠倒,否则会导致异常终止事件发送不出去。

TransactionalEventListener事件补偿:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Slf4j
@Component
public class CreateSessionFailedListener {

    @TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
    public void onRollbackEvent(CreateSessionFailedEvent event) {
        try {
            restful api补偿
        } catch (Exception e) {
            log.error("onRollbackEvent occur error;event={}",event,e);
        }
    }
}

使用TransactionalEventListener注解写事务监听器,并且监听的时机是异常回滚,也就是本地事务出现异常回滚后触发该事件监听。

这样就能实现二方服务执行成功后,本地事务回滚,然后补偿订正二方服务数据了。当然也可以在事务的上层调用方捕获并识别异常,然后根据需要决定是否需要补偿。

三、源码&原理解析

1.监听器初始化

@TransactionalEventListener注解肯定和事务相关,那么我们就从springboot开启事务注解的地方开始分析,先看EnableTransactionManagement:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
    ...
}

TransactionalEventListener导入了选择器TransactionManagementConfigurationSelector:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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;
    }
  }
}

默认是Proxy代理,会引入AutoProxyRegistrar和ProxyTransactionManagementConfiguration,前者我们在spring cache原理解析中已经分析过,直接看ProxyTransactionManagementConfiguration:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

  @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
  @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
    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() {
    TransactionInterceptor interceptor = new TransactionInterceptor();
    interceptor.setTransactionAttributeSource(transactionAttributeSource());
    if (this.txManager != null) {
      interceptor.setTransactionManager(this.txManager);
    }
    return interceptor;
  }

}

ProxyTransactionManagementConfiguration定义了几个基础设施类,来实现事务逻辑织入,在之前的篇幅中已经不止一次分析过,此处不在赘述,我们看一下期继承关系:

ProxyTransactionManagementConfiguration继承了AbstractTransactionManagementConfiguration

类,该类定义了一个bean:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
  return new TransactionalEventListenerFactory();
}

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class TransactionalEventListenerFactory implements EventListenerFactory, Ordered {

  @Override
  public boolean supportsMethod(Method method) {
    return AnnotatedElementUtils.hasAnnotation(method, TransactionalEventListener.class);
  }
  @Override
  public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
    return new ApplicationListenerMethodTransactionalAdapter(beanName, type, method);
  }
}

该方法根据用户使用@TransactionalEventListener注解的方法创建时间监听器代理,在应用启动的时候EventListenerMethodProcessor中调用,其原理在另外一片文章《事件驱动编程》中也分析过,然后我们看一下创建的监听器代理的实现ApplicationListenerMethodTransactionalAdapter:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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()) {
      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);
      }
    }
  }
}

监听器逻辑调用会调用onApplicationEvent方法,这一段逻辑比较巧妙,首先检查当前上下文是否在事务中,如果是则把监听器逻辑注册到事务同步器中,等待后续事务执行过程指定节点触发,如果没有在事务中则立即触发事件监听逻辑。

事件工厂初始化:

事务事件监听器初始化:

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

在spring体系中我们可以直接注入事件发布器来发布事件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Autowired
protected ApplicationEventPublisher applicationEventPublisher;

看一下ApplicationEventPublisher定义:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@FunctionalInterface
public interface ApplicationEventPublisher {
  /**
   * Notify all <strong>matching</strong> listeners registered with this
   * application of an application event. Events may be framework events
   * (such as RequestHandledEvent) or application-specific events.
   * @param event the event to publish
   * @see org.springframework.web.context.support.RequestHandledEvent
   */
  default void publishEvent(ApplicationEvent event) {
    publishEvent((Object) event);
  }
  /**
   * Notify all <strong>matching</strong> listeners registered with this
   * application of an event.
   * <p>If the specified {@code event} is not an {@link ApplicationEvent},
   * it is wrapped in a {@link PayloadApplicationEvent}.
   * @param event the event to publish
   * @since 4.2
   * @see PayloadApplicationEvent
   */
  void publishEvent(Object event);
}

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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来发布事件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
  ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
  for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
    Executor executor = getTaskExecutor();
    if (executor != null) {
      executor.execute(() -> invokeListener(listener, event));
    }
    else {
      invokeListener(listener, event);
    }
  }
}

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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);
  }
}

继续看doInvokeListener:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
  try {
    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.isDebugEnabled()) {
        logger.debug("Non-matching event type for listener: " + listener, ex);
      }
    }
    else {
      throw ex;
    }
  }
}

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

然后我们回顾一下事务事件监听器适配器实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public void onApplicationEvent(ApplicationEvent event) {
  if (TransactionSynchronizationManager.isSynchronizationActive()) {
    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);
    }
  }
}

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

我们暂且理解为当前逻辑在事务中,先创建事务同步逻辑:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public TransactionSynchronizationEventAdapter(ApplicationListenerMethodAdapter listener,
    ApplicationEvent event, TransactionPhase phase) {

  this.listener = listener;
  this.event = event;
  this.phase = phase;
}

包含了事件监听器,事件类型和事务事件触发阶段。然后调用事件同步管理器把事件同步逻辑注册到事务中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static void registerSynchronization(TransactionSynchronization synchronization)
    throws IllegalStateException {

  Assert.notNull(synchronization, "TransactionSynchronization must not be null");
  if (!isSynchronizationActive()) {
    throw new IllegalStateException("Transaction synchronization is not active");
  }
  synchronizations.get().add(synchronization);
}

我们把事务事件监听器执行的此阶段叫做注册阶段,用时序图更清晰的分析一下其逻辑:

那事件事务监听器逻辑注册到事务生命周期成功了,什么时候触发呢?那就要回到ProxyTransactionManagementConfiguration的TransactionInterceptor了,加事务注解的逻辑执行的时候会被TransactionInterceptor拦截到,然后执行invoke逻辑:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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());
  }
}

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
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");
  }
  DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
  if (defStatus.isLocalRollbackOnly()) {
    if (defStatus.isDebug()) {
      logger.debug("Transactional code has requested rollback");
    }
    processRollback(defStatus, false);
    return;
  }
  if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
    if (defStatus.isDebug()) {
      logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
    }
    processRollback(defStatus, true);
    return;
  }
  processCommit(defStatus);
}

如果事务已结束,异常终止,如果事务需要回滚则执行processRollback,否则执行processCommit提交,我们继续看processRollback回滚逻辑:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
  try {
    boolean unexpectedRollback = unexpected;
    try {
            //1.处理事务提交前事件监听逻辑
      triggerBeforeCompletion(status);
            //回滚逻辑
            ...      
    }
    catch (RuntimeException | Error ex) {
      triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
      throw ex;
    }
    //2触发事务提交后监听逻辑
    triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
    // Raise UnexpectedRollbackException if we had a global rollback-only marker
    if (unexpectedRollback) {
      throw new UnexpectedRollbackException(
          "Transaction rolled back because it has been marked as rollback-only");
    }
  }
  finally {
    cleanupAfterCompletion(status);
  }
}

看一下triggerAfterCompletion实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private void triggerAfterCompletion(DefaultTransactionStatus status, int completionStatus) {
  if (status.isNewSynchronization()) {
    List<TransactionSynchronization> synchronizations = TransactionSynchronizationManager.getSynchronizations();
    TransactionSynchronizationManager.clearSynchronization();
    if (!status.hasTransaction() || status.isNewTransaction()) {
      if (status.isDebug()) {
        logger.trace("Triggering afterCompletion synchronization");
      }
      // No transaction or new transaction for the current scope ->
      // invoke the afterCompletion callbacks immediately
      invokeAfterCompletion(synchronizations, completionStatus);
    }
    else if (!synchronizations.isEmpty()) {
      // Existing transaction that we participate in, controlled outside
      // of the scope of this Spring transaction manager -> try to register
      // an afterCompletion callback with the existing (JTA) transaction.
      registerAfterCompletionWithExistingTransaction(status.getTransaction(), synchronizations);
    }
  }
}

如果当前阶段没有事务或者新事务则执行后置回调逻辑invokeAfterCompletion:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected final void invokeAfterCompletion(List<TransactionSynchronization> synchronizations, int completionStatus) {
  TransactionSynchronizationUtils.invokeAfterCompletion(synchronizations, completionStatus);
}

然后调用TransactionSynchronizationUtils#invokeAfterCompletion方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public void afterCompletion(int status) {
  if (this.phase == TransactionPhase.AFTER_COMMIT && status == STATUS_COMMITTED) {
    processEvent();
  }
  else if (this.phase == TransactionPhase.AFTER_ROLLBACK && status == STATUS_ROLLED_BACK) {
    processEvent();
  }
  else if (this.phase == TransactionPhase.AFTER_COMPLETION) {
    processEvent();
  }
}

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected void processEvent() {
  this.listener.processEvent(this.event);
}

到这里就执行到我们自定义监听器的逻辑了,也用时序图来清晰的描述事务事件的触发时机和逻辑:

总结

我们本篇从使用和源码角度分别分析了TransactionalEventListener使用方式和实现原理,可以得出以下几个结论:

  • TransactionalEventListener本质上是EventListener,依托于spring事件体系支持
  • TransactionalEventListener从注册到触发依赖于事务管理器和事务的生命周期
  • TransactionalEventListener适用于在事务的生命周期中特定节点做一些前置逻辑和后置补偿

对于一个事务涉及到本地和二方服务调用的场景,并且本地业务的执行依赖二方服务的结果,在本地服务出现异常发生回滚的时候,可以使用事务事件监听来做逻辑解耦和数据补偿,并且这种方式更优雅和简单。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-08-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PersistentCoder 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Spring事务事件监控
本文首先会使用实例进行讲解Spring事务事件是如何使用的,然后会讲解这种使用方式的实现原理。
JavaQ
2019/05/30
8590
Spring事务监听机制---使用@TransactionalEventListener处理数据库事务提交成功后再执行操作(附:Spring4.2新特性讲解)【享学Spring】
从标题就可以看出,本篇文章内容既和Spring的事件/监听机制有关,同时还和Spring事务以及Spring事务同步机制有关。
YourBatman
2019/09/03
13.2K0
从注解@EventListener和@TransactionalEventListener掌握Spring的事件机制原理 - Java技术债务
Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式;为的就是业务系统逻辑的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现内容是什么,发布者的工作只是为了发布事件而已。
Java技术债务
2024/06/21
6600
从注解@EventListener和@TransactionalEventListener掌握Spring的事件机制原理 - Java技术债务
深入理解Spring事件机制(二):事件的推送[通俗易懂]
Spring 从 3.x 开始支持事件机制。在 Spring 的事件机制中,我们可以令一个事件类继承 ApplicationEvent 类,然后将实现了 ApplicationListener 的 Bean 注册到 spring 容器,最后向 ApplicationEventPublisher 推送事件对象即可令所有订阅者收到事件。在 4.2 以后,甚至不需要实现 ApplicationListener 接口,仅需在 Bean 中方法标记 @EventListener 注解即可。
全栈程序员站长
2022/09/23
1.8K0
聊聊spring的TransactionalEventListener
本文主要研究一下spring的TransactionalEventListener
code4it
2023/09/11
2750
Spring高手之路26——全方位掌握事务监听器
Spring事务监听器是一种机制,允许我们在事务的不同阶段(如提交、回滚、开始)执行自定义逻辑。通过事务监听器,我们可以在事务的生命周期中插入一些额外的操作,比如记录日志、发送通知、更新缓存等。
砖业洋__
2024/12/20
4121
Spring高手之路26——全方位掌握事务监听器
【Spring源码】Spring Event事件
事件发布/订阅机制在实际项目中很经常用到,一方面可以很容易让我们的代码进行解耦,另一方面可以很方便的进行一对一或一对多的消息通信,是一种常见的观察者设计模式,具有很好的扩展性。今天就来讲一下Spring的事件机制。
有一只柴犬
2024/01/25
4200
【Spring源码】Spring Event事件
聊聊spring的TransactionalEventListener
本文主要研究一下spring的TransactionalEventListener
code4it
2023/09/12
3600
聊聊spring的TransactionalEventListener
如何优雅地Spring事务编程
在开发中,有时候我们需要对 Spring 事务的生命周期进行监控,比如在事务提交、回滚或挂起时触发特定的逻辑处理。那么如何实现这种定制化操作呢?
BookSea
2024/04/30
1510
如何优雅地Spring事务编程
深入了解 Spring 中的事务(从核心注解和类入手)
此注解是 Spring 支持注解事务配置的标志。表明 Spring 开启注解事务配置的支持。是注解驱动开发事务配置的必备注解。
IT技术小咖
2020/11/16
1.3K0
聊聊如何在spring事务中正确进行远程调用
最近和朋友聊天,他说他承接的外包项目遇到了分布式事务问题,问我有没啥解决方案,我本可以直接跟他说,分布式事务方案网上一大堆,什么tcc、可靠消息一致性、最大努力通知之类的,直接网上找个试下,比如直接用阿里的seata。但我并没有这么做,因为分布式事务,本来就是一个很复杂的课题,真正落地的时候,会发现有时候是多种分布式方案一起混用,而非一种方案走到黑。
lyb-geek
2021/04/29
1K0
聊聊如何在spring事务中正确进行远程调用
聊聊TransactionSynchronization的invokeAfterCompletion
本文主要研究一下TransactionSynchronization的invokeAfterCompletion
code4it
2023/09/10
1650
Spring事务专题(五)聊聊Spring事务到底是如何实现的
在上篇文章中我们一起学习了Spring中的事务抽象机制以及动手模拟了一下Spring中的事务管理机制,那么本文我们就通过源码来分析一下Spring中的事务管理到底是如何实现的,本文将选用Spring5.2.x版本。
程序员DMZ
2020/08/18
1.4K0
Spring事务专题(五)聊聊Spring事务到底是如何实现的
DDD落地之事件驱动模型
周末的时候写了一文带你落地DDD,发现大家对于新的领域与知识都挺感兴趣的。后面将会出几篇DDD系列文章给大家介绍mvc迁移DDD实际要做的一些步骤。
柏炎
2022/08/23
1.1K0
DDD落地之事件驱动模型
Spring学习笔记(10)一spring容器事件ApplicationEvent使用
定义两种事件目的是为下面要说明@EventListener 注解和@TransactionalEventListener 注解的区别。
黄规速
2022/04/14
1.4K0
Spring框架 SpringEvent
Spring的事件(Application Event)其实就是一个观察者设计模式,一个 Bean 处理完成任务后希望通知其它 Bean 或者说 一个Bean 想观察监听另一个Bean的行为。
郭顺发
2023/07/07
2450
Spring事件
事件是框架中被忽视的功能之一,但也是非常有用的功能之一,并且像Spring中的许多其他能力一样,事件发布是ApplicationContext上下文提供的功能之一。
叔牙
2020/11/19
7970
Spring事件
springboot监听器
小知识:Spring boot项目启动时会扫描项目中的监听器并加载到广播器中,所以广播器广播的时候能获取到所有的监听器。 Spring boot识别项目中的监听器规则是:@EventListener注解标注的方法,ApplicationListener接口的实现类。
用户4235284
2022/12/03
9740
数据库事务提交后才发送MQ消息解决方案
在项目开发中常常会遇到在一个有数据库操作的方法中,发送MQ消息,如果这种情况消息队列效率比较快,就会出现数据库事务还没提交,消息队列已经执行业务,导致不一致问题。举个应用场景,我们提交一个订单,将流水号放在MQ里,MQ监听到后就会查询订单去做其它业务,如果这时候数据库事务还没提交,也就是没生成订单流水,MQ监听到消息就去执行业务,查询订单,肯定会出现业务不一致问题
SmileNicky
2023/11/03
1.2K0
数据库事务提交后才发送MQ消息解决方案
Spring源码解析(十二):TransactionInterceptor事务拦截器
prepareConnectionForTransaction 设置隔离级别和只读属性:
冬天vs不冷
2025/01/21
2170
Spring源码解析(十二):TransactionInterceptor事务拦截器
推荐阅读
相关推荐
Spring事务事件监控
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档