博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring中ApplicationListener监听器设计解析
阅读量:2488 次
发布时间:2019-05-11

本文共 13108 字,大约阅读时间需要 43 分钟。

在设计模式中,观察者模式中主要由观察者和主题事件这两个角色组成,而Spring中的监听器设计相对设计模式中的观察者模式来说更加抽象,主要多出了一些额外的角色,目的是为了能够更好的让观察者和事件解耦,一起来学习一下吧!

设计模式中的观察者模式 V.S Spring监听器

设计模式中的观察者模式角色:

  1. 抽象主题(Subject):
    它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。 抽象主题提供一个接口,可以增加和删除观察者对象。
  2. 具体主题(Concrete Subject):
    将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
  3. 抽象观察者(Observer):
    为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
  4. 具体观察者(Concrete Observer):
    实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调

Spring监听器主要角色

  1. ApplicationEvent :
    事件抽象类,根据不同的事件
  2. ApplicationListener:
    接口,只有一个方法,传递了一个事件
  3. ApplicationEventMulticaster:
    事件多播器,主要就是用来负责对ApplicationListener的管理,添加、删除、事件广播。
  4. ApplicationEventPublisher:
    接口,主要用于发布事件

类的设计图

在这里插入图片描述

Spring启动时发布事件源码分析

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try {
// Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. //初始化事件多播器 initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. //注册监听器 registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. //改方法中包含了:发布事件 finishRefresh(); } catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally {
// Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }

1、创建一个事件多播器,方法入口在refresh方法中。

protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory(); //第一次进来工厂中肯定没有这个bean if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); } } else {
//创建一个SimpleApplicationEventMulticaster的多播器 this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); //注册一级缓存中。 beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " + "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]"); } } }

2、注册监听器

protected void registerListeners() {
// Register statically specified listeners first. //获取应用程序中的监听器集合,添加到applicationListeners集合中 for (ApplicationListener
listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener); } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let post-processors apply to them! //获取实现了ApplicationListener接口的类,并放入applicationListenerBeans集合中 String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } // Publish early application events now that we finally have a multicaster... Set
earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent); } } }

3、发布事件

protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning). clearResourceCaches(); // Initialize lifecycle processor for this context. initLifecycleProcessor(); // Propagate refresh to lifecycle processor first. getLifecycleProcessor().onRefresh(); // Publish the final event. //发布事件 publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active. LiveBeansView.registerApplicationContext(this); }
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null"); // Decorate event as an ApplicationEvent if necessary ApplicationEvent applicationEvent; if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event; } else {
applicationEvent = new PayloadApplicationEvent<>(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 {
//调用多播器的multicastEvent方法发布事件 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); } // Publish event via parent context as well... if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType); } else {
this.parent.publishEvent(event); } } }
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); Executor executor = getTaskExecutor(); //从第二步注册时,准备好的两个集合中获取监听器。applicationListenerBeans、applicationListeners for (ApplicationListener
listener : getApplicationListeners(event, type)) {
if (executor != null) {
//调用给定事件的监听器方法 executor.execute(() -> invokeListener(listener, event)); } else {
invokeListener(listener, event); } } }
protected void invokeListener(ApplicationListener
listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler(); if (errorHandler != null) {
try {
doInvokeListener(listener, event); } catch (Throwable err) {
errorHandler.handleError(err); } } else {
//具体调用 doInvokeListener(listener, event); } }
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
//最终回调到了接口方法,由实现者自行实现。 listener.onApplicationEvent(event); } catch (ClassCastException ex) {
String msg = ex.getMessage(); if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for // -> let's suppress the exception and just log a debug message. Log logger = LogFactory.getLog(getClass()); if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex); } } else {
throw ex; } } }

如何发布一个自己的事件

1、注解+实现ApplicationListener接口

