spring的观察者模式demo

1.观察者模式与发布与订阅模式对比:

观察者模式

比较概念的解释是,目标和观察者是基类,目标提供维护观察者的一系列方法,观察者提供更新接口。具体观察者和具体目标继承各自的基类,然后具体观察者把自己注册到具体目标里,在具体目标发生变化时候,调度观察者的更新方法。

比如有个“天气中心”的具体目标A,专门监听天气变化,而有个显示天气的界面的观察者B,B就把自己注册到A里,当A触发天气变化,就调度B的更新方法,并带上自己的上下文。

img

发布/订阅模式

比较概念的解释是,订阅者把自己想订阅的事件注册到调度中心,当该事件触发时候,发布者发布该事件到调度中心(顺带上下文),由调度中心统一调度订阅者注册到调度中心的处理代码。

比如有个界面是实时显示天气,它就订阅天气事件(注册到调度中心,包括处理程序),当天气变化时(定时获取数据),就作为发布者发布天气信息到调度中心,调度中心就调度订阅者的天气处理程序。

img

总结

  1. 从两张图片可以看到,最大的区别是调度的地方。

虽然两种模式都存在订阅者和发布者(具体观察者可认为是订阅者、具体目标可认为是发布者),但是观察者模式是由具体目标调度的,而发布/订阅模式是统一由调度中心调的,所以观察者模式的订阅者与发布者之间是存在依赖的,而发布/订阅模式则不会。

  1. 两种模式都可以用于松散耦合,改进代码管理和潜在的复用。

2.搭建spring的观察者模式

1.搭建事件发布通用类

/**
 * 事件发布
 */
@Component
public class EventPublish {
    @Resource
    private ApplicationContext applicationContext;

    public void publish(Event event){
        applicationContext.publishEvent(event);
    }
}

2.搭建事件处理者(异步,同步时去掉@Async即可)

import com.wangfan.pojo.Event;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class EventConsumer {

    @EventListener(Event.class)
    @Async
    public void consumer(Event event){
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(event.getId());
        System.out.println(event.getContent());
        System.out.println("消息已被处理!");
    }
}

3.测试

import com.wangfan.event.EventPublish;
import com.wangfan.pojo.Event;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.Scanner;

@SpringBootTest
class TestWatchApplicationTests {

    @Resource
    private EventPublish eventPublish;
    @Test
    void contextLoads() {
        Event event = new Event();
        event.setId("1");
        event.setContent("前端业务已处理,传递参数:param");
        eventPublish.publish(event);
        System.out.println("前端方法执行完毕!");
        Scanner scanner=new Scanner(System.in);
        int i = scanner.nextInt();
        System.out.println(i);
    }

}