先域名 还是先做网站,怎么建设网站上传音乐,移动互联网开发的特点,老狼请客高清免费观看mx1.前言
很多时候我们看源码的时候看不下去#xff0c;其中一个原因是系统往往使用了许多设计模式#xff0c;如果你不清楚这些设计模式#xff0c;这无疑增加了你阅读源码的难度。
springboot中就大量使用了设计模式#xff0c;本文主要介绍其中的一种监听器模式#xf…1.前言
很多时候我们看源码的时候看不下去其中一个原因是系统往往使用了许多设计模式如果你不清楚这些设计模式这无疑增加了你阅读源码的难度。
springboot中就大量使用了设计模式本文主要介绍其中的一种监听器模式这是观察者模式中的一种。
作者利用空闲时间去阅读了一下相关的源码然后决定分享出来大家相互学习。
这篇文章主要分为3个部分:
第一个部分主要讲下监听模式的几个步骤以及一个简单的例子这样我们在阅读源码的时候就知道是怎么回事了。
第二个部分是这篇文章的核心也就是springboot中是如何使用监听模式的。
第三个部分主要是在spingboot中自定义实现监听功能
2.监听模式
实现监听模式的四个步骤
创建事件创建事件的监听器创建广播器发布事件
我们就按照上面的步骤实现一个监听功能
2.1新建工程
创建一个springboot工程主要的依赖是这个
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId
/dependency我们的springboot版本是2.7.17
2.2创建事件
先创建一个基础的模板事件
package com.example.springbootcode.order.event;public abstract class OrderEvent {abstract void desc();
}这是一个抽象类里面定义了抽象方法接下里就创建具体的事件
订单开始创建事件
package com.example.springbootcode.order.event;public class OrderCreateStartingEvent extends OrderEvent{Overridepublic void desc() {System.out.print(第一步开始创建订单……);}
}订单创建完成事件
package com.example.springbootcode.order.event;public class OrderCreateFinishEvent extends OrderEvent{Overridepublic void desc() {System.out.print(最后一步订单创建完成,……);}
}这里定义了两个事件都继承了OrderEvent实现了里面的desc方法
2.3创建监听器
创建一个监听器接口
package com.example.springbootcode.order.event;public interface OrderListener {void onOrderEvent(OrderEvent event);
}定义了一个监听事件的方法其参数就是事件接下来我们实现具体的监听器
订单创建过程监听器
public class OrderLogListener implements OrderListener{Overridepublic void onOrderEvent(OrderEvent event) {if (event instanceof OrderCreateStartingEvent) {event.desc();} else if (event instanceof OrderCreateFinishEvent){event.desc();}}
}监听事件并调用事件里面的desc()方法
2.4创建广播器
定义事件广播器接口
package com.example.springbootcode.order.event;public interface EventMulticaster {void multicasterEvent(OrderEvent event);void addListener(OrderListener listener);void removeListener(OrderListener listener);
}广播器我们可以这样理解主要复杂监听器的管理并将事件广播给所有监听器如果该监听器对广播的事件感兴趣那么就会处理事件。
接下来实现一下具体的广播器
package com.example.springbootcode.order.event;import java.util.ArrayList;
import java.util.List;public class OrderEventMulticaster implements EventMulticaster{ListOrderListener listenerList new ArrayList();Overridepublic void multicasterEvent(OrderEvent event) {listenerList.forEach(listener - listener.onOrderEvent(event));}Overridepublic void addListener(OrderListener listener) {listenerList.add(listener);}Overridepublic void removeListener(OrderListener listener) {listenerList.remove(listener);}
}这里主要实现了3个方法事件广播、新增监听器、删除监听器
2.5发布事件
发布事件其实说白了就是在项目中调用OrderEventMulticaster
SpringBootApplication
public class SpringbootCodeApplication {public static void main(String[] args) {SpringApplication.run(SpringbootCodeApplication.class, args);OrderEventMulticaster orderEventMulticaster new OrderEventMulticaster();orderEventMulticaster.addListener(new OrderLogListener());orderEventMulticaster.multicasterEvent(new OrderCreateStartingEvent());}
}加了两个监听器然后我们发布了一个订单开始创建事件控制台会打印第一步开始创建订单……
到这里为止一个简单的监听模式就实现了接下来我们根据这个例子去阅读一下springboot源码中关于监听器的部分。
3.监听模式源码精讲
由于springboot有太多地方使用了监听模式我们不可能去阅读所有代码这也不是我写这篇文章的目的。我们只需了解其中的一个事件、一个监听器就知道springboot大概是怎么实现事件的监听和发布。
下面我们以应用程序启动为例看看其是怎么实现事件的监听和发布。
3.1启动事件
在讲启动事件之前我们先来看看springboot跟生命周期相关的事件脉络
由图可以发现启动程序开始到完成会发布ApplicationStartingEvent、ApplicationPreparedEvent、ApplicationReadyEvent、ApplicationStartedEvent……这些事件。
其实由名字大概就知道它们的意思这里我们以 ApplicationStartingEvent 这个开始启动事件为例去看了解其实现过程。
EventObject
是所有事件状态对象的根类 这是 java.util 包中的 EventObject 类的源代码里面有个方法 getSource() 用于返回事件最初发生的对象。
ApplicationEvent
提供了一个基本的事件模型为应用程序中的事件提供了一种通用的表示方式 。
SpringApplicationEvent
提供了一个 与 Spring Boot 应用程序的启动过程相关的事件通用的基类这里就是类似于我们前面例子中的OrderEvent事件
public abstract class SpringApplicationEvent extends ApplicationEvent {private final String[] args;public SpringApplicationEvent(SpringApplication application, String[] args) {super(application);this.args args;}public SpringApplication getSpringApplication() {return (SpringApplication) getSource();}public final String[] getArgs() {return this.args;}
}总得来说就是获取事件的源和事件相关的参数
ApplicationStartingEvent
这个就是启动事件了类似于我们例子中的OrderCreateStartingEvent我们看看这个启动事件的代码
public class ApplicationStartingEvent extends SpringApplicationEvent {private final ConfigurableBootstrapContext bootstrapContext;public ApplicationStartingEvent(ConfigurableBootstrapContext bootstrapContext, SpringApplication application,String[] args) {super(application, args); // Ⅰthis.bootstrapContext bootstrapContext; // Ⅱ}public ConfigurableBootstrapContext getBootstrapContext() {return this.bootstrapContext;}}它干了下面这些事
Ⅰ 调用父类的构造函数将 application 设置为事件的源将参数数组 args 设置为事件的相关参数
**Ⅱ**初始化一个上下文接口并通过getBootstrapContext()来获取该对象
总得来说这个事件是比较简单的。
3.2监听器
还是一样我们先上图先了解一下关于启动程序事件监听器的实现脉络 EventListener
这是一个标记接口 在 Java 编程中常用于为一组类提供一个共同的标记而不包含任何方法。标记接口通常用于指示类具有某种特定的性质、行为或能力。
ApplicationListener
这是 Spring Framework 中的 ApplicationListener 接口用于定义应用程序事件监听器这里就类似于上面例子中的OrderListener
FunctionalInterface //Ⅰ
public interface ApplicationListenerE extends ApplicationEvent extends EventListener {void onApplicationEvent(E event); // Ⅱstatic T ApplicationListenerPayloadApplicationEventT forPayload(ConsumerT consumer) {return event - consumer.accept(event.getPayload());}}Ⅰ FunctionalInterface 是 Java 注解用于标记一个接口指示它是一个函数式接口。函数式接口是只包含一个抽象方法的接口通常用于支持 Lambda 表达式和函数引用。
ⅡonApplicationEvent(E event)处理事件其参数是一个泛型但必须是继承ApplicationEvent
SmartApplicationListener和GenericApplicationListener主要是为了扩展ApplicationListener这里就不深入讲解了。springboot这样设计的目的其实就是后续的扩展而不是把所有东西都写在ApplicationListener基本上所有的系统都是这么个原则。
LoggingApplicationListener
最后我们的主角登场了从名字大概可以猜到这是一个跟启动日志记录监听器它会在启动过程的某个阶段记录日志下面是核心代码
public class LoggingApplicationListener implements GenericApplicationListener {// 省略……Overridepublic void onApplicationEvent(ApplicationEvent event) {if (event instanceof ApplicationStartingEvent) {onApplicationStartingEvent((ApplicationStartingEvent) event);}else if (event instanceof ApplicationEnvironmentPreparedEvent) {onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);}else if (event instanceof ApplicationPreparedEvent) {onApplicationPreparedEvent((ApplicationPreparedEvent) event);}else if (event instanceof ContextClosedEvent) {onContextClosedEvent((ContextClosedEvent) event);}else if (event instanceof ApplicationFailedEvent) {onApplicationFailedEvent();}}// 省略……
}从代码中可以看到它是监听启动过程的所有事件其中第一个就是我们上面讲到的ApplicationStartingEvent开始启动事件这里类似于我们上面例子中的OrderLogListener
3.3广播器
跟上面一样我们还是先上图 ApplicationEventMulticaster
package org.springframework.context.event;import java.util.function.Predicate;import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;public interface ApplicationEventMulticaster {void addApplicationListener(ApplicationListener? listener);void addApplicationListenerBean(String listenerBeanName);void removeApplicationListener(ApplicationListener? listener);void removeApplicationListenerBean(String listenerBeanName);void removeApplicationListeners(PredicateApplicationListener? predicate);void removeApplicationListenerBeans(PredicateString predicate);void removeAllListeners();void multicastEvent(ApplicationEvent event);void multicastEvent(ApplicationEvent event, Nullable ResolvableType eventType);}定义事件广播器接口类似于前面例子中的EventMulticaster
AbstractApplicationEventMulticaster
public abstract class AbstractApplicationEventMulticasterimplements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {//省略……Overridepublic void addApplicationListener(ApplicationListener? listener) {synchronized (this.defaultRetriever) {// Explicitly remove target for a proxy, if registered already,// in order to avoid double invocations of the same listener.Object singletonTarget AopProxyUtils.getSingletonTarget(listener);if (singletonTarget instanceof ApplicationListener) {this.defaultRetriever.applicationListeners.remove(singletonTarget);}this.defaultRetriever.applicationListeners.add(listener);this.retrieverCache.clear();}}//省略……Overridepublic void removeApplicationListener(ApplicationListener? listener) {synchronized (this.defaultRetriever) {this.defaultRetriever.applicationListeners.remove(listener);this.retrieverCache.clear();}}}这是一个抽象类实现了监听器的新增和删除的具体逻辑这样做的目的就是封装一些通用的功能至于说要不要加一个这样的抽象类完全就是根据你的实际业务情况而定。
SimpleApplicationEventMulticaster
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {//省略……Overridepublic void multicastEvent(ApplicationEvent event) {multicastEvent(event, resolveDefaultEventType(event));}Overridepublic void multicastEvent(final ApplicationEvent event, Nullable ResolvableType eventType) {ResolvableType type (eventType ! null ? eventType : resolveDefaultEventType(event));Executor executor getTaskExecutor();for (ApplicationListener? listener : getApplicationListeners(event, type)) {if (executor ! null) {executor.execute(() - invokeListener(listener, event));}else {invokeListener(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()) ||(event instanceof PayloadApplicationEvent matchesClassCastMessage(msg, ((PayloadApplicationEvent) event).getPayload().getClass()))) {// Possibly a lambda-defined listener which we could not resolve the generic event type for// - lets suppress the exception.Log loggerToUse this.lazyLogger;if (loggerToUse null) {loggerToUse LogFactory.getLog(getClass());this.lazyLogger loggerToUse;}if (loggerToUse.isTraceEnabled()) {loggerToUse.trace(Non-matching event type for listener: listener, ex);}}else {throw ex;}}}
}这个类继承AbstractApplicationEventMulticaster并且实现了multicastEvent()广播事件这类似于例子中的OrderEventMulticaster
3.4发布事件
前面所有东西都准备好了看看程序启动时是如何监听事件的。我们从启动类开始跟跟踪
SpringBootApplication
public class SpringbootCodeApplication {public static void main(String[] args) {SpringApplication.run(SpringbootCodeApplication.class, args);}
}进入run方法
public class SpringApplication {// 省略代码public static ConfigurableApplicationContext run(Class? primarySource, String... args) {return run(new Class?[] { primarySource }, args);}public static ConfigurableApplicationContext run(Class?[] primarySources, String[] args) {// ⅠSpringApplication Ⅱrunreturn new SpringApplication(primarySources).run(args); }public SpringApplication(Class?... primarySources) {this(null, primarySources);}// ⅢSuppressWarnings({ unchecked, rawtypes })public SpringApplication(ResourceLoader resourceLoader, Class?... primarySources) {this.resourceLoader resourceLoader;Assert.notNull(primarySources, PrimarySources must not be null);this.primarySources new LinkedHashSet(Arrays.asList(primarySources));this.webApplicationType WebApplicationType.deduceFromClasspath();this.bootstrapRegistryInitializers new ArrayList(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));// ⅣsetListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass deduceMainApplicationClass();}// Ⅴpublic void setListeners(Collection? extends ApplicationListener? listeners) {this.listeners new ArrayList(listeners);}}Ⅰ我们先进入SpringApplication构造函数最后我们发现会来到Ⅰ-Ⅲ-Ⅳ-Ⅴthis.listeners存储了启动时需要加载的监听器。
我们看看this.listeners存储了哪些监听器 我们可以发现LoggingApplicationListener监听器也保存在里面接下来就是怎么把这些监听器加载到广播器中 构造函数实际上时初始化一些变量 还记得上面**Ⅱ**run这个注释吗构造函数执行完后开始执行run方法我们进入run方法
public ConfigurableApplicationContext run(String... args) {long startTime System.nanoTime();DefaultBootstrapContext bootstrapContext createBootstrapContext();ConfigurableApplicationContext context null;configureHeadlessProperty();SpringApplicationRunListeners listeners getRunListeners(args);// Ⅵlisteners.starting(bootstrapContext, this.mainApplicationClass);// 省略代码return context;
}**Ⅵ**这里就是发布一个启动开始事件了进入starting方法
package org.springframework.boot;
class SpringApplicationRunListeners {// Ⅰvoid starting(ConfigurableBootstrapContext bootstrapContext, Class? mainApplicationClass) {doWithListeners(spring.boot.application.starting, (listener) - listener.starting(bootstrapContext),(step) - {if (mainApplicationClass ! null) {step.tag(mainApplicationClass, mainApplicationClass.getName());}});}// 省略代码}这里都是发布启动相关的事件starting里面调用了doWithListeners方法其中最主要的是第二个参数是一个表达式我们进去看看最后我们来到这里
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {//省略代码// 前面已经被初始化过public EventPublishingRunListener(SpringApplication application, String[] args) {this.application application;this.args args;// Ⅰ new广播器this.initialMulticaster new SimpleApplicationEventMulticaster();for (ApplicationListener? listener : application.getListeners()) {// Ⅱ 添加监听器application.getListeners()获取的就是前面的this.listenersthis.initialMulticaster.addApplicationListener(listener);}}//省略代码Overridepublic void starting(ConfigurableBootstrapContext bootstrapContext) {this.initialMulticaster// Ⅲ 广播事件.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));}//省略代码
}这里的步骤就像我们上面例子中的一样
SpringBootApplication
public class SpringbootCodeApplication {public static void main(String[] args) {SpringApplication.run(SpringbootCodeApplication.class, args);OrderEventMulticaster orderEventMulticaster new OrderEventMulticaster();orderEventMulticaster.addListener(new OrderLogListener());orderEventMulticaster.multicasterEvent(new OrderCreateStartingEvent());}
}new一个广播器然后添加监听器最后是广播事件。
4.自定义监听器
了解了spingboot的监听模式后接下来我们看看如何在springboot项目中使用它。
4.1创建事件
package com.example.springbootcode.my;import org.springframework.context.ApplicationEvent;public class UserMsgEvent extends ApplicationEvent {public UserMsgEvent(Object source) {super(source);}// 自定义自己的逻辑方法public void sendMsg(){System.out.print(向用户发送消息);}
}这里需要注意的是我们继承的是ApplicationEvent不继承SpringApplicationEvent主要是因此其跟启动相关的我们定义的事件明显跟应用启动没啥关系。
4.2创建监听器
package com.example.springbootcode.my;import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;Component
public class UserListener implements ApplicationListenerUserMsgEvent {Overridepublic void onApplicationEvent(UserMsgEvent event) {event.sendMsg();}
}这里继承ApplicationListener
4.3自定义触发事件
package com.example.springbootcode.my;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;Service
public class UserService {private final ApplicationEventPublisher eventPublisher;public UserService(ApplicationEventPublisher eventPublisher) {this.eventPublisher eventPublisher;}public void send(){eventPublisher.publishEvent(new UserMsgEvent(this));}
}通过构造函数注入 ApplicationEventPublisher 这是一个Spring框架提供的接口用于发布事件
最后在需要调用的地方调用UserService里面的send方法即可