首页 > 编程语言 >Java观察者模式-SpringBoot实现观察者模式

Java观察者模式-SpringBoot实现观察者模式

时间:2023-10-10 18:14:08浏览次数:47  
标签:Java Spring 观察者 模式 事件 import ApplicationEvent

观察者模式

一、Java观察者模式

Java观察者模式是一种设计模式,用于实现对象之间的一对多依赖关系。在观察者模式中,当一个对象的状态发生变化时,它的所有依赖对象(观察者)都会自动收到通知并进行相应的更新。

观察者模式由以下几个核心组件组成:

  1. 主题(Subject):也称为被观察者或可观察对象,它维护一组观察者对象,并提供方法用于添加、删除和通知观察者。
  2. 观察者(Observer):也称为订阅者或监听器,它定义了接收和处理主题通知的方法。
  3. 具体主题(ConcreteSubject):实现主题接口,维护观察者列表,并在状态发生变化时通知观察者。
  4. 具体观察者(ConcreteObserver):实现观察者接口,定义了接收和处理主题通知的具体逻辑。

观察者模式的工作流程如下:

  1. 观察者通过订阅主题来注册自己,使得主题知道它们的存在。
  2. 当主题的状态发生变化时,它会通知所有注册的观察者。
  3. 观察者收到通知后,根据需要进行相应的更新操作。

观察者模式的优点包括解耦主题和观察者,使得它们可以独立变化;支持动态添加和删除观察者;实现了对象之间的松耦合,提高了系统的灵活性和可扩展性。

  • 场景1:用图来理解:

image

  • 场景2:多模块开发,解耦情况下,可以模块之间传递参数。

二、Spring实现的观察者模式

1、设计理念

在Spring Boot中,实现观察者模式的设计理念是基于事件驱动的编程模型。Spring Boot提供了一种简单而强大的事件机制,可以方便地实现观察者模式。

以下是Spring Boot实现观察者模式的设计理念:

  1. 事件(Event):事件是触发的动作或状态变化,可以是任何Java对象。在Spring Boot中,事件通常是继承自ApplicationEvent类的对象。

  2. 事件发布者(Event Publisher):事件发布者负责发布事件。在Spring Boot中,可以使用ApplicationEventPublisher接口来发布事件。通常,事件发布者是一个Spring Bean,通过依赖注入ApplicationEventPublisher来发布事件。

  3. 事件监听者(Event Listener):事件监听者是观察者,负责接收和处理事件。在Spring Boot中,可以使用@EventListener注解标记方法,使其成为事件监听者。当事件发布者发布事件时,被标记的方法会自动被调用。

  4. 事件处理逻辑:事件监听者方法中定义了事件的处理逻辑。可以根据具体需求,在事件监听者方法中编写相应的业务逻辑。

通过使用Spring Boot的事件机制,可以实现松耦合的观察者模式。事件发布者和事件监听者之间没有直接的依赖关系,它们通过事件进行通信。这样,可以方便地添加、删除和修改事件监听者,而不需要修改事件发布者的代码。

观察者模式的设计理念在Spring Boot中体现了面向对象编程的原则,如单一职责、开闭原则和依赖倒置原则。它提供了一种灵活、可扩展和可维护的方式来实现事件驱动的编程模型。

2、继承ApplicationEvent和不继承的区别

  • 发送的参数可以是普通JavaBean(String、integer、自定义类)、也可以是继承了ApplicationEvent的JavaBean
如果MyEvent继承ApplicationEvent,则可以使用Spring框架提供的事件传递机制。这意味着可以通过ApplicationEventPublisher发布事件,并且可以使用@EventListener注解标记观察者方法来接收事件。这种方式更符合Spring框架的设计理念,可以方便地实现观察者模式。

如果MyEvent不继承ApplicationEvent,则无法使用Spring框架提供的事件传递机制。需要自己实现事件的传递和观察者模式的逻辑。这种方式更适用于非Spring环境下的观察者模式实现。

继承ApplicationEvent的好处是可以利用Spring框架提供的事件传递机制,简化了观察者模式的实现。同时,还可以利用Spring框架提供的其他特性,如事务管理、AOP等。

不继承ApplicationEvent的好处是更加灵活,可以根据具体需求自由定义事件的结构和传递方式。但需要自己实现事件的传递和观察者模式的逻辑。

综上所述,如果在Spring框架中使用观察者模式,建议继承ApplicationEvent,以便利用Spring框架提供的事件传递机制和其他特性。

3、默认是广播模式

Spring框架中的观察者模式默认是广播模式。

在Spring框架中,当一个事件被发布时,所有注册的观察者都会接收到该事件。这意味着,一个事件可以被多个观察者同时接收和处理,实现了广播的效果。