package com.wyl.learn.listen;import org.springframework.context.ApplicationEvent;import org.springframework.context.ApplicationListener;import org.springframework.stereotype.Component;@Componentpublic class MyListener implements ApplicationListener {
@Override public void onApplicationEvent(ApplicationEvent event) {
System.out.println(event); System.out.println("my listener event==============="); }}
package com.wyl.learn;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestSpring {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.wyl.learn"); }}

在这里插入图片描述

通过上述分析现在应该清楚,onApplicationEvent方法的调用就是在启动时,发布了一个publishEvent(new ContextRefreshedEvent(this));事件时触发的。

当没有指定具体事件类型时,任何事件的发布都会调用到onApplicationEvent方法。

指定一个自定义的事件类型。

public class MyEvent extends ApplicationEvent {
/** * Create a new {@code ApplicationEvent}. * * @param source the object on which the event initially occurred or with * which the event is associated (never {@code null}) */ public MyEvent(Object source) {
super(source); }}
package com.wyl.learn.listen;import org.springframework.context.ApplicationEvent;import org.springframework.context.ApplicationListener;import org.springframework.stereotype.Component;@Componentpublic class MyListener implements ApplicationListener
{
/*@Override public void onApplicationEvent(ApplicationEvent event) { System.out.println(event); System.out.println("my listener event==============="); }*/ @Override public void onApplicationEvent(MyEvent event) {
System.out.println(event); System.out.println("my listener event==============="); }}

此时再启动Spring时,则不会触发MyListener的onApplicationEvent方法调用。

2、手动发布

对于自定义的事件,只需通过手动发布即可。

package com.wyl.learn;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestSpring {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.wyl.learn"); //发布指定事件 applicationContext.publishEvent(new MyEvent("自定义事件发布")); }}

在这里插入图片描述

3、@EventListener注解

使用@EventListener注解的方式可以使代码更加简洁,减少Listener的创建。

import org.springframework.context.event.EventListener;import org.springframework.stereotype.Component;@Componentpublic class MyAnnotationListener {
@EventListener public void myEvent(MyEvent myEvent){
System.out.println("使用@EventListener注解方式发布事件"); System.out.println(myEvent.toString()); }}

有了注解MyListener类就用不到了,MyEvent还是和之前的一样,启动方法也不变。

package com.wyl.learn;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestSpring {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.wyl.learn"); //发布指定事件 applicationContext.publishEvent(new MyEvent("自定义事件发布")); }}

在这里插入图片描述

SpringBoot中的运用

SpringBoot中run方法也用到了一些监听器,当你理解了spring的监听器设计后,再看SpringBoot时则会非常轻松。

public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection
exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); //看看这个监听器是如何使用的 listeners.starting(); try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] {
ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try {
listeners.running(context); } catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }
public void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting(); } }

看看这个方法,不就和上面spring启动时使用的方法一样嘛,连多播器都是spring中默认的SimpleApplicationEventMulticaster,后面方法已经不用看了。

在这里插入图片描述

转载地址:http://allrb.baihongyu.com/

你可能感兴趣的文章
mongodb查询优化
查看>>
五步git操作搞定Github中fork的项目与原作者同步
查看>>
git 删除远程分支
查看>>
删远端分支报错remote refs do not exist或git: refusing to delete the current branch解决方法
查看>>
python multiprocessing遇到Can’t pickle instancemethod问题
查看>>
APP真机测试及发布
查看>>
通知机制 (Notifications)
查看>>
10 Things You Need To Know About Cocoa Auto Layout
查看>>
一个异步网络请求的坑:关于NSURLConnection和NSRunLoopCommonModes
查看>>
iOS 如何放大按钮点击热区
查看>>
ios设备唯一标识获取策略
查看>>
获取推送通知的DeviceToken
查看>>
Could not find a storyboard named 'Main' in bundle NSBundle
查看>>
CocoaPods安装和使用教程
查看>>
Beginning Auto Layout Tutorial
查看>>
block使用小结、在arc中使用block、如何防止循环引用
查看>>
iPhone开发学习笔记002——Xib设计UITableViewCell然后动态加载
查看>>
iOS开发中遇到的问题整理 (一)
查看>>
Swift code into Object-C 出现 ***-swift have not found this file 的问题
查看>>
为什么你的App介绍写得像一坨翔?
查看>>