版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接: https://blog.csdn.net/weixin_43212912/article/details/102665437
            </div><!--一个博主专栏付费入口--><!--一个博主专栏付费入口结束--><link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-4a3473df85.css"><div id="content_views" class="markdown_views prism-atom-one-dark"><!-- flowchart 箭头图标 勿删 --><svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path></svg><p></p><div class="toc"><h3><a name="t0"></a>设计模式篇-观察者模式(发布-订阅模式)</h3><ul><li><a href="#_2" rel="nofollow" target="_self">目录</a></li><ul><li><a href="#_3" rel="nofollow" target="_self">定义</a></li><li><a href="#java_6" rel="nofollow" target="_self">java内置观察者模式实现</a></li><li><a href="#java_111" rel="nofollow" target="_self">java内置观察者模式的缺点</a></li><li><a href="#_117" rel="nofollow" target="_self">自己实现观察者模式</a></li><li><a href="#spring_209" rel="nofollow" target="_self">spring是如何使用观察者模式的</a></li><ul><li><a href="#_213" rel="nofollow" target="_self">事件机制主要成员:</a></li><li><a href="#spring_228" rel="nofollow" target="_self">使用spring事件机制实现天气发布例子</a></li><li><a href="#spring_329" rel="nofollow" target="_self">解析spring事件机制的具体实现</a></li></ul></ul></ul></div><p></p>

目录

定义

观察者模式(Observer):定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
  • 1

上面是官方给出的观察者模式的定义,从我个人角度来讲,我觉得就把它称之为发布-订阅模式更为贴切。虽然看起来这个设计模式没什么难度,但是想把它真正应用到日常的代码开发中,还是得下一番功夫。本文首先会使用一个简单的例子来引导大家,让大家明白什么是观察者模式,然后再给大家讲解一下spring框架是如何使用这个观察者模式的(由于本人对于java语言更为熟悉,所以接下来的讲解全部使用的语言都是java)。

java内置观察者模式实现

我们可以自己实现观察者模式,也可以使用java语言本身内置的观察者模式,通过java.util包中的Observer接口(观察者)与Observable类(被观察者)实现。接下来将使用java内置的观察者模式实现一个天气预报发布和订阅的小例子。

接下来我们实现上图天气预告的发布订阅。

  1. 定义一个天气预告发布者,需要继承Observable类;当发布天气预告信息时,所有的订阅者都会受到天气信息。
package observation;

import java.util.Observable;

/**

  • 天气预告发布者 发布天气信息给订阅者
    */
    public class WeatherPublisher extends Observable {

    //天气信息
    private String weatherInfo;

    //订阅者使用该方法主动获取天气信息
    public String getWeatherInfo() {
    return weatherInfo;
    }

    public void setWeatherInfo(String weatherInfo) {
    this.weatherInfo = weatherInfo;
    //在通知订阅者前必须调用该方法指示状态的改变
    //为什么要调用该方法,我们且看后面的讲解
    this.setChanged();
    //采用“拉”的方式,订阅者主动拉取天气的变化信息
    this.notifyObservers();
    //与上面的相面,采用“推”的方式,将天气信息推送给订阅者
    // this.notifyObservers(weatherInfo);
    }

    public static void main(String[] args) {
    //定义一个天气预告发布者
    WeatherPublisher weatherPublisher = new WeatherPublisher();

     <span class="token comment">//添加小王和小李为天气预告订阅者</span>weatherPublisher<span class="token punctuation">.</span><span class="token function">addObserver</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">XiaoLiSubscriber</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>weatherPublisher<span class="token punctuation">.</span><span class="token function">addObserver</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">XiaoWangSubscriber</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//发布天气信息</span>weatherPublisher<span class="token punctuation">.</span><span class="token function">setWeatherInfo</span><span class="token punctuation">(</span><span class="token string">"今天天气很晴朗,阳光明媚,适合出游"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>weatherPublisher<span class="token punctuation">.</span><span class="token function">setWeatherInfo</span><span class="token punctuation">(</span><span class="token string">"明天是阴天,记得出门带伞哦"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    

    }
    }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  1. 定义天气预告订阅者小王和小李,需要实现Observer接口;
    天气订阅者小王:
