什么是观察者模式
在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新。
其实就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息。x
应用场景
Zookeeper事件通知节点、消息订阅通知、安卓开发事件注册
分布式配置中心
原理类图

抽象被观察者角色:也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
具体被观察者角色:也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。
具体观察者角色:实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。
手写简单实现
具体代码
定义事件对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;
@Data @NoArgsConstructor @AllArgsConstructor public class EvenObject {
private String id;
private String message;
}
|
定义事件监听
1 2 3 4 5 6 7 8 9 10 11 12
|
public interface EventListener {
void doEvent(EvenObject evenObject); }
|
事件管理类
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;
public class EventManager {
Map<Enum<EventType>, List<EventListener>> listeners = new HashMap<>();
public EventManager(Enum<EventType>... operations) { for (Enum<EventType> operation : operations) { this.listeners.put(operation, new ArrayList<>()); } }
public enum EventType { MQ, Message }
public void subscribe(Enum<EventType> eventType, EventListener listener) { List<EventListener> users = listeners.get(eventType); users.add(listener); }
public void unsubscribe(Enum<EventType> eventType, EventListener listener) { List<EventListener> users = listeners.get(eventType); users.remove(listener); }
public void notify(Enum<EventType> eventType, EvenObject result) { List<EventListener> users = listeners.get(eventType); for (EventListener listener : users) { listener.doEvent(result); } } }
|
业务抽象类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
public abstract class BusinessService {
private EventManager eventManager;
public BusinessService() { eventManager = new EventManager(EventManager.EventType.MQ, EventManager.EventType.Message); eventManager.subscribe(EventManager.EventType.MQ, new MqEventListener()); eventManager.subscribe(EventManager.EventType.Message, new MessageEventListener()); }
public EvenObject draw(String id) { EvenObject lotteryResult = doDraw(id); eventManager.notify(EventManager.EventType.MQ, lotteryResult); eventManager.notify(EventManager.EventType.Message, lotteryResult); return lotteryResult; }
protected abstract EvenObject doDraw(String id); }
|
业务实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import java.time.LocalDateTime;
public class BusinessServiceImpl extends BusinessService{
@Override protected EvenObject doDraw(String id) { EvenObject evenObject = new EvenObject(id,"message"+ LocalDateTime.now()); return evenObject;
} }
|
测试
1 2 3 4 5 6 7
| public static void main(String[] args) { BusinessService businessService = new BusinessServiceImpl(); EvenObject draw = businessService.draw("123"); log.info("测试结果:{},{}", draw.getId(),draw.getMessage()); }
|
1 2 3 4 5 6
| 21:44:54.838 [main] INFO com.example.springbooot.observer.MqEventListener - 给用户 123 发送MQ通知(短信):message2021-09-02T21:44:54.836 21:44:54.842 [main] INFO com.example.springbooot.observer.MessageEventListener - 给用户 123 发送短信通知(短信):message2021-09-02T21:44:54.836 21:44:54.843 [main] INFO com.example.springbooot.observer.Main - 测试结果:123,message2021-09-02T21:44:54.836
Process finished with exit code 0
|
JDK自带观察实现
自定义主题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import java.util.Observable;
public class MessageObservable extends Observable {
@Override public void notifyObservers(Object arg) { setChanged(); super.notifyObservers(arg); } }
|
自定义观察者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import lombok.extern.slf4j.Slf4j;
import java.util.Observable; import java.util.Observer;
@Slf4j public class EmailObServer implements Observer {
@Override public void update(Observable o, Object arg) { MessageObservable messageObServable = (MessageObservable) o; log.info("发送邮件内容:{}",arg); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import lombok.extern.slf4j.Slf4j;
import java.util.Observable; import java.util.Observer;
@Slf4j public class SmsObServer implements Observer {
@Override public void update(Observable o, Object arg) { log.info("发送sms:{}",arg); } }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import java.time.LocalDateTime;
public class JdkObServer {
public static void main(String[] args) { MessageObservable messageObServable = new MessageObservable(); messageObServable.addObserver(new EmailObServer()); messageObServable.addObserver(new SmsObServer()); messageObServable.notifyObservers(LocalDateTime.now()); } }
|
Spring封装实现
创建Event事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import lombok.Getter; import lombok.Setter; import org.springframework.context.ApplicationEvent;
public class MyApplicationEvent extends ApplicationEvent {
@Getter @Setter private String msg;
public MyApplicationEvent(Object source, String msg) { super(source); this.msg = msg; } }
|
创建Event事件监听
实现 接口方式
实现 ApplicationListener
接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import org.springframework.context.ApplicationListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component;
@Component public class EmailListener implements ApplicationListener<MyApplicationEvent> {
@Override @Async public void onApplicationEvent(MyApplicationEvent event) { System.out.println(Thread.currentThread().getName() + "发送邮件内容:" + event.getMsg()); } }
|
实现 SmartApplicationListener
接口
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
| import org.springframework.context.ApplicationEvent; import org.springframework.context.event.SmartApplicationListener; import org.springframework.stereotype.Component;
@Component public class MqListener implements SmartApplicationListener { @Override public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) { System.out.println(eventType == MyApplicationEvent.class); return eventType == MyApplicationEvent.class; }
@Override public int getOrder() { return 10; }
@Override public void onApplicationEvent(ApplicationEvent event) { System.out.println(Thread.currentThread().getName() + "发送mq内容:" + ((MyApplicationEvent) event).getMsg()); } }
|
注解方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component;
@Component public class SmsListener {
@EventListener public void sendEmail(MyApplicationEvent event) { System.out.println(Thread.currentThread().getName() + "发送短信内容:" + event.getMsg()); } }
|
事件发布
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
| import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
@RestController public class PushController {
@Autowired private ApplicationContext applicationContext;
@RequestMapping("/push") public void push(){ MyApplicationEvent myApplicationEvent = new MyApplicationEvent(this,LocalDateTime.now().toString()); applicationContext.publishEvent(myApplicationEvent); }
}
|
测试
1 2 3
| http-nio-8089-exec-1发送短信内容:2021-09-02T22:45:51.712 http-nio-8089-exec-1发送mq内容:2021-09-02T22:45:51.712 http-nio-8089-exec-1发送邮件内容:2021-09-02T22:45:51.712
|