天天看点

Spring Transaction#TransactionalEventListener 原理

spring context 模块里的ApplicationEventPublisher、EventListener等实现了一个同步的发布订阅框架;当然这个框架是跟spring的其他模块深度耦合的。

@TransactionalEventListener本质上是一个@EventListener,Spring Tx针对使用Transaction时进行了特别的处理;处理过程可见ApplicationListenerMethodTransactionalAdapter;

TransactionalEventListenerFactory类会对将每一个扫描到的注解有TransactionalEventListener包装成ApplicationListenerMethodTransactionalAdapter对象;

通过ApplicationListenerMethodTransactionalAdapter的onApplicationEvent方法可以看到

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

当使用ApplicationEventPublisher public一个对象的时候,此监听器就会监听到,并将发布的对象、将注解有TransactionalEventListener包装成的ApplicationListenerMethodTransactionalAdapter和TransactionalEventListener注解上指定的TransactionPhase一同组装成TransactionSynchronizationEventAdapter对象,这个对象是一个TransactionSynchronization的实现,随后将此TransactionSynchronization对象通过TransactionSynchronizationManager注册;TransactionSynchronizationEventAdapter注册到当前事务之后,就可以在事务执行过程通过回调TransactionSynchronizationEventAdapter对应的方法,间接调用到将注解有TransactionalEventListener包装成的ApplicationListenerMethodTransactionalAdapter的逻辑了;

关于TransactionSynchronizationManager和TransactionSynchronization不太明白的,可以搜索一下其作用,可以先这么理解,TransactionSynchronization是一个接口,其里面定义了一个事务执行过程中重要时间点的回调方法,TransactionSynchronizationManager通过ThreadLocal管理注册到事务的多个TransactionSynchronization;

典型的使用过程如下:

public class User {
  private long id;
  private String name;
  private int age;

  // getter and setter...
}
@Service
@Transactional
public class UserServiceImpl implements UserService {
  @Autowired
  private JdbcTemplate jdbcTemplate;

  @Autowired
  private ApplicationEventPublisher publisher;

  @Override
  public void insert(User user) {
    jdbcTemplate.update("insert into user (id, name, age) value (?, ?, ?)", 
        user.getId(), user.getName(), user.getAge());
    publisher.publishEvent(user);
  }
}      

insert方法事务拦截器拦截,执行完方法之后,也就发布了一个事件,由于spring的事件发布订阅是同步的,也就是说,执行完publisher.publishEvent(user),发布事件之后,在一个线程中,接着回调订阅的逻辑;在此处,这个回调的逻辑也就是ApplicationListenerMethodTransactionalAdapter的onApplicationEvent方法,上面已经解析完这个方法的内容,此方法最重要的逻辑是构建一个TransactionSynchronization对象,并注册给当前事务;