这种广播模式的实现是通过ApplicationEventMulticaster接口和其默认实现类SimpleApplicationEventMulticaster来完成的。SimpleApplicationEventMulticaster会将事件广播给所有注册的观察者。

当然,如果需要更加细粒度地控制事件的传递方式,也可以自定义ApplicationEventMulticaster的实现类,实现自己的事件传递逻辑。

总结起来,Spring框架中的观察者模式默认是广播模式,一个事件会被所有注册的观察者接收和处理。这种广播模式的实现是通过ApplicationEventMulticaster接口和SimpleApplicationEventMulticaster类来完成的。

三、实现

1、广播模式(默认)——不推荐

  • 事件 —— 这里先不用,也可以用
  • 这里发送普通的JavaBean的参数,不发送“事件”

1.1、事件(Event)(无)

1.2、事件发布者(Event Publisher)

  • 注入ApplicationEventPublisher来实现
package com.cc.jsl.service.impl;

import com.cc.jsl.service.ILoginService;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * <p>事件发布者(Event Publisher)</p>
 *
 * @author CC
 * @since 2023/10/10
 */
@Service
public class LoginServiceImpl implements ILoginService {

    @Resource
    private ApplicationEventPublisher eventPublisher;

    @Override
    public void login(){
        //登陆逻辑...

        //发送
        // 1、可以直接发送JavaBean的参数:如String、自定义类
        eventPublisher.publishEvent("字符串参数!");
//        eventPublisher.publishEvent(new UserCs("cs" , 18));
//        eventPublisher.publishEvent(34);
        // 2、发送事件参数(继承了ApplicationEvent的类)

    }

}

1.3、事件监听者(Event Listener)

  • 使用@Async、@EventListener实现
  • 可以是很多个,也可以在不同类中
package com.cc.jsl.listener;

import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

/**
 * <p>事件监听者(Event Listener)</p>
 *
 * @author CC
 * @since 2023/10/10
 */
@Component
public class ReceiveListener {

    /**
     * 打电话 - 接收普通JavaBean参数
     */
    @Async
    @EventListener
    public void sendCall(String msg) {
        //发送邮件逻辑
        System.out.println("打电话!-普通-> " + msg);
    }

    /**
     * 发送邮件 - 接收字符串参数
     */
    @Async
    @EventListener
    public void sendEmail(String msg) {
        //发送邮件逻辑
        System.out.println("发送邮件!-普通-> " + msg);
    }
}

2、单个发送(推荐)

  • 每个发送都自定义一个唯一的类,并且继承ApplicationEvent

2.1、事件(Event)

  • 继承ApplicationEvent
  • 继承ApplicationEvent的好处是可以利用Spring框架提供的事件传递机制,简化了观察者模式的实现。同时,还可以利用Spring框架提供的其他特性,如事务管理、AOP等。
package com.cc.jsl.event;

import lombok.Getter;
import lombok.Setter;
import org.springframework.context.ApplicationEvent;

/**
 * <p>发邮件专属的唯一事件</p>
 * <p>需要实现set方法</p>
 *
 * @author CC
 * @since 2023/10/10
 */
@Getter
@Setter
public class EmailEvent extends ApplicationEvent {

    /**
     * 参数1
     */
    private String name;

    /**
     * 参数2
     */
    private Integer age;

    public EmailEvent(Object source, String name, Integer age) {
        super(source);
        this.name = name;
        this.age = age;
    }
}

2.2、事件发布者(Event Publisher)

package com.cc.jsl.service.impl;

import com.cc.jsl.event.EmailEvent;
import com.cc.jsl.service.ILoginService;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * <p>事件发布者(Event Publisher)</p>
 *
 * @author CC
 * @since 2023/10/10
 */
@Service
public class LoginServiceImpl implements ILoginService {

    @Resource
    private ApplicationEventPublisher eventPublisher;

    @Override
    public void login(){
        //登陆逻辑...

        //事件发布
        // 1、可以直接发送JavaBean的参数:如String、自定义类
//        eventPublisher.publishEvent("字符串参数!");
//        eventPublisher.publishEvent(new UserCs("cs" , 18));
//        eventPublisher.publishEvent(34);

        // 2、发送事件参数(继承了ApplicationEvent的类)
        EmailEvent emailEvent = new EmailEvent(this, "cc", 18);
        eventPublisher.publishEvent(emailEvent);
    }
}

2.3、事件监听者(Event Listener)

package com.cc.jsl.listener;

import com.cc.jsl.event.EmailEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

/**
 * <p>事件监听者(Event Listener)</p>
 *
 * @author CC
 * @since 2023/10/10
 */
