前言:在講述內容之前 希望大家對設計模式有所了解 即使你學會了本片的內容 也不知道什么時候去使用 或者為什么要這樣去用
觀察者模式:
觀察者模式是一種對象行為模式。它定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。在觀察者模式中,主體是通知的發布者,它發出通知時並不需要知道誰是它的觀察者,可以有任意數目的觀察者訂閱並接收通知。觀察者模式不僅被廣泛應用於軟件界面元素之間的交互,在業務對象之間的交互、權限管理等方面也有廣泛的應用
觀察者模式(Observer)完美的將觀察者和被觀察的對象分離開。舉個例子,用戶界面可以作為一個觀察者,業務數據是被觀察者,用戶界面觀察業務數據的變化,發現數據變化后,就顯示在界面上。面向對象設計的一個原則是:系統中的每個類將重點放在某一個功能上,而不是其他方面。一個對象只做一件事情,並且將他做好。觀察者模式在模塊之間划定了清晰的界限,提高了應用程序的可維護性和重用性。
觀察者設計模式定義了對象間的一種一對多的組合關系,以便一個對象的狀態發生變化時,所有依賴於它的對象都得到通知並自動刷新。(以上源於百度)
已經熟悉設計模式的可以直接向下閱讀 對不熟悉的 希望通過上述內容 你們可以有一定的了解 通俗點說 觀察者模式 是設計框架的一種
當然我們的Spring Boot當然也不會放過這么好的設計模式 那么Spring Boot中又有哪些地方使用到了
1.ApplicationStartingEvent
當應用啟動還沒有進行任何處理時,在對所有的監聽器做初始化的時候發送的事件
public ConfigurableApplicationContext run(String... args) {
//記錄服務啟動事件
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
//開啟awt的headless模式
//Headless模式是系統的一種配置模式。在系統可能缺少顯示設備、鍵盤或鼠標這些外設的情況下可以使用該模式
this.configureHeadlessProperty();
//獲取監聽器列表
SpringApplicationRunListeners listeners = this.getRunListeners(args);
啟動所有監聽器
listeners.starting();
.................
}
此時監聽列表中只有一個監聽事件為EventPublishingRunListener

它的作用就是通知Spring Boot項目開始啟動

2.ApplicationEnvironmentPreparedEvent
當已獲取的了所有Spring Context上下文信息 但是此時還沒有進行創建
此時Spring Boot開始啟動 EventPublishingRunListener會發送ApplicationEnvironmentPreparedEvent事件 告訴Spring Boot應用環境已經准備就緒 准備做后續處理 監聽此事件的監聽器是ConfigFileApplicationListener
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
//獲取環境 資源 加載器
List<EnvironmentPostProcessor> postProcessors = this.loadPostProcessors();
postProcessors.add(this);
//對Order的大小進行排序 裝載
AnnotationAwareOrderComparator.sort(postProcessors);
//使用迭代器 根據順序開始執行 環境 資源 的配置
Iterator var3 = postProcessors.iterator();
while(var3.hasNext()) {
EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var3.next();
postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
}
}
3.ApplicationContextInitializedEvent
測試Spring Context上下文已經初始化完畢 但是此時上下文是的空的
開始向Spring上下文裝填內容
public void contextPrepared(ConfigurableApplicationContext context) {
//獲取當前所有有關的上下文的監聽器
Iterator var2 = this.listeners.iterator();
while(var2.hasNext()) {
SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();
//通知
listener.contextPrepared(context);
}
}
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
//向上下文中裝填配置參數
//context.setEnvironment(environment);
//向應用中裝填上下文
this.postProcessApplicationContext(context);
//進行初始化參數裝填
this.applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
this.logStartupInfo(context.getParent() == null);
this.logStartupProfileInfo(context);
}
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
Set<Object> sources = this.getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
this.load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
4.ApplicationPreparedEvent
應用加載完畢
public void contextLoaded(ConfigurableApplicationContext context) {
ApplicationListener listener;
//相容器中裝填已經初始化的上下文對象
for(Iterator var2 = this.application.getListeners().iterator(); var2.hasNext(); context.addApplicationListener(listener)) {
listener = (ApplicationListener)var2.next();
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware)listener).setApplicationContext(context);
}
}
//通知
this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
5.ApplicationStartedEvent
應用初始化完成
public void started(ConfigurableApplicationContext context) {
//通知
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
6.ApplicationReadyEvent
應用加載完畢
public void running(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
}
這就是Spring在啟動的時候 發生的事件交互 最直觀的我們可以看出 當一個具體的功能實現完畢之后 創建事件 去通知下一個階段去做相對的事情 這樣子比在一個方法里面 去直接調用好得多 並且可以支持廣播模式(一對多)
當然在Spring Boot中使用觀察者模式 也非常簡單 首先我們創建一個名為旅游的事件
@Data
public class TravelEvent {
private String money;
private String location;
private String sex;
}
當我們需要去旅行時 需要帶錢 帶男/女朋友 去什么地方游玩
注冊一個監聽類用來監聽我們發出的事件
1.監聽類的實例必須由Spring容器管理 切必須有實例 否則無法監聽到事件的發生
2.在方法上使用@EventListener(事件類)注解 可以將事件實例當做入參 進行業務處理
3.使用ApplicationEventPublisher發送事件 進行測試
@Component
public class TravelEventListener {
@EventListener(TravelEvent.class)
public void location(TravelEvent travelEvent){
System.out.println("地方:"+travelEvent.getLocation());
}
@EventListener(TravelEvent.class)
public void sex(TravelEvent travelEvent){
System.out.println("朋友:"+travelEvent.getSex());
}
@EventListener(TravelEvent.class)
public void money(TravelEvent travelEvent){
System.out.println("錢:"+travelEvent.getMoney());
}
}
@RestController
@RequestMapping("/event")
public class EventController {
@Autowired
ApplicationEventPublisher applicationEventPublisher;
@PostMapping("/travel")
public String goTravel(@RequestBody TravelEvent travelEvent){
applicationEventPublisher.publishEvent(travelEvent);
return "ok";
}
}