package observation;

import java.util.Observable;
import java.util.Observer;

/**

  • 天气订阅者小王
    */
    public class XiaoWangSubscriber implements Observer {

    //第二个参数即是使用“推”方式推送过来的天气信息,这里使用“拉”方式主动获取
    public void update(Observable o, Object arg) {
    if (o instanceof WeatherPublisher) {
    WeatherPublisher publisher = (WeatherPublisher) o;
    System.out.println(“小王主动获取天气信息:” + publisher.getWeatherInfo());
    }
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

天气订阅者小李:

package observation;

import java.util.Observable;
import java.util.Observer;

/**

  • 天气订阅者小李
    */
    public class XiaoLiSubscriber implements Observer {

    public void update(Observable o, Object arg) {
    if (o instanceof WeatherPublisher) {
    WeatherPublisher publisher = (WeatherPublisher) o;
    System.out.println(“小李主动获取天气信息:” + publisher.getWeatherInfo());
    }
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

运行结果如下:

小王主动获取天气信息:今天天气很晴朗,阳光明媚,适合出游
小李主动获取天气信息:今天天气很晴朗,阳光明媚,适合出游
小王主动获取天气信息:明天是阴天,记得出门带伞哦
小李主动获取天气信息:明天是阴天,记得出门带伞哦
  • 1
  • 2
  • 3
  • 4

其实上面的例子是很简单的,打开Observable类的源码仔细阅读就能明白。这里我们贴一下Observable类的伪代码:

从这里能看出来,为什么我们在通知前必须要调用setChange()这个方法,只有change表只为true时才能通知观察者。

java内置观察者模式的缺点

  1. java.util.Observable的黑暗面
    Observable是一个类,而不是一个接口,这点就很尴尬了,java的类只能继承一个类,无法继承多个类,也就无法同时具有该类和其它超类的行为。这点违反了面向对象编程的原则(针对接口编程,不针对实现编程)。而且Observable类也并未实现其它任何接口,所以你无法建立自己的实现,和Java内置的Observer API搭配使用。如果它无法满足你的需求,也可以自己实现一套观察者模式。
  2. 观察者数量很多耗费时间
    当被观察者状态发生变化会通知所有观察者,如果直接和间接观察者的数量很多,将会耗费很多时间。

自己实现观察者模式

上面说到jdk内置的观察者模式的一些缺点,当它无法满足使用者的需求时,我们可以自己实现一套。实现的方式并不困难,我们仍然使用上面天气预告的例子。实现的方式其实和jdk内置的观察者模式差不多,但是根据业务的不同,会有细节上的差别。

  1. 天气发布者接口
    这里和Observable类就有所不同,我们使用接口而不是类。可以根据不同的业务需求创建发布者。
public interface Subject {//注册观察者public void registerObserver(Observer observer);//删除观察者public void removeObserver(Observer observer);//通知所有观察者public void notifyObservers();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
public class WeatherSubject implements Subject {
<span class="token keyword">private</span> List<span class="token generics function"><span class="token punctuation">&lt;</span>Observer<span class="token punctuation">&gt;</span></span> observers<span class="token punctuation">;</span>
<span class="token keyword">private</span> String weatherInfo<span class="token punctuation">;</span><span class="token keyword">public</span> <span class="token function">WeatherSubject</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>observers <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics function"><span class="token punctuation">&lt;</span>Observer<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">registerObserver</span><span class="token punctuation">(</span>Observer observer<span class="token punctuation">)</span> <span class="token punctuation">{</span>observers<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>observer<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">removeObserver</span><span class="token punctuation">(</span>Observer observer<span class="token punctuation">)</span> <span class="token punctuation">{</span>observers<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>observer<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">notifyObservers</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">for</span> <span class="token punctuation">(</span>Observer observer <span class="token operator">:</span> observers<span class="token punctuation">)</span> <span class="token punctuation">{</span>observer<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span>weatherInfo<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token keyword">public</span> String <span class="token function">getWeatherInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">return</span> weatherInfo<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setWeatherInfo</span><span class="token punctuation">(</span>String weatherInfo<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>weatherInfo <span class="token operator">=</span> weatherInfo<span class="token punctuation">;</span><span class="token function">notifyObservers</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>WeatherSubject weatherSubject <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">WeatherSubject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>weatherSubject<span class="token punctuation">.</span><span class="token function">registerObserver</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">XiaoWangObserver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>weatherSubject<span class="token punctuation">.</span><span class="token function">registerObserver</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">XiaoLiObserver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>weatherSubject<span class="token punctuation">.</span><span class="token function">setWeatherInfo</span><span class="token punctuation">(</span><span class="token string">"今天天气很晴朗,阳光明媚,适合出游"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>weatherSubject<span class="token punctuation">.</span><span class="token function">setWeatherInfo</span><span class="token punctuation">(</span><span class="token string">"明天是阴天,记得出门带伞哦"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  1. 天气预告订阅者
public interface Observer {public void update(String wetherInfo);
}
  • 1
  • 2
  • 3
public class XiaoLiObserver implements Observer {public void update(String wetherInfo) {System.out.println("小李收到天气信息:" + wetherInfo);}
}
  • 1
  • 2
  • 3
  • 4
  • 5
public class XiaoWangObserver implements Observer {public void update(String wetherInfo) {System.out.println("小王收到天气信息:" + wetherInfo);}
}
  • 1
  • 2
  • 3
  • 4
  • 5

运行结果如下:

小王收到天气信息:今天天气很晴朗,阳光明媚,适合出游
小李收到天气信息:今天天气很晴朗,阳光明媚,适合出游
小王收到天气信息:明天是阴天,记得出门带伞哦
小李收到天气信息:明天是阴天,记得出门带伞哦
  • 1
  • 2
  • 3
  • 4

看完这些,相信大家一定对观察者模式有一定的了解。下面我们就来看一看sping框架中是怎么使用观察者模式的。

spring是如何使用观察者模式的

spring框架,学过java的同学一定对它不陌生,spring对于设计模式的应用十分值得我们学习,下面我们就来看一看它是如何使用观察者模式的。

spring中事件机制的底层原理就是观察者模式。java其实也有自己的事件机制,spring的事件机制也是由java的事件机制拓展而来。spring提供的事件机制是通过ApplicationEvent类和ApplicationListener接口实现的。我们仍然使用上面的天气信息发布的例子来讲解spring的观察者模式。

事件机制主要成员:

  1. 事件

    上图是spring提供的几类标准事件的类图,EventObject是jdk提供的事件,sping中的所有事件都要继承ApplicationEvent。事件比较好理解了,就是触发源,触发某个动作执行的源头。
    ContextStartedEvent:当应用上下文启动时发布;
    ContextClosedEvent:当应用上下文关闭时发布,“关闭”指所有的单实例bean都被销毁,不可以重启或者刷新;
    ContextStopedContext:当应用上下文停止时发布,“停止”指所有生命周期的bean都将接收到明确的停止信号,可以被重启;
    ContextRefreshEvent:当应用上下文初始化或者刷新时发布
    由上面的类图我们可以看出,spring支持两种事件,ApplicationContextEvent和PayloadApplicationEvent,至于这两种事件有什么区别,我们后面在讲解源码时再细细道来。
  2. 事件监听器(监听事件的触发,对其做出响应)
    spring中的事件监听器都必须实现ApplicationListen接口,它只定义了一个方法onApplicationEvent(E event),该方法接收ApplicationEvent事件对象,并实现响应事件的处理逻辑。关于SmartApplicationListener和GenericApplicationListener这里不做详细介绍。
    监听器也可以使用注解的方式实现@EventListener,因为这里主要是要讲原理,便不做介绍了。
  3. 事件广播器(负责将事件通知给监听器)

    当容器发布事件时,事件广播器会将事件通知给事件监听器注册表中的各个事件监听器。我们可以自定义广播器,如果没有自定义,spring则会使用默认的SimpleApplicationEventMulticaster广播器。接下来我们便使用spring的事件机制实现天气发布这个小例子,并讲解一下spring事件机制实现的方式。

使用spring事件机制实现天气发布例子

1、首先我们需要实现一个事件,发布事件,必须要有事件才行,这里定义是天气事件

/*** 天气事件,包含待发布的天气信息*/
public class WeatherEvent extends ApplicationContextEvent {
<span class="token keyword">private</span> String weatherInfo<span class="token punctuation">;</span><span class="token keyword">public</span> <span class="token function">WeatherEvent</span><span class="token punctuation">(</span>ApplicationContext source<span class="token punctuation">,</span> String weatherInfo<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">super</span><span class="token punctuation">(</span>source<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">this</span><span class="token punctuation">.</span>weatherInfo <span class="token operator">=</span> weatherInfo<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token keyword">public</span> String <span class="token function">getWeatherInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">return</span> weatherInfo<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

2、接下实现监听器,即天气监听者,我们实现3个监听者,我们仔细看一下有什么不同。
监听者1:

public class WeatherListen1 implements ApplicationListener<WeatherEvent> {
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onApplicationEvent</span><span class="token punctuation">(</span>WeatherEvent event<span class="token punctuation">)</span> <span class="token punctuation">{</span>System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"天气监听者1:"</span> <span class="token operator">+</span> event<span class="token punctuation">.</span><span class="token function">getWeatherInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

监听者2:

public class WeatherListen2 implements ApplicationListener<WeatherEvent> {
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onApplicationEvent</span><span class="token punctuation">(</span>WeatherEvent event<span class="token punctuation">)</span> <span class="token punctuation">{</span>System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"天气监听者2:"</span> <span class="token operator">+</span> event<span class="token punctuation">.</span><span class="token function">getWeatherInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

监听者3:

public class OtherListen3 implements ApplicationListener<PayloadApplicationEvent> {
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onApplicationEvent</span><span class="token punctuation">(</span>PayloadApplicationEvent event<span class="token punctuation">)</span> <span class="token punctuation">{</span>System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"其它天气监听者3:"</span> <span class="token operator">+</span> event<span class="token punctuation">.</span><span class="token function">getPayload</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

监听者1与监听者2监听ApplicationContextEvent事件,监听者3监听的是PayloadApplicatinEvent事件。这里我们看一下这两个事件的区别在哪。首先看一下AbstractApplicationContext这个抽象类的源码,当中有一个publishEvent方法,所有的事件都是在这里被发布的。我们所熟知的ClassPathXmlApplicationContext与FileSystemXmlApplicationContext类都是继承这个类,最终都是调用这个类的publishEvent方法发布事件的。
图中红色框框中可知,除了ApplicationEvent外的事件都被包装成PayloadApplicatinEvent事件。
PayloadApplicatinEvent类的构造函数有两个参数,第二个参数就是我们发布出去的事件。我们可以通过getPayload()获取发布的事件。
如果我们代码里有一个事件想发布,却又没有继承ApplicationEvent,为了不影响现有的功能,这时发布的事件就可以以PayloadApplicatinEvent的形式发布。
3、还有天气的发布者

/*** 这里也可以使用ApplicationEventPublisher,ApplicationContext接口继承了它,* 通过实现ApplicationContextAware获取应用上下文对象,并调用publishEvent方法发布事件*/
public class WeatherPublisher implements ApplicationContextAware {
<span class="token keyword">private</span> ApplicationContext applicationContext<span class="token punctuation">;</span><span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setApplicationContext</span><span class="token punctuation">(</span>ApplicationContext applicationContext<span class="token punctuation">)</span> <span class="token keyword">throws</span> BeansException <span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>applicationContext <span class="token operator">=</span> applicationContext<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">publishEvent</span><span class="token punctuation">(</span>String weatherInfo<span class="token punctuation">)</span> <span class="token punctuation">{</span>WeatherEvent weatherEvent <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">WeatherEvent</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>applicationContext<span class="token punctuation">,</span> weatherInfo<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//发布ApplicationContextEvent事件</span><span class="token keyword">this</span><span class="token punctuation">.</span>applicationContext<span class="token punctuation">.</span><span class="token function">publishEvent</span><span class="token punctuation">(</span>weatherEvent<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//发布PayloadApplicationEvent事件</span><span class="token keyword">this</span><span class="token punctuation">.</span>applicationContext<span class="token punctuation">.</span><span class="token function">publishEvent</span><span class="token punctuation">(</span><span class="token string">"今天天阴,请注意保暖!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>ApplicationContext applicationContext <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ClassPathXmlApplicationContext</span><span class="token punctuation">(</span><span class="token string">"bean.xml"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>WeatherPublisher weatherPublisher <span class="token operator">=</span> <span class="token punctuation">(</span>WeatherPublisher<span class="token punctuation">)</span> applicationContext<span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span><span class="token string">"weatherPublisher"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>weatherPublisher<span class="token punctuation">.</span><span class="token function">publishEvent</span><span class="token punctuation">(</span><span class="token string">"今天天气阳光明媚!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

运行结果:

天气监听者1:今天天气阳光明媚!
天气监听者2:今天天气阳光明媚!
其它天气监听者3:今天天阴,请注意保暖!
  • 1
  • 2
  • 3

事件的发布使用的是ApplicationContext,这个例子中的应用上下文是ClassPathXmlApplicationContext,讲到这里大家可能不太明白为什么使用应用上下文来发布事件,这个就需要我们来看看spring容器的源码了。究竟spring是如何形成这么一套完整的事件机制的。

解析spring事件机制的具体实现

spring在AbstractApplicationContext这个抽象类中实现了事件体系的搭建。AbstractApplicationContext的refresh()方法完成了spring容器的启动。事件机制的实现也是在这个过程中完成的。

这里我们只看事件机制的实现过程,其他部分(beanFactory等)会在别的文章中详细介绍。关于事件机制的主要就是以上三个函数了。
1、首先,初始化应用上下文广播器,我们可以自定义事件广播器,只要实现ApplicationEventMulticaster这个接口即可。如果没有实现自己的广播器,spring便会使用默认的SimpleApplicationEventMulticaster作为事件广播器。
说了这么多,究竟什么是事件广播器呢?
事件广播器的作用是把Applicationcontext发布的Event广播给所有的在spring中注册的监听器。事件其实是通过事件广播器发布给监者的。
2、注册事件监听器
所有的事件监听器由spring管理,进入registerListeners()函数我们可以发现,监听器的管理者也是事件广播器。关于事件监听器我们不再详述。
3、完成容器初始化并广播ContextRefreshedEvent事件
finishRefresh()函数不再详细展开。

本文源码:码云地址

到这里关于观察者模式的介绍就结束了,第一次写博客,有很多不足的地方请见谅,不正确的地方还请及时指出,本文的源码会放在github上,大家可以下载观看,谢谢!
  • 1
                                </div><link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-b6c3c6d139.css" rel="stylesheet"></div>

设计模式篇-观察者模式相关推荐

  1. 设计模式:观察者模式--Observer

    一.什么是观察者模式 1.生活中的观察者模式 1.警察抓小偷 在现实生活中,警察抓小偷是一个典型的观察者模式「这以一个惯犯在街道逛街然后被抓为例子」,这里小偷就是被观察者,各个干警就是观察者,干警时时 ...

  2. 游戏服务器架构-设计模式之观察者模式和发布订阅模式真的一样吗?

    前面我给大家分享了观察者模式和发布订阅模式,有人私信给我说这俩不是一样嘛,大体没什么区别,我猜测大多数认为这两者是一样的可以继续阅读这两篇文章,如果还不能解答你的问题,我相信这篇文章对比两者的关系会让 ...

  3. 程序员内功-设计模式篇

    一. 什么是设计模式 纠结了好久,今天终于下定决心开始写设计模式系列,因为这个系列章节确实不好写,在这之前,也看了好多关于设计模式的博客.视频.书籍等,最后结合自己的理解,亲自动手实操代码,完成该章节 ...

  4. Android设计模式之观察者模式在项目中的实际使用总结

    前言 观察者模式在Android开发中使用频率非常高,最常用的地方如订阅–发布系统,类似微信公众号用户订阅和接收消息的场景,因为这个模式最重要的功能就是解耦,将被观察者和观察者解耦,使得它们之间的依赖 ...

  5. Java多线程编程实战指南+设计模式篇pdf

    下载地址:网盘下载 随着CPU 多核时代的到来,多线程编程在充分利用计算资源.提高软件服务质量方面扮演了越来越重要的角色.而 解决多线程编程中频繁出现的普遍问题可以借鉴设计模式所提供的现成解决方案.然 ...

  6. java多线程编程_Java多线程编程实战指南+设计模式篇.pdf

    Java多线程编程实战指南+设计模式篇.pdf 对Java架构技术感兴趣的工程师朋友们可以关注我,转发此文后私信我"Java"获取更多Java编程PDF资料(附送视频精讲) 关注我 ...

  7. java 观察者模式_图解Java设计模式之观察者模式

    图解Java设计模式之观察者模式 天气预报项目需求 天气预报设计方案 1 - 普通方案 观察者模式(Observer)原理 观察者模式解决天气预报需求 观察者模式在JDK应用的源码分析 天气预报项目需 ...

  8. java设计模式观察者模式吗_Java设计模式之观察者模式原理与用法详解

    Java设计模式之观察者模式原理与用法详解 本文实例讲述了Java设计模式之观察者模式原理与用法.分享给大家供大家参考,具体如下: 什么是观察者模式 可以这么理解: 观察者模式定义了一种一对多的依赖关 ...

  9. 设计模式 C++观察者模式

    无论是在现实世界中还是在软件系统中,人们常常会遇到这样一类问题,一个对象的状态改变会引发其他对象的状态改变,如十字路口的交通信号灯,红灯亮则汽车停,绿灯亮则汽车行,再如点击软件中一个按钮,则会弹出一个 ...

最新文章

  1. Vivado中IP核生成文件
  2. #if 和#ifdef的区别
  3. What Are You Talking About
  4. Windows 配置Apache+CGI
  5. 西安电话面试:谈谈Vue数据双向绑定原理,看看你的回答能打几分
  6. 修过的一个android framework原生系统代码bug
  7. 华为起诉美国政府新进展;小米空调对董明珠“没有压力”;扎克伯格:后悔没早点学微信 | 极客头条...
  8. vue set方法_Vue 数据响应式
  9. bootstrap栅格系统中同行div高度不一致的解决方法
  10. 世界国家中英文名称以及地区区号json格式
  11. JSONObject.fromObject爆红,显示无fromObject方法
  12. [FFMPEG播放器]结合FFMPEG使用SDL2渲染ASS字幕
  13. 第09章节-Python3.5-Django目录详解 8
  14. 不用电脑怎么设置路由器
  15. 2020杭电多校赛 Multi-University Training Contest
  16. CCNA 中文读书笔记四
  17. 【10】Ubuntu16虚拟机调整窗口大小自适应
  18. 20154312 曾林 Exp5_MSF基础应用
  19. iOS拍摄视频,自定义拍摄界面,高清压缩,添加水印
  20. 湘鄂情资源独具 大数据转型可期

热门文章

  1. 5G微基站与智慧灯杆的关系
  2. outlook连接yeahI邮箱注意事项
  3. 微软ChatGPT技术的底层支撑——GPU
  4. jQuery移除元素自动解绑事件实现
  5. PL/SQL 注释(Comment)
  6. 公办大学计算机系的女生少吗,高考:女生失业率“最低”的大学专业,考上家长很开心...
  7. 两个数之间的偶数(奇数)算法
  8. 端口检测工具FPORT
  9. Windows beanstalkd启动
  10. 微任务宏任务以及EventLoop详解