@Component
public class ReceiveListener {

    /**
     * 打电话 - 接收普通JavaBean参数
     */
    @Async
    @EventListener
    public void sendCall(String msg) {
        //发送邮件逻辑
        System.out.println("打电话!-普通-> " + msg);
    }

    /**
     * 发送邮件 - 接收字符串参数
     */
    @Async
    @EventListener
    public void sendEmail(String msg) {
        //发送邮件逻辑
        System.out.println("发送邮件!-普通-> " + msg);
    }

    /**
     * 发送邮件 - 接收唯一事件
     */
    @Async
    @EventListener(EmailEvent.class)
    public void sendEmail(EmailEvent emailEvent) {
        //发送邮件逻辑
        System.out.println("发送邮件!-事件-> " + emailEvent);
    }
}
  • 发送邮件!-事件-> 除了这个以外的所有监听者都不会监听到消息
  • 经过测试,不使用事件,直接使用自定义类,只有监听了这个类的接受者才能接收到,所以相当于实现了一对一。
  • 自定义事件的好处:可以利用Spring框架提供的事件传递机制,简化了观察者模式的实现。同时,还可以利用Spring框架提供的其他特性,如事务管理、AOP等。
  • 接收到的消息:
    image

四、总结

参考:https://blog.csdn.net/weixin_43745998/article/details/127301003

标签:Java,Spring,观察者,模式,事件,import,ApplicationEvent
From: https://www.cnblogs.com/kakarotto-chen/p/17755295.html

相关文章

  • Java 集合
    目录Java集合List,Set,Queue,Map的区别集合框架底层数据结构CollectionListSetQueueMap如何选用集合?ListArrayList和Array(数组)的区别转换ArrayList转换为数组数组转换为ArrayListSetComparable和Comparator的区别Comparable接口Comparator接口总结HashSetLinkedHas......
  • 工厂方法模式
      ......
  • Java 中 extends 与implements 的区别 ?
    一、介绍extends与implements的概念1、类与类之间的继承使用extends:子类extends父类的属性和方法,并且进行扩展或者重写。//父类classAnimal{publicvoideat(){System.out.println("Animaliseating");}publicvoidnoeat(){......
  • 建造者模式
    一、概念建造者模式使用简单的对象一步一步构建一个复杂的对象。应用场景:在软件系统中,有时需要创建一个复杂对象,其通常由各个部分的子对象用一定的算法构成。由于需求的变化,这个复杂对象的各个部分会有所不同,但是它们组合在一起的算法是相对稳定的。二、实现我们假设......
  • Java设计模式之责任链模式
    1.1.概述在现实生活中,常常会出现这样的事例:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。例如,公司员工请假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批准的天数不同,员工必须根据自己要请假的天数去找不同的领导签名,也就是说员工必须记住每个领......
  • Java创建PKCS12证书Http请求
    //证书地址publicstaticfinalStringPATH="XX.pfx";//密码publicstaticfinalStringPASSWORD="aaa";publicstaticCloseableHttpClientinitSSLConfig()throwsException{//证书类型KeyStorekeyStore=KeyStore.getInstanc......
  • 详解如何通过JavaScript实现函数重载
    有的同学在开发中可能遇到过一个困扰,但是很少有人去解决这个问题,我这用一个例子展现出来constsearcher={};searcher.findAll=()=>{console.log("查询所有用户");};searcher.findByName=(name)=>{console.log("按照用户名称查询");};searcher.findByFirstN......
  • Android Studio可以编译但Flutter提示无法定位java runtime
    AndroidStudio可以编译但Flutter提示无法定位javaruntime下面我们重点讲一下“UnabletofindbundledJavaversion”报错问题到AndroidStudio安装目录下注意:有些AndroidStudio可能是“jbr”文件,不用管jbr文件,直接复制一份jbr文件在同一路经,再把复制的文件改名为“jre”文......
  • java stream 操作map根据key或者value排序的实现
    javastream操作map根据key或者value排序的实现publicclassTest02{publicstaticvoidmain(String[]args){List<FundBenchMarkInfo>fundBenchMarkList=newArrayList<>();fundBenchMarkList.add(newFundBenchMarkInfo("2",new......
  • Composite 组合模式简介与 C# 示例【结构型3】【设计模式来了_8】
    〇、简介1、什么是组合设计模式?一句话解释:  针对树形结构的任意节点,都实现了同一接口,他们具有相同的操作,可以通过某一操作来遍历全部节点。组合模式通过使用树形结构来组合对象,用来表示部分以及整体层次。组合模式属于结构型模式,多用于递归。官方意图描述:将对象组合成树形......