声明:本文根据鲁班学院子路老师spring中观察者模式课程整理得来
观察者模式特点:
被观察者持有监听的观察者的引用。
被观察者支持增加和删除的观察者。
被观察者状态改变通知观察者。
JDK中观察者implements Observer接口,重写update()方法
当观察者发生变化,收到通知进行具体的处理
可以随时取消
松耦合:
观察者增加或者删除无需修改被观察者的代码,只需调用被观察者对应的增加或则删除的方法即可
被观察者只负责通知观察者,但无需了解观察者如何处理通知
观察者只需等待被观察者通知,无需观察被观察者细节
通知不会错过:
由于被动接受,正常情况下不会错过主体的改变通知,而主动获取的话,由于时机选择问题,可能导致错过某些状态
Java实现
Java中有观察者模式使用的API
Java.util.Observable 这是一个类
java.util.Observer 这是一个接口
开关的重要性
可以筛选通知
可以撤销通知
可以控制通知
Spring中的观察者模式
在Spring中定义和应用程序上下文相关的事件时需要继承ApplicationEvent类
public abstract class ApplicationEvent extends EventObject {
/** use serialVersionUID from Spring 1.2 for interoperability. */
private static final long serialVersionUID = 7099057708183571937L;
/** System time when the event happened. */
private final long timestamp;
/**
* Create a new {@code ApplicationEvent}.
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
*/
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
/**
* Return the system time in milliseconds when the event occurred.
*/
public final long getTimestamp() {
return this.timestamp;
}
}
在ApplicationEvent的父类EventObject类(这个是java源码中的类)中有一个得到事件源的方法getSource()
Spring中的Events
事件通过**org.springframework.context.ApplicationEvent**实例来表示。这个抽象类继承扩展了**java.util.EventObject**,可以使用**EventObject中的getSource**方法,我们可以很容易地获得所发生的给定事件的对象。这里,事件存在两种类型。
1. **与应用程序上下文相关联**
所有这种类型的事件都继承自**org.springframework.context.event.ApplicationContextEvent**类。
它们应用于由**org.springframework.context.ApplicationContext**引发的事件(其构造函数传入的是`ApplicationContext`类型的参数)。
这样,我们就可以直接通过应用程序上下文的生命周期来得到所发生的事件:`ContextStartedEvent`在上下文启动时被启动,当它停止时启动`ContextStoppedEvent`,当上下文被刷新时产生`ContextRefreshedEvent`,最后在上下文关闭时产生`ContextClosedEvent`。
以ContextStartedEvent这个类为例,实现SpringEvent的扩展功能,这个事件在context.start()的时候来进行监听处理。
public class ContextStartedEvent extends ApplicationContextEvent {
/**
* Create a new ContextStartedEvent.
* @param source the {@code ApplicationContext} that has been started
* (must not be {@code null})
*/
public ContextStartedEvent(ApplicationContext source) {
super(source);
}
}
1.首先创建一个listener类
/**
* spring通过实现ApplicationListener这个接口,同时传入一个泛型(ContextStartedEvent)就可以
* 监听到这个泛型对应的事件
*/
@Component
public class SpringListenerStart implements ApplicationListener<ContextStartedEvent> {
@Override
public void onApplicationEvent(ContextStartedEvent event) {
System.out.println("----- spring application start listener------");
}
}
2.创建测试类
public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WkApplication.class); context.start();//在调用context的start()方法时,会触发spring的监听器,调用ContextStartedEvent对应的事件方法
}
}
3.运行结果
Spring监听器的应用(模拟一个发邮件的监听器):
1.创建一个SpringMailEvent类,使它继承ApplicationEvent类(这个是Spring的事件类,自己的事件都要继承它)
public class SpringMailEvent extends ApplicationEvent implements Serializable {
//需要序列化,要不会报错。我也不知道为什么
private static final long serialVersionUID=762508508425139227l;
private String content;
/**
* Create a new {@code ApplicationEvent}.
*
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
*/
public SpringMailEvent(Object source) {
super(source);
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
2.创建一个SpringMailListener监听器类,使他实现ApplicationListener接口,同时泛型中穿我们自己定义的事件<SpringMailEvent>
@Component
public class SpringMailListener implements ApplicationListener<SpringMailEvent> {
/**
* 当程序调用了一个发邮件的方法时,这个监听器就会监听到,
* 同时在onApplicationEvent方法中做出响应
* @param event the event to respond to
*/
@Override
public void onApplicationEvent(SpringMailEvent event) {
System.out.println("mail send ");
}
}
3.创建一个类,使自定义的监听器和事件与spring容器关联起来
/**
* 创建自己的类,使自定义的监听器和事件与spring容器关联起来
*/
@Component
public class MailBean {
@Autowired
ApplicationContext context;//注入Sprig应用程序上下文
/**
* 我们之前只是定义了SpringMailEvent类,但是这个类并没有和Spring容器关联起来,
* 所以我们需要借助ApplicationContext的publishEvent()方法,把这个事件发布出去
*/
public void sendMail(){
context.publishEvent(new SpringMailEvent(context));
}
}
4.测试类
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WkApplication.class);
// context.start();
//触发发邮件的事件
context.getBean(MailBean.class).sendMail();
}
}
5.测试结果
2. **与request 请求相关联**
由**org.springframework.web.context.support.RequestHandledEvent**实例来表示,当在ApplicationContext中处理请求时,它们被引发。
Spring如何将事件分配给专门的监听器?
这个过程由事件广播器来实现,由**org.springframework.context.event.ApplicationEventMulticaster**接口的实现表示。此接口定义了3种方法
1. **addApplicationListener()** 添加新的监听器**:定义了两种方法来添加新的监听器:**addApplicationListener(ApplicationListener<?> listener)**和**addApplicationListenerBean(String listenerBeanName)**。当监听器对象已知时,可以应用第一个。如果使用第二个,我们需要将bean name 得到listener对象(`依赖查找DL`),然后再将其添加到`listener`列表中
2. **removeApplicationListenerBean(String listenerBeanName)** **删除监听器**:添加方法一样,我们可以通过传递对象来删除一个监听器(**removeApplicationListener(ApplicationListener<?> listener)**或通过传递bean名称。第三种方法,**removeAllListeners()**用来删除所有已注册的监听器。
3. **multicastEvent(ApplicationEvent event)****将事件发送到已注册的监听器**。