Spring的事件發(fā)布與監(jiān)聽方式案例講解
事件
主要代碼在org.springframework.context,org.springframework.context.event包中
事件發(fā)布與監(jiān)聽主要包含以下角色:
- 事件:
ApplicationEvent - 事件監(jiān)聽器:
ApplicationListenerSmartApplicationListenerGenericApplicationListener - 事件發(fā)布器:
ApplicationEventPublisher - 事件廣播器:
ApplicationEventMulticaster
引入ApplicationListener有兩種方式:
- spring spi
- 手動注入bean
手動注入bean有兩種方式:
- 類上注解
@Component等注解+實現(xiàn)ApplicationListener接口 - 類上注解
@Component等注解+方法上注解@EventListener
案例如下:
// bean注入方式一,實現(xiàn)ApplicationListener+@Component注入bean
@Component
public class HelloEventListener implements SmartApplicationListener {
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return false;
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
}
}
// bean注入方式二,@EventListener+@Component
@Component
public class Test {
@EventListener
public void listen(Object obj){
System.out.println("listening");
}
@EventListener(classes={ApplicationEvent.class},condition="springEL")
public void listen(ApplicationEvent event){
System.out.println("listening");
}
}
關于@EventListener注解方法注入是通過EventListenerMethodProcessor的一個SmartInitializingSingleton,同時該類也是一個BeanFactoryPostProcessor,但掃描@EventListener方法和注入邏輯不在該接口的postProcess方法中,而是SmartInitializingSingleton接口的afterSingletonsInstantiated方法。
關于SmartInitializingSingleton的接口作用注釋如下:
Callback interface triggered at the end of the singleton pre-instantiation phase during BeanFactory bootstrap. This interface can be implemented by singleton beans in order to perform some initialization after the regular singleton instantiation algorithm, avoiding side effects with accidental early initialization (e.g. from ListableBeanFactory.getBeansOfType calls). In that sense, it is an alternative to InitializingBean which gets triggered right at the end of a bean’s local construction phase.
看到其作用和 InitializingBean 類似,用于構造函數(shù)后的初始化操作,不過該接口是所有bean被創(chuàng)建之后被調(diào)用。在所有 bean的構造方法、初始化(@PostConstruct、InitializingBean)、BeanPostProcessor都執(zhí)行完畢后再執(zhí)行該接口方法,注意是所有bean都執(zhí)行完這些方法。
Invoked right at the end of the singleton pre-instantiation phase, with a guarantee that all regular singleton beans have been created already.
public class EventListenerMethodProcessor
implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
// 負責設置EventListenerFactory
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 回調(diào)beanFactory賦值
this.beanFactory = beanFactory;
// 拿到所有的EventListenerFactory
Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
List<EventListenerFactory> factories = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(factories);
// 設置eventListenerFactories
this.eventListenerFactories = factories;
}
@Override
public void afterSingletonsInstantiated() {
...
processBean(beanName, type);
...
}
private void processBean(final String beanName, final Class<?> targetType) {
if (
// 不包含@EventListener的類的備忘錄是否有該類型
!this.nonAnnotatedClasses.contains(targetType) &&
// 該類型的type, method or field 是否能被注解@EventListener
AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
// 不能是org.springframework開頭的類,或者被注解了@Component,注意是或者
!isSpringContainerClass(targetType)
) {
// 提取所有的方法
Map<Method, EventListener> annotatedMethods = null;
try {
annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method ->
AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
}
...
if (CollectionUtils.isEmpty(annotatedMethods)) {
// 備忘錄,加入已掃描的沒有注解@EventListener的類
this.nonAnnotatedClasses.add(targetType);
...
}
else {
// Non-empty set of methods
ConfigurableApplicationContext context = this.applicationContext;
Assert.state(context != null, "No ApplicationContext set");
List<EventListenerFactory> factories = this.eventListenerFactories;
Assert.state(factories != null, "EventListenerFactory List not initialized");
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
// 生成ApplicationListener
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
}
context.addApplicationListener(applicationListener);
break;
}
...ApplicationListener監(jiān)聽到事件后的執(zhí)行是同步過程,如果需要異步,可搭配@Async+@EventListener
事務消息監(jiān)聽器
spring-tx包下提供TransactionalApplicationListener接口和@TransactionalEventListener注解。
TransactionalApplicationListener接口:An ApplicationListener that is invoked according to a TransactionPhase. NOTE: Transactional event listeners only work with thread-bound transactions managed by a PlatformTransactionManager.
到此這篇關于Spring的事件發(fā)布與監(jiān)聽方式案例講解的文章就介紹到這了,更多相關Spring事件發(fā)布與監(jiān)聽內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- 詳解SpringBoot實現(xiàn)ApplicationEvent事件的監(jiān)聽與發(fā)布
- spring event 事件異步處理方式(發(fā)布,監(jiān)聽,異步處理)
- SpringBoot事件發(fā)布與監(jiān)聽超詳細講解
- Spring事件發(fā)布監(jiān)聽,順序監(jiān)聽,異步監(jiān)聽方式
- SpringBoot事件發(fā)布和監(jiān)聽詳解
- 詳解Spring事件發(fā)布與監(jiān)聽機制
- 解析Spring事件發(fā)布與監(jiān)聽機制
- 詳解SpringBoot 發(fā)布ApplicationEventPublisher和監(jiān)聽ApplicationEvent事件
相關文章
基于Jackson實現(xiàn)API接口數(shù)據(jù)脫敏的示例詳解
用戶的一些敏感數(shù)據(jù),例如手機號、郵箱、身份證等信息,在數(shù)據(jù)庫以明文存儲,但在接口返回數(shù)據(jù)給瀏覽器(或三方客戶端)時,希望對這些敏感數(shù)據(jù)進行脫敏,所以本文就給大家介紹以惡如何利用Jackson實現(xiàn)API接口數(shù)據(jù)脫敏,需要的朋友可以參考下2023-08-08
為什么 Java 8 中不需要 StringBuilder 拼接字符串
java8中,編輯器對“+”進行了優(yōu)化,默認使用StringBuilder進行拼接,所以不用顯示的使用StringBuilder了,直接用“+”就可以了。下面我們來詳細了解一下2019-05-05

