当前位置: 首页 > 科技观察

别写for循环了,Spring自带的观察者模式很香!

时间:2023-03-13 19:51:54 科技观察

分享如何在Spring/SpringBoot中实现观察者模式。循环编程再也不用面试了,Spring框架自带的事件监听机制,实现观察者模式,为你轻松实现解耦!Spring事件监听机制其实在Spring/SpringBoot框架中就有一套事件监听机制,可以实现观察者模式。Spring/SpringBoot框架中也有很多内置的事件,我们也可以自定义发布应用事件,下面会介绍。主要涉及的核心类和接口如下:ApplicationEventApplicationEvent(应用事件)是一个抽象类,相当于观察者模式下的观察目标。ApplicationEvent源码如下:publicabstractclassApplicationEventextendsEventObject{/**useserialVersionUIDfromSpring1.2forinteroperability.*/privatestaticfinallongserialVersionUID=7099057708183571937L;/**Systemtimewhentheeventhappened.*/privatefinallongtimestamp;/***Createanew{@codeApplicationEvent}.*@paramsourcetheobjectonwhichtheeventinitiallyoccurredorwith*whichtheeventisassociated(never{@codenull})*/publicApplicationEvent(Objectsource){super(source);this.timestamp=System.currentTimeMillis();}/***Returnthesystemtimeinmillisecondswhentheeventoccurred.*/publicfinallonggetTimestamp(){returnthis.timestamp;}}ApplicationEvent继承自Java中的EventObject事件对象类,Spring框架中的所有事件都继承自ApplicationEvent类,它是所有事件的父类。ApplicationEvent的主要核心是类构造器,它可以初始化一个源事件关联对象,在事件监听器中获取和通知更新。ApplicationListenerApplicationListener(应用程序事件监听器)是一个接口,相当于观察者模式下的观察者。ApplicationListener源码如下:publicinterfaceApplicationListenerextendsEventListener{/***Handleanaapplicationevent.*@parameventtheeventtorespondto*/voidonApplicationEvent(Eevent);}ApplicationListener继承自Java中的EventListener事件监听接口。当ApplicationListener类中只指定了一个onApplication方法时,事件发布后会被触发执行,可以通过event获取事件中关联的对象。ApplicationEventPublisher应用事件发布接口,封装了事件发布功能的基础接口。publicinterfaceApplicationEventPublisher{/***Notifyallma??tchinglistenersregisteredwiththis*applicationofanapplicationevent.Eventsmaybeframeworkevents*(suchasContextRefreshedEvent)orapplication-specificevents.*

Suchaneventpublicationstepiseffectivelyahand-offtothe*multicasteranddoesnotimplysynchronous/asynchronousexecution*orevenimmediateexecutionatall.Eventlistenersareencouraged*tobeasefficientaspossible,individuallyusingasynchronous*executionforlonger-runningandpotentiallyblockingoperations.*@parameventtheeventtopublish*@see#publishEvent(Object)*@seeorg.springframework.context.event.ContextRefreshedEvent*@seeorg.springframework.context.event.ContextClosedEvent*/defaultvoidpublishEvent(ApplicationEventevent){publishEvent((Object)event);}/***通知所有匹配注册了这个*applicationofanevent的监听器。*

如果指定的{@codeevent}不是{@linkApplicationEvent},*itiswrappedina{@linkPayloadApplicationEvent}.*

Suchaneventpublicationstepiseffectivelyahand-offtothe*multicasteranddoesnotimplysynchronous/asynchronousexecution*orevenimmediateexecutionatall.Eventlistenersareencouraged*tobeasefficientaspossible,individuallyusingasynchronous*executionforlonger-runningandpotentiallyblockingoperations.*@parameventtheeventtopublish*@since4.2*@see#publishEvent(ApplicationEvent)*@seePayloadApplicationEvent*/voidpublishEvent(Objectevent);}ApplicationEventPublisher有一个默认接口方法和一个接口方法。接口方法需要具体的子类容器来实现。如下图所示,ApplicationContext接口继承了ApplicationEventPublisher接口,所以可以使用常用的ApplicationContext来发布事件。上面介绍的Spring事件监听和发布角色结合起来发布ApplicationEvent事件,通过ApplicationEventPublisher或者ApplicationContext容器关联事件对象,然后ApplicationListener监听事件。当事件发布时,监听器将执行它并获得事件和关联的对象。SpringBootObserverMode了解了Spring框架中的事件和监听机制之后,我们就以上一篇文章中的ObserverMode为例进行改造。SpringBoot的基础知识和构建过程就不做介绍了。不熟悉的可以关注公众号Java技术栈,后台回复关键词“boot”阅读我之前写的系列教程。所有SpringBoot教程实战源码在以下仓库:https://github.com/javastacks/spring-boot-best-practice新建观察者目标类importlombok.Getter;importorg.springframework.context.ApplicationEvent;/***观察对象:栈长*来源微信公众号:Java技术栈{super(source);}}实现了Spring框架中的ApplicationEvent应用事件接口,相当于一个observertarget。添加观察者类importlombok.NonNull;importlombok.RequiredArgsConstructor;importorg.springframework.context.ApplicationListener;importorg.springframework.scheduling.annotation.Async;*/@RequiredArgsConstructorpublicclassReaderListenerimplementsApplicationListener{@NonNullprivateStringname;privateStringarticle;@Async@OverridepublicvoidonApplicationEvent(JavaStackEventevent){//更新文章updateArticle(event);}privatevoidupdateArticle(JavaStackEventevent){this.article=(String)event.getSource();System.out.printf("我是读者:%s,文章已更新为:%s\n",this.name,this.article);}}在Spring框架中实现ApplicationListener应用监听接口,该接口相当于观察者。观察目标和观察者类的结构图如下:新建测试配置类importlombok.extern.slf4j.Slf4j;importorg.springframework.boot.CommandLineRunner;importorg.springframework.context.ApplicationContext;importorg.springframework.context.annotation。Bean;importorg.springframework.context.annotation.Configuration;@Slf4j@ConfigurationpublicclassObserverConfiguration{@BeanpublicCommandLineRunnercommandLineRunner(ApplicationContextcontext){return(args)->{log.info("发布事件:什么是观察者模式?");context.publishEvent(newJavaStackEvent("什么是观察者模式?"));};}@BeanpublicReaderListenerreaderListener1(){returnnewReaderListener("小明");}@BeanpublicReaderListenerreaderListener2(){returnnewReaderListener("小张");}@BeanpublicReaderListenerreaderListener3(){returnnewReaderListener(“小明的爱”);}}Spring配置中创建三个readerbean,SpringBoot启动后发布观察者模式事件,然后通知三个bean。Output:这里可能不适合为每个reader创建一个Bean,因为需要模仿观察者模式的应用。观察者模式的实际应用要参考具体的业务。比如在电商支付场景中,可以在用户支付后发布一个支付事件,然后会有扣分、短信通知、赠券等一系列后续动作。事件监听观察者,可以实现业务解耦,是一个非常典型的应用场景。如果使用消息中间件,其实就是观察者模式下发布订阅模式的概念。总结使用Spring中的事件监听机制也可以很方便的实现观察者模式,观察目标不需要维护观察者列表,相当于发布订阅模式。它们是完全解耦的,但是每个观察者都需要创建一个bean。好了,今天的分享就到这里,我们来学习设计模式的另一种写法,后面会更新其他设计模式的实战文章,第一时间推送公众号Java技术栈。本教程所有实际源码已上传至本仓库:https://github.com/javastacks/spring-boot-best-practice