架构师集合之Spring的ApplicationListener(监听)

首先来个demo看看怎么使用:

定义事件:

public class EmailEvent extends ApplicationEvent{
   private String address;
   private String text;
   public EmailEvent(Object source, String address, String text){
   super(source);
      this.address = address;
      this.text = text;
   }
   public EmailEvent(Object source) {
     super(source);
   }
   //......address和text的setter、getter
}

定义监听:

@Component
public class EmailNotifier implements ApplicationListener{
   public void onApplicationEvent(ApplicationEvent event) {
     if (event instanceof EmailEvent) {
        EmailEvent emailEvent = (EmailEvent)event;
        System.out.println("邮件地址:" + emailEvent.getAddress());
        System.our.println("邮件内容:" + emailEvent.getText());
     } else {
       
     }
   }
}

测试:

public class SpringTest {
   public static void main(String args[]){
     ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
     //创建一个ApplicationEvent对象
     EmailEvent event = new EmailEvent("hello","abc@163.com","This is a test");
     //主动触发该事件
     context.publishEvent(event);
   }
}

看看结果:

邮件地址:abc@163.com
邮件内容:This is a test

通过上面的案例可以知道,我们需要先定义一个事件类继承ApplicationEvent,然后定义一个监听实现ApplicationListener,并且要把监听加入到spring管理中(可以使用注解方式或者xml方式),最后使用的时候只要实例化事件,然后发布事件,那么自然能监听到事件。

源码分析

找到spring源码路径ClassPathXmlApplicationContext->AbstractApplicationContext的refresh方法->initApplicationEventMulticaster方法:

protected void initApplicationEventMulticaster() {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	/**
	 * 判断容器中是否存在bdName为applicationEventMulticaster的bd
	 * 也就是自定义的事件监听多路广播器,必须实现ApplicationEventMulticaster接口
	 */
	if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
		this.applicationEventMulticaster =
				beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
		if (logger.isDebugEnabled()) {
			logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
		}
	}
	else {
		/**
		 * 如果没有,则默认采用SimpleApplicationEventMulticaster
		 */
		this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
		beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
		if (logger.isDebugEnabled()) {
			logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
					APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
					"': using default [" + this.applicationEventMulticaster + "]");
		}
	}
}

这里就是初始化ApplicationEventMulticaster。

接下来我们看看AbstractApplicationContext的refresh方法->finishRefresh方法:

protected void finishRefresh() {
		// Initialize lifecycle processor for this context.
//初始化生命周期管理器LifecycleProcessor
		initLifecycleProcessor();
 
		// Propagate refresh to lifecycle processor first.
//启动所有实现了Lifecycle接口的bean
		getLifecycleProcessor().onRefresh();
 
		// Publish the final event.
//发布刷新完成事件
		publishEvent(new ContextRefreshedEvent(this));
 
		// Participate in LiveBeansView MBean, if active.
		LiveBeansView.registerApplicationContext(this);
	}

再进入publishEvent(new ContextRefreshedEvent(this)):

protected void publishEvent(Object event, ResolvableType eventType) {
		Assert.notNull(event, "Event must not be null");
		if (logger.isTraceEnabled()) {
			logger.trace("Publishing event in " + getDisplayName() + ": " + event);
		}

		// Decorate event as an ApplicationEvent if necessary
    // 将事件封装为ApplicationEvent
		ApplicationEvent applicationEvent;
		if (event instanceof ApplicationEvent) {
			applicationEvent = (ApplicationEvent) event;
		}
		else {
			applicationEvent = new PayloadApplicationEvent<Object>(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...
    // 通过parent发布时间
		if (this.parent != null) {
			if (this.parent instanceof AbstractApplicationContext) {
				((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
			}
			else {
				this.parent.publishEvent(event);
			}
		}
	}

接下来看看multicastEvent(applicationEvent, eventType)方法:

	@Override
	public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			Executor executor = getTaskExecutor();
			if (executor != null) {
				executor.execute(new Runnable() {
					@Override
					public void run() {
						invokeListener(listener, event);
					}
				});
			}
			else {
				invokeListener(listener, event);
			}
		}
	}

上面就是遍历ApplicationListener,然后执行invokeListener(listener, event),那么接下来我们看看invokeListener:

protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
		ErrorHandler errorHandler = getErrorHandler();
		if (errorHandler != null) {
			try {
				listener.onApplicationEvent(event);
			}
			catch (Throwable err) {
				errorHandler.handleError(err);
			}
		}
		else {
			try {
				listener.onApplicationEvent(event);
			}
			catch (ClassCastException ex) {
				String msg = ex.getMessage();
				if (msg == null || msg.startsWith(event.getClass().getName())) {
					// Possibly a lambda-defined listener which we could not resolve the generic event type for
					Log logger = LogFactory.getLog(getClass());
					if (logger.isDebugEnabled()) {
						logger.debug("Non-matching event type for listener: " + listener, ex);
					}
				}
				else {
					throw ex;
				}
			}
		}
	}

这里就知道了最后是调用了listener.onApplicationEvent(event)方法,这就是为什么我们实现ApplicationListener 接口,重写onApplicationEvent方法就能监听到事件了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小明程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值