观察者模式:observer pattern
对象存在一对多关系,当一个对象被修改,则自动通知其他依赖它的对象
关键代码:在抽象类中有ArrayList 存放观察者们
subject
observer
client
package com.example.demo.designpattern.oberver;
import java.util.ArrayList;
import java.util.List;
/**
* 观察者模式 被观察的对象
*/
public class Subject {
//被观察的属性状态,当属性变化时要通知观察者们
private String state;
//观察者集合,因为需要通知观察者
private List<AbstractObserver> abstractObserverList = new ArrayList<>();
public String getState() {
return state;
}
// 被观察的是state的属性,所有当state属性变化时,需要同时观察者
public void setState(String state) {
this.state = state;
this.notifyAllObserves(state);
}
private void notifyAllObserves(String state) {
for(AbstractObserver abstractObserver:abstractObserverList) {
abstractObserver.update();
}
}
//将观察者加入集合中
public void add(AbstractObserver abstractObserver) {
this.abstractObserverList.add(abstractObserver);
}
}
package com.example.demo.designpattern.oberver;
/**
* 抽象观察者,解耦
*/
public abstract class AbstractObserver {
//定义一个对象,在实现类构造方法中传入对象
public Subject subject;
public abstract void update();
}
package com.example.demo.designpattern.oberver;
/**
* 具体的观察者,实现抽象类
*/
public class Observer1 extends AbstractObserver{
//观察者们需要将自己加入观察对象的观察集合中
//传入观察者对象
public Observer1(Subject subject){
this.subject = subject;
subject.add(this);
}
@Override
public void update() {
System.out.println("观察者1收到了状态变化通知");
}
}
package com.example.demo.designpattern.oberver;
public class Observer2 extends AbstractObserver{
public Observer2(Subject subject) {
this.subject = subject;
subject.add(this);
}
@Override
public void update() {
System.out.println("观察者2收到了状态变化通知");
}
}
package com.example.demo.designpattern.oberver;
public class ObserverDemo {
public static void main(String[] args) {
Subject subject = new Subject();
new Observer1(subject);
new Observer2(subject);
subject.setState("1");
}
}
java源码已经内置了观察者模式,我们使用时只需要去继承即可
主题类 Observable Observable内部使用Vector来存储注册的观察者实例,是线程安全的。
分析下 主题类 Observable源码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package java.util;
public class Observable {
//只有changed为true才开启通知
private boolean changed = false;
//观察者集合使用vector保证线程安装
private Vector<Observer> obs = new Vector();
public Observable() {
}
//将观察者加入集合
public synchronized void addObserver(Observer var1) {
if (var1 == null) {
throw new NullPointerException();
} else {
if (!this.obs.contains(var1)) {
this.obs.addElement(var1);
}
}
}
//删除观察者
public synchronized void deleteObserver(Observer var1) {
this.obs.removeElement(var1);
}
// 主题类状态发生变化时通知观察者
public void notifyObservers() {
this.notifyObservers((Object)null);
}
public void notifyObservers(Object var1) {
Object[] var2;
synchronized(this) {
if (!this.changed) {
return;
}
//集合转数组遍历
var2 = this.obs.toArray();
this.clearChanged();
}
for(int var3 = var2.length - 1; var3 >= 0; --var3) {
((Observer)var2[var3]).update(this, var1);
}
}
public synchronized void deleteObservers() {
this.obs.removeAllElements();
}
// 将changed变成true
protected synchronized void setChanged() {
this.changed = true;
}
protected synchronized void clearChanged() {
this.changed = false;
}
public synchronized boolean hasChanged() {
return this.changed;
}
public synchronized int countObservers() {
return this.obs.size();
}
}
观察者抽象类:Observer 具体的实现需要我们自己实现
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package java.util;
public interface Observer {
void update(Observable var1, Object var2);
}
下面就按照java自带的观察者模式改造上述案例
package com.example.demo.designpattern.oberver.javaobserver;
import java.util.Observable;
public class JavaSubject extends Observable {
//定义我们观察的属性
private String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
statementChanged();
}
private void statementChanged() {
//将changed改成true
setChanged();
//通知其他观察者
notifyObservers();
}
}
package com.example.demo.designpattern.oberver.javaobserver;
import java.util.Observable;
import java.util.Observer;
public class Observer1 implements Observer {
private Observable observable;
public Observer1(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
System.out.println("观察者1收到了状态变化通知");
}
}
package com.example.demo.designpattern.oberver.javaobserver;
import com.example.demo.designpattern.oberver.Subject;
public class JavaSubjectDemo {
public static void main(String[] args) {
JavaSubject javaSubject = new JavaSubject();
new Observer1(javaSubject);
javaSubject.setState("1");
}
}
借用java自带的观察者模式可以很轻松就实现了通知
基于观察者模式的spring监听机制
spring 中观察者模式的实现:
对象说明:
applicationContext spring核心容器对象(beanfactory也是容器对象) 事件监听中 ApplicationContext 可以作为事件的发布者,也就是事件源 因为 ApplicationContext 继承自 ApplicationEventPublisher。
Spring 中默认存在以下事件,他们都是对 ApplicationContextEvent 的实现(继承自ApplicationContextEvent):
ContextStartedEvent:ApplicationContext 启动后触发的事件;
ContextStoppedEvent:ApplicationContext 停止后触发的事件;
ContextRefreshedEvent:ApplicationContext 初始化或刷新完成后触发的事件;
ContextClosedEvent:ApplicationContext 关闭后触发的事件。在 ApplicationEventPublisher 中定义了事件发布的方法:publishEvent(Object event)
applicationEvent 事件对象 (contextrefreshedEvent 容器刷新对象) 主题类
applicationListener 事件监听对象 观察者类(接口抽象) 继承自 jdk 的 EventListener,该类中只有一个方法 onApplicationEvent。当监听的事件发生后该方法会被执行
ApplicationEventMulticaster 事件管理,用于事件监听器的注册和事件的广播。监听器的注册就是通过它来实现的,它的作用是把 Applicationcontext 发布的 Event 广播给它的监听器列表。
案例: 主题
package com.example.demo.designpattern.oberver.springobserver;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import java.time.Clock;
public class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
System.out.println("MyEvent 构造器执行");
}
}
监听对象: 可以继承ApplicationListener<MyEvent>实现
package com.example.demo.designpattern.oberver.springobserver;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class MyListenerA implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
System.out.println("MyListenA");
}
}
可以使用注解 @EventListener 实现
package com.example.demo.designpattern.oberver.springobserver;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class MylistenerB {
@EventListener
public void onApplicationEvent(MyEvent event) {
System.out.println("MylistenB");
}
}
发布: 注明在bean加载过程中实现了ApplicationContextAware的接口,会在bean实例化完成后调用setApplicationContext方法,传入ApplicationContext bean工厂,然后调用publishEvent 发布事件
package com.example.demo.designpattern.oberver.springobserver;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.stereotype.Component;
@Component(value ="myPublisher")
public class MyPublisher implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void publishEvent(ApplicationEvent event){
System.out.println("publish event");
applicationContext.publishEvent(event);
}
}
测试:
package com.example.demo.designpattern.oberver.springobserver;
import com.example.demo.designpattern.oberver.springobserver.MyEvent;
import com.example.demo.designpattern.oberver.springobserver.MyPublisher;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Scope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
@RestController
@RequestMapping(value = "kangtest")
public class SpringObserverController {
@RequestMapping(value = "observer", method = RequestMethod.GET)
public void getText() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
ServletContext servletContext = request.getSession().getServletContext();
WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
MyPublisher myPublisher = (MyPublisher)applicationContext.getBean("myPublisher");
myPublisher.publishEvent(new MyEvent(this));
// new MyEvent(this);
}
}