使用實例
監聽器:
@Component
public class TransactionListener {
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handler(TransactionEvent transactionEvent) {
System.out.println(transactionEvent.getSource());
}
}
帶有事務的業務代碼:
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
public void saveUser() {
User user = new User();
userMapper.insert(user);
eventPublisher.publishEvent(newTransactionEvent("事務提交后發布事件1"));
}
源碼:
TransactionalEventListenerFactory:
作用:
這個類用來創建ApplicationListenerMethodTransactionalAdapter對象
如何被注冊到spring容器中
@Bean的方式
AbstractTransactionManagementConfiguration這個類被@Configuration修飾
下面有個@Bean的方法,創建出TransactionalEventListenerFactory實例
EventListenerMethodProcessor
在AnnotationConfigUtils.registerAnnotationConfigProcessors()方法中會把這個類弄成BeanDefinition,注冊到BDRegistry中
這個類實現EventListenerMethodProcessor接口的postProcessBeanFactory方法,和BeanFactoryPostProcessor接口的afterSingletonsInstantiated(),其他Bean實例化過程中會調用到這兩個方法
創建監聽器
在所有bean實例化之后,實現SmartInitializingSingleton接口的Bean,會被調用到實現該接口的
afterSingletonsInstantiated方法。
DefaultListableBeanFactory.preInstantiateSingletons()
這里EventListenerMethodProcessor調用afterSingletonsInstantiated方法
從BeanFactoryBean取出所有的BeanName,循環調用processBean方法
processBean方法
從bean的Class對象中找出含有@EventListener注解的方法,存到Map<Method, EventListener>中,
@TransactionListenr方法也會被匹配,因為這個注解里打了@EventListener
如果從Bean的Class對象中,找到了含有@EventListener注解的方法,循環每一個方法,循環調用EventListenerFactory的子類進行,判斷是否支持該方法的上的注解
//策略模式,如果支持解析該方法的注解,則調用該factory的createApplicationListener方法創建監聽器
-
TransactionalEventListenerFactory 用來對@TransactionalEventListener修飾的方法創建監聽器
image DefaultListenerFactory 用來對@EventListener,@TransactionalEventListener修飾的方法創建監聽器
創建ApplicationListenerMethodTransactionalAdapter對象
其構造方法將beanName,Class,method對象,賦值到自己的屬性中,并把注冊抽出來了而已
創建完監聽器對象后,將其加入到Spring的事務管理器中
ApplicationListenerMethodTransactionalAdapter類
實現了ApplicationListener接口,說明它是一個監聽器,前面已經加入到事件管理器中,那么根據實現的onApplicationEvent方法的參數類型,決定響應不同類型的事件
那么,我們編寫的帶有@TransactionalEventListener注解的方法會在發布事件之后,就會被調用么?
發布事件
注入ApplicationEventPublisher對象
這就是一個上下文ApplicationContext對象,ApplicationContext實現了ApplicationEventPublisher接口
@Autowired
private ApplicationEventPublisher eventPublisher;
發布事件:
根據時間類型,拿出事件管理器里的監聽器,執行onApplicationEvent方法
這個到ApplicationListenerMethodTransactionalAdapter來執行onApplicationEvent方法
創建一個了TransactionSynchronization對象,放到了事務管理器中
TransactionSynchronization
- 里面持有:event對象
- 由被@TransactionalEventListener修飾的方法封裝而成的監聽器適配器
- @TransactionalEventListener的value值(TransactionPhase.AFTER_COMMIT)
發布事件的話,后面就沒了,那么事件的觸發在哪里呢?在事務的切面里。
事務提交后,觸發事件
事務切面
提交事務后,會調這個方法
取出存放在TransactionSynchronizationManager事務管理器中的TransactionSynchronization,剛才發布事件的時候,往里面存了的哦
分別調用TransactionSynchronization對象的afterCompletion方法
最后從容器中取出我們編寫的TransactionListener類型的bean,反射調用它的被@TransactionalEventListener修飾的方法
總結
一般的監聽器
- 實現ApplicationListener接口,實現onApplicationEvent方法,
- 用@Componnet修飾,ioc容器啟動的時候加入到事件管理器中,獲取手動調用上下文對象的addApplicationListener方法加入
- 發布事件,隨即觸發事件
@TransactionalEventListener修飾的監聽器
- 每一個被該注解修飾的方法都會創建一個監聽器(持有method對象和當前類的Class),并加入到事件管理器中
- 發布事件時,調用上一步創建的監聽器的監聽方法,將該監聽器和必要的信息封裝成對象,放到事務管理器
- 由事務切面在提交事務之后,從事務管理器里取出上一步存儲的對象,反射調用我們自己的監聽方法。
需注意點:
- 事務監聽方法所在的類一定要注冊到spring容器中,如果沒被實例化,則不會判斷方法中是否存在@TransactionalEventListener注解,不會創建監聽器適配器。
- 發布事件一定要在被事務管理的代碼中。如果在事務范圍之外發布事件,事務切面已經結束,則不會去調用監聽器適配器中反射調用我們監聽方法的方法。