一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - java和Spring中觀察者模式的應用詳解

java和Spring中觀察者模式的應用詳解

2022-02-20 11:41商俊帥 Java教程

這篇文章主要介紹了java和Spring中觀察者模式的應用,,具有一定的參考價值,感興趣的可以了解一下,希望能夠給你帶來幫助

一、觀察者模式基本概況

1.概念

觀察者模式(Observer Design Pattern)也被稱為發布訂閱模式(Publish-Subcribe Design Pattern)。定義如下

Define a one-to-many dependency between objects so that when one object changes state,all its dependents are notified and update automatically。

觀察者模式定義了一種一對多的依賴關系,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態變化時,會通知所有觀察者對象,使它們能夠自動更新自己。

2.作用

參考設計模式之美的一段總結

回到本質,設計模式要干的事情就是解耦。創建型模式是將創建對象和使用對象解耦,結構型模式是將不同功能代碼解耦,行為型模式是將不同的行為代碼解耦,具體到觀察者模式,是將觀察者和被觀察者代碼解耦。

3.實現方式

觀察者模式在不同的場景有不同的實現方式,自然也有不同的名字。如Publisher-Subscriber、Producer-Consumer、Dispatcher-Listener,等等。

有哪些不同實現方式呢?同步阻塞方式,異步非阻塞方式;進程內實現方式,跨進程實現方式。

同步阻塞方式是經典的實現方式,是說在主題通知觀察者和觀察者執行自己的邏輯是由同一個線程完成的,比如下面要說的java中Observer接口和Observable類,后有UML圖

public void notifyObservers(Object arg) {
  for (int i = arrLocal.length-1; i>=0; i--){
  	//使用了for循環同步通知觀察者
  	((Observer)arrLocal[i]).update(this, arg);
  } 
}

異步非阻塞方式是在通知觀察者和觀察者執行自己邏輯不是同一個線程,如下代碼

public void notifyObservers(Object arg) {
  for (int i = arrLocal.length-1; i>=0; i--){
  	//使用了開啟新線程方式異步通知觀察者
  	new Thread(()->{
  		((Observer)arrLocal[i]).update(this, arg);
		}).start();
  } 
}

上面都是在同一個進程中,還有跨進程的實現方式就是常用的MQ,消息隊列

 

二、java實現兩種觀察者模式

1.Observer接口和Observable類

下面我們使用JDK提供的接口和類實現項目中使用觀察者模式

java和Spring中觀察者模式的應用詳解

先說下Observer接口和Observable類

Observable類,被觀察者。有三個組成部分,用Vector管理注冊的觀察者(Observer),并提供了增刪、統計方法。一旦狀態(changed)改變就通知(notifyObservers)觀察者。notifyObservers方法會調用觀察者(Observer)的update方法。

Observer接口就是一個觀察者的標準,實現該接口并重寫update方法就可以實現一個觀察者。

具體的源碼大家可以自己看下,比較簡單,在java.util包下。

實現一個需求

當自定義被觀察者data值=1時通知各個觀察者執行update方法,應該如何做?

UML圖已經畫出來了,剩下就是寫代碼了。

代碼如下

//自定義被觀察者
public class MyObservable extends Observable {
  private int data;
  public void setData(int data) {
      this.data = data;
  }
  public void notifyObserver(){
  	//當data等于1時通知觀察者
      if (data==1){
          this.setChanged();
          super.notifyObservers();
      }
  }
}
//自定義觀察者
public class MyObserver implements Observer {
  @Override
  public void update(Observable o, Object arg) {
      System.out.println("自定義觀察者執行了.....");
  }
}
//測試類
public class PubSubTest {
  public static void main(String[] args) {
      MyObservable observable = new MyObservable();
      observable.addObserver(new MyObserver());
      observable.setData(1);
      observable.notifyObserver();
  }
}

2.EventObject和EventListener

JDK提供了EventObject類和EventListener接口定義了實現觀察者模式的第二個標準,只是定義了標準沒有提供默認實現,但是其他框架如Spring實現該方式,這個下面再說。

先看EventObject類

該類實現的功能就是定義一個事件,其中有一個最重要的屬性source,叫事件源。含義是哪個類發出的事件。自定義事件時需要繼承該類

public class EventObject implements java.io.Serializable {
  protected transient Object  source;
  public EventObject(Object source) {
      if (source == null)
          throw new IllegalArgumentException("null source");
      this.source = source;
  }
  public Object getSource() {
      return source;
  }
}

EventListener接口是一個空接口,自定義監聽器需要繼承該接口。

注意此時事件就是一個被觀察者,監視器就是觀察者。

 

三、Spring事件監聽實戰及原理

1.Spring如何使用EventObject和EventListener實現觀察者?

在Spring中為自定義事件和自定義監聽者,分別提供一個類和一個接口。

ApplicationEvent類繼承了EventObject,用于在Spring環境下自定義事件

public abstract class ApplicationEvent extends EventObject {
	/**
	 * 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 ApplicationEvent(Object source) {
		super(source);
		this.timestamp = System.currentTimeMillis();
	}
}

ApplicationListener接口繼承JDK的EventListener,用于在Spring環境下自定義監聽者

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
	/**
	 * Handle an application event.
	 * @param event the event to respond to
	 */
	void onApplicationEvent(E event);
}

onApplicationEvent方法就是根據傳過來的事件參數,監聽是否是自己感興趣的事件,然后執行方法體。

介紹完類和接口剩下的就是如何在Spring中如何自定義事件、如何發布事件、如何使用自定義監聽器監聽事件,下面舉個例子

