天天看點

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對象,并注冊給目前事務;