前言:在講述內容之前 希望大家對設計模式有所瞭解 即使你學會了本片的內容 也不知道什麼時候去使用 或者為什麼要這樣去用
觀察者模式:
觀察者模式是一種物件行為模式。它定義物件間的一種一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新。在觀察者模式中,主體是通知的釋出者,它發出通知時並不需要知道誰是它的觀察者,可以有任意數目的觀察者訂閱並接收通知。觀察者模式不僅被廣泛應用於軟體介面元素之間的互動,在業務物件之間的互動、許可權管理等方面也有廣泛的應用
觀察者模式(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";
}
}