2.先實戰―要先會用

實現一個需求:當調用一個類的方法完成時,該類發布事件,事件監聽器監聽該類的事件并執行的自己的方法邏輯

假設這個類是Request、發布的事件是ReuqestEvent、事件監聽者是ReuqestListener。當調用Request的doRequest方法時,發布事件。模擬的代碼如下

public class SpringEventTest {
  public static void main(String[] args) {
      ApplicationContext context=new AnnotationConfigApplicationContext("com.thinkcoder.parttern.behavioral.pubsub.spring");
      Request request = (Request) context.getBean("request");
      //調用方法,發布事件
      request.doRequest();
  }
}
//定義事件
class RequestEvent extends ApplicationEvent {
  public RequestEvent(Request source) {
      super(source);
  }
}
//發布事件
@Component
class Request{
  @Autowired
  private ApplicationContext applicationContext;
  public void doRequest(){
      System.out.println("調用Request類的doRequest方法發送一個請求");
      applicationContext.publishEvent(new RequestEvent(this));
  }
}
//監聽事件
@Component
class RequestListener implements ApplicationListener<RequestEvent> {
  @Override
  public void onApplicationEvent(RequestEvent event) {
      System.out.println("監聽到RequestEvent事件,執行方法");
  }
}
//打印的日志
調用Request類的doRequest方法發送一個請求
監聽到RequestEvent事件,執行方法

上面我們依靠spring實現了事件―監聽機制,使用的步驟有如下幾步

  • 定義事件:繼承ApplicationEvent類,實現方法傳入事件源。由事件源產生事件
  • 發布事件:使用Spring的IOC容器ApplicationContext的publishEvent方法發布事件
  • 監聽事件:實現ApplictionListener接口重寫方法即可實現自定義監聽器

3.會原理―搞清楚為什么會這樣

先將上述過程畫成一幅圖,然后展開來解釋各個步驟,相信我你能看懂

java和Spring中觀察者模式的應用詳解

通過上面的流程圖,回答下面幾個問題

1.監聽器什么時候注冊到IOC容器中?

注冊的開始邏輯是在AbstractApplicationContext類的refresh方法,該方法包含了整個IOC容器初始化所有方法。其中有一個registerListeners()方法就是注冊系統監聽者(spring自帶的)和自定義監聽器的。

看registerListeners的關鍵方法體,其中的兩個方法addApplicationListener和addApplicationListenerBean,從方法可以看出是添加監聽者。

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!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
	getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}

那么最后將監聽者放到哪里了呢?就是ApplicationEventMulticaster接口的子類

java和Spring中觀察者模式的應用詳解

該接口主要兩個職責,維護ApplicationListener相關類和發布事件。

實現是在默認實現類AbstractApplicationEventMulticaster,最后將Listener放到了內部類ListenerRetriever兩個set集合中

private class ListenerRetriever {
	public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
	public final Set<String> applicationListenerBeans = new LinkedHashSet<>();

ListenerRetriever又被稱為監聽器注冊表。

2.Spring如何發布的事件并通知的監聽者?

該問題開始是在ApplicationContext.publishEvent的方法,該方法調用路線

AbstractApplicationContext.publishEvent→SimpleApplicaitonEventMulticaster.multicastEvent→SimpleApplicaitonEventMulticaster.invokeListener→SimpleApplicaitonEventMulticaster.doInvokeListener→調用系統及自定義listener的onApplicationEvent方法,這個就是發布事件并通知的調用路線。

這個注意的有兩個方法

multicastEvent方法,該方法有兩種方式調用invokeListener,通過線程池和直接調用,進一步說就是通過異步和同步兩種方式調用

public 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);
		}
	}
}

最后看doInvokeListener方法

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
	try {
		//直接調用了listener接口的onApplicationEvent方法
		listener.onApplicationEvent(event);
	}
}

 

四、最后一張圖總結

java和Spring中觀察者模式的應用詳解

上圖包含了在Spring如何自定義事件、監聽器以及發布事件和通知監聽者的原理,大家可以自己梳理下。

原文鏈接:https://blog.csdn.net/shang_0122/article/details/120679734

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 皇上好大好硬好涨好深好爽 | mmkk在线看片 | 高贵女王调奴vk | 99热资源| 99国产精品免费视频 | vomoulei成人舞蹈 | ts视频在线观看 | 日本道色综合久久影院 | 高h短篇合集| 公妇乱淫在线播放免费观看 | 無码一区中文字幕少妇熟女网站 | 俄罗斯女人与公拘i交酡 | 热99这里只有精品 | 男男gaygays黑人| 色综合视频在线观看 | 粗又长好猛好爽视频 | 免费国产白棉袜踩踏区域 | 日本黄a三级三级三级 | 搞逼综合网 | 国产国语videosex另类 | 成年人在线免费看 | 亚洲国产成人精品无码区5566 | 天天综合色天天综合色sb | 国产精品嫩草影院一二三区入口 | s8sp加密路线和免费路线首页 | 日日爽日日操 | 精品一区二区三区高清免费不卡 | 99久久综合九九亚洲 | 亚洲精品福利在线 | 日韩一| 欧美坐爱 | 52av我爱avhaose01好| 出轨娇妻的呻吟1—9 | 精品久久久噜噜噜久久7 | 国产91精品在线播放 | 涩涩成人 | 亚洲精品AV无码永久无码 | 欧美在线国产 | yin娃sao货调教情趣用品店 | 半挠脚心半黄的网站 | yellow片在线观看 |