发布时间:2024-01-01 13:00
从这一专栏开始将学习设计模式,上课学习和自己总结归纳的笔记将总结出来供大家参考。
参考书籍:《设计模式就该这样学》
其他文章:
Java设计模式-UML类图 | Java设计模式-七大架构设计原则-开闭原则 |
---|---|
Java设计模式-七大架构设计原则-依赖倒置原则 | Java设计模式-七大架构设计原则-单一职责原则 |
Java设计模式-七大架构设计原则-接口隔离原则 | Java设计模式-七大架构设计原则-最少知道原则(迪米特法则) |
Java设计模式-七大架构设计原则-里氏替换原则和合成复用原则 | Java设计模式-创建型设计模式-简单工厂模式 |
Java设计模式-创建型设计模式-工厂方法模式(工厂模式) | Java设计模式-创建型设计模式-抽象工厂模式 |
Java设计模式-创建型设计模式-建造者模式 | Java设计模式-创建型设计模式-原型模式 |
Java设计模式-创建型设计模式-单例模式 | Java设计模式-结构型设计模式-适配器模式 |
Java设计模式-行为型设计模式-观察者模式 | |
在GOF23种设计模式中,有三种类型的设计模式,分别是:创建型设计模式、结构型设计模式、行为型设计模式。
在GoF23种设计模式中属于行为型设计模式:
Chain of Responsibility ( 责任链模式 )、Command ( 命令模式 )、Interpreter ( 解释器模式 ) 、Iterator ( 迭代器模式 )、Mediator ( 中介者模式 ) 、Memento ( 备忘录模式 ) 、Observer ( 观察者模式 )、State ( 状态模式 ) 、Strategy ( 策略模式 )、TemplateMethod ( 模板方法 )、Visitor ( 访问者模式 )11种模式。
观察者模式(Observer Pattern):又叫做发布-订阅模式(Publish/Subscribe pattern)、模型-视图(Model/View pattern)。定义一种一对多的依赖关系,一个主题对象可以被多个观察值对象同时监听,使得每当主题对象状态变化时,所有依赖它的对象都会得到通知并被自动更新。
在GoF23种设计模式中属于行为型设计模式:
其中包括:Chain of Responsibility ( 责任链模式 )、Command ( 命令模式 )、Interpreter ( 解释器模式 ) 、Iterator ( 迭代器模式 )、Mediator ( 中介者模式 ) 、Memento ( 备忘录模式 ) 、Observer ( 观察者模式 )、State ( 状态模式 ) 、Strategy ( 策略模式 )、TemplateMethod ( 模板方法 )、Visitor ( 访问者模式 )11种模式。
抽象主题(ISubject):指被观察的对象,一般是一个抽象类或者是接口,定义了增加、删除、通知观察者对象的方法。
具体主题(ConcreteSubject):具体被观察的对象,当其内部状态变化的时候,会通。已注册的观察者。
抽象观察者(IObserver):定义了响应通知的更新方法。
具体观察者(ConcreteObserver):当得到状态更新的通知时,会自动做出响应。
优点:
观察者和被观察者是松耦合的,符合依赖倒置原则(高层模块不应该依赖底层模块,二者都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象);
分离了观察者和被观察者,并且建立了一套触发机制,使得被观察者数据的变化可以响应到多个观察者上;
实现了一对多的通信机制,支持事件处理机制,支持兴趣分发机制,当被观察者触发事件时,只有感兴趣的观察者可以接收到通知。
缺点:
如果观察者的数量过多,则事件通知会耗费更多的时长;
事件通知呈线性关系,如果其中一个观察者处理事件卡壳,则会影响后续的观察者修改该事件;
如果观察者和被观察者之间存在循环依赖,则可能导致两者之间循环调用导致系统崩溃。
观察者模式的应用场景:
起床闹钟设置(如果一个人设置了一个闹钟,那么便会被闹钟提醒,那么闹钟就是被观察者,用户就是观察者);
朋友圈点赞提醒(微信朋友圈点赞之后,你就是观察者,微信的那条朋友圈就是被观察者);
网购APP商品降价通知推送(网购平台上,关注某个商品,当商品降价时,会收到通知)。
/**
* 抽象观察者
*/
interface Observer{
void response();
}
/**
* 具体观察者A
*/
class ConcreteObserverA implements Observer{
@Override
public void response() {
System.out.println(\"具体观察者A作出反应!\");
}
}
/**
* 具体观察者B
*/
class ConcreteObserverB implements Observer{
@Override
public void response() {
System.out.println(\"具体观察者B作出反应!\");
}
}
/**
* 抽象主题(被观察者)
*/
abstract class Subject{
protected List observers = new ArrayList<>();
/**
* 增加观察者方法
* @param observer
*/
public void add(Observer observer){
observers.add(observer);
}
/**
* 删除观察者方法
* @param observer
*/
public void remove(Observer observer){
observers.remove(observer);
}
/**
* 通知观察者方法
*/
public abstract void notifyObserver();
}
/**
* 具体目标(具体被观察者)
*/
class ConcreteSubject extends Subject{
@Override
public void notifyObserver() {
System.out.println(\"具体目标发生改变!\");
System.out.println(\"----------------\");
for(Observer obs : observers){
obs.response();
}
}
}
public class ObserverSimpleTest {
public static void main(String[] args){
Subject subject = new ConcreteSubject();
Observer observerA = new ConcreteObserverA();
Observer observerB = new ConcreteObserverB();
subject.add(observerA);
subject.add(observerB);
subject.notifyObserver();
}
}
观察者模式在Spring框架中的具体实现就是事件模型驱动开发
1.事件(ApplicationEvent)
ApplicationEvent 是所有事件对象的父类,类似于被观察者要做的被观察的事情。
用户可以通过继承ApplicationEvent,实现自定义事件。
下列描述了Spring提供的内置事件:
ContextRefreshedEvent:Spring容器刷新完成(所有bean都完成创建)的事件;
ContextClosedEvent:关闭Spring容器的时候的事件。
…等
2.事件发布(ApplicationEventPublisher/ApplicationContext)
ApplicationContext 是 Spring 中的核心容器,通过它的publishEvent()发布事件的通知给观察者(ApplicationListener)监听到(告诉观察者你需要观察哪个事件),因为事件创建好了不知道会不会被观察者观察到,所以会使用它。
3.事件监听(ApplicationListener)
ApplicationListener 事件监听器,也就是抽象观察者。继承自 jdk 的 EventListener,该类中只有一个方法 onApplicationEvent(),通过这个方法就是在事件执行的时候观察者要做的事情, 用户可以实现ApplicationListener接口进行事件监听(创建具体观察者)
4.事件多播器(ApplicationEventMulticaster)
ApplicationEventMulticaster 用于事件监听器的注册和事件的广播。等同于被观察者中的observers属性,监听器的注册、删除、把 Applicationcontext (被观察者)发布的事件广播给它的ApplicationListener(被观察者)列表(让他们进行链式调用)。
@ComponentScan(\"com.wxr.ext\")
@Configuration
public class ExtConfig {
}
这就是用户自定义创建的具体观察者类
@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {
/**
* 当容器中发布此事件以后,该方法出发
* 监听ApplicationEvent及下面的子事件
* 根据ApplicationEvent的继承关系:
* 例如:
* ContextRefreshedEvent:容器刷新完成(所有bean都完成创建)会发布这个事件
* ContextClosedEvent:关闭容器的时候会发布这个事件
* 步骤:
* 1.写一个监听器来监听某个事件(ApplicationEvent及其子类)
* 2.把监听器加入到容器中
* 3.只要容器中有相应类型的事件发布,我们就监听到这个事件
* @param event
*/
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println(\"收到事件:\"+event);
}
}
public class IocTest {
@Test
public void test02(){
AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(ExtConfig.class);
//发布事件
ioc.publishEvent(new ApplicationEvent(new String(\"我发布的事件\")) {
});
System.out.println(\"ioc容器创建完成\");
ioc.close();
}
}
根据三.1的输出结果,我们按照先后顺序从ContextRefreshedEvent,IocTest$1,ContextClosedEvent进行分析
执行步骤:
1.向spring容器中注册事件多播器(ApplicationEventMulticaster)
2.向spring容器中注册事件监听器(ApplicationListener)
3.通过事件发布(ApplicationEventPublisher/ApplicationContext)的publishEvent()告诉监听器需要监听的是哪个事件
3.1获取事件多播器(ApplicationEventMulticaster),通过它来遍历所有的事件监听器(ApplicationListener),并且调用他们的 onApplicationEvent()进行事件监听
3.2完成事件监听
2.1.1创建IoC容器(调用AnnotationConfigApplicationContext的构造器)
public class IocTest {
@Test
public void test02(){
//2.1.1.1走这里
AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(ExtConfig.class);
//发布事件
ioc.publishEvent(new ApplicationEvent(new String(\"我发布的事件\")) {
});
System.out.println(\"ioc容器创建完成\");
ioc.close();
}
}
//AnnotationConfigApplicationContext的构造器
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
//2.1.1.1走这里
refresh();
}
2.1.1.1调用AbstractApplicationContext.refresh()刷新容器
/**
*这是AbstractApplicationContext.refresh()
*/
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
//执行BeanFactoryPostProcessors
invokeBeanFactoryPostProcessors(beanFactory);
//注册bean的后置处理器
registerBeanPostProcessors(beanFactory);
// 初始化事件的多播器(派发器),在2.1.1.1.1.1.1会提到
initApplicationEventMulticaster();
// 注册所有的监听器,从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中
registerListeners();
//调用本类的finishBeanFactoryInitialization(beanFactory)完成BeanFactory的初始化工作
//实例化剩下的单实例Bean
finishBeanFactoryInitialization(beanFactory);
//调用本类的finishRefresh(),容器刷新完成
//2.1.1.1.1走这里
finishRefresh();
}
}
2.1.1.1.1调用AbstractApplicationContext.finishRefresh()完成容器刷新
protected void finishRefresh() {
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
//发布事件ContextRefreshedEvent刚刚好2.1ContextRefreshedEvent是一样的
//调用本类下的publishEvent(new ContextRefreshedEvent(this))
//2.1.1.1.1.1走这里
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
2.1.1.1.1.1调用AbstractApplicationContext. publishEvent(new ContextRefreshedEvent(this)) 开始进行ContextRefreshedEvent事件发布
@Override
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}
protected void publishEvent(Object event, ResolvableType eventType) {
Assert.notNull(event, \"Event must not be null\");
if (logger.isTraceEnabled()) {
logger.trace(\"Publishing event in \" + getDisplayName() + \": \" + event);
}
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<Object>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
//1.获取事件的多播器(派发器):getApplicationEventMulticaster() 2.1.1.1.1.1.1走这里
//2.派发事件:multicastEvent(applicationEvent, eventType)2.1.1.1.1.1.2走这里
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
2.1.1.1.1.1.1调用getApplicationEventMulticaster()获取事件的多播器(派发器)
ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
if (this.applicationEventMulticaster == null) {
throw new IllegalStateException(\"ApplicationEventMulticaster not initialized - \" +
\"call \'refresh\' before multicasting events via the context: \" + this);
}
return this.applicationEventMulticaster;
}
获取方法在refresh()的initApplicationEventMulticaster()中
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//判断在beanFactory中是否有id=\"applicationEventMulticaster\"的组件
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
//如果有就直接获取
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isDebugEnabled()) {
logger.debug(\"Using ApplicationEventMulticaster [\" + this.applicationEventMulticaster + \"]\");
}
}
else {
//如果没有那么就自己创建一个新的id=\"applicationEventMulticaster\"并注册到容器中
//我们可以再其他组件要派发事件的时候,自动注入这个applicationEventMulticaster
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isDebugEnabled()) {
logger.debug(\"Unable to locate ApplicationEventMulticaster with name \'\" +
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
\"\': using default [\" + this.applicationEventMulticaster + \"]\");
}
}
}
2.1.1.1.1.1.2调用SimpleApplicationEventMulticaster. multicastEvent(final ApplicationEvent event, ResolvableType eventType) 进行派发事件
@Override
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//拿到所有的ApplicationListener挨个遍历
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
//如果有异步执行的功能,那么通过多线程的方式异步派发invokeListener(listener, event);
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
//否则用同步的方式直接调用本类下的invokeListener(listener, event);
//2.1.1.1.1.1.2.1走这里
invokeListener(listener, event);
}
}
}
2.1.1.1.1.1.2.1调用SimpleApplicationEventMulticaster.invokeListener(ApplicationListener> listener, ApplicationEvent event)
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
//这次走这里
doInvokeListener(listener, event);
}
}
//再次调用本类下的doInvokeListener(ApplicationListener listener, ApplicationEvent event)
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
//2.1.1.1.1.1.2.1.1
//走这个方法直接回调到我们自己写的MyApplicationListener. onApplicationEvent(ApplicationEvent event)
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || msg.startsWith(event.getClass().getName())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
Log logger = LogFactory.getLog(getClass());
if (logger.isDebugEnabled()) {
logger.debug(\"Non-matching event type for listener: \" + listener, ex);
}
}
else {
throw ex;
}
}
}
2.1.1.1.1.1.2.1.1回到我们自己写的MyApplicationListener. onApplicationEvent(ApplicationEvent event)完成事件发布
@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println(\"收到事件:\"+event);
}
}
2.2.1调用自己写的发布时间方法ioc.publishEvent(new ApplicationEvent(new String(“我发布的事件”)) {});
public class IocTest {
@Test
public void test02(){
AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(ExtConfig.class);
//2.2.1.1走这里
ioc.publishEvent(new ApplicationEvent(new String(\"我发布的事件\")) {
});
System.out.println(\"ioc容器创建完成\");
ioc.close();
}
}
2.2.1.1直接调用AbstractApplicationContext. publishEvent(new ContextRefreshedEvent(this)) 开始进行ContextRefreshedEvent事件发布
@Override
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}
protected void publishEvent(Object event, ResolvableType eventType) {
Assert.notNull(event, \"Event must not be null\");
if (logger.isTraceEnabled()) {
logger.trace(\"Publishing event in \" + getDisplayName() + \": \" + event);
}
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<Object>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
//1.获取事件的多播器(派发器):getApplicationEventMulticaster()
//2.派发事件:multicastEvent(applicationEvent, eventType),这次走这里
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
2.2.1.1后面的逻辑和2.1.1.1.1.1.2之后一样了这里就不赘述了
2.3.1调用ioc.close()
public class IocTest {
@Test
public void test02(){
AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(ExtConfig.class);
//发布事件
ioc.publishEvent(new ApplicationEvent(new String(\"我发布的事件\")) {
});
System.out.println(\"ioc容器创建完成\");
//2.3.1.1走这里
ioc.close();
}
}
2.3.1.1调用AbstractApplicationContext.close()关闭容器
@Override
public void close() {
synchronized (this.startupShutdownMonitor) {
//这次走这里
doClose();
// If we registered a JVM shutdown hook, we don\'t need it anymore now:
// We\'ve already explicitly closed the context.
if (this.shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
}
catch (IllegalStateException ex) {
// ignore - VM is already shutting down
}
}
}
}
protected void doClose() {
//多余代码省略
try {
//发布ContextClosedEvent事件
//2.3.1.1.1走这里
publishEvent(new ContextClosedEvent(this));
}
//多余代码省略
}
2.3.1.1.1调用AbstractApplicationContext.publishEvent(ApplicationEvent event)发布ContextClosedEvent事件
2.3.1.1.1.1后面的逻辑和2.1.1.1.1.1.2之后一样了这里就不赘述了
ElasticSearch、kibana设置账户密码;ElasticSearch对外访问
基于 Rainbond 部署 DolphinScheduler 高可用集群
引领生物计算新浪潮 | 2021全球抗体亲和力预测大赛圆满结束
Lifecycle:生命周期感知型组件的基础 —— Jetpack 系列(1)
还摆个屁的烂?用Python画如此漂亮的专业插图 ?简直So easy!
Springboot使用redis实现接口Api限流的示例代码
外文翻译 | 你以为你会用Math.random() ? 不,你不会……
java 地图控件_控件交互-与地图交互-开发指南-Android 地图SDK | 高德地图API
【k8s部署 】k8s构建Flannel网络插件失败The connection to the server raw.githubusercontent.com was refused问题解决