1.介绍
- 本质是“定义对象之间的一对多依赖关系,以便当一个对象改变状态时,其所有依赖关系都会被通知并自动更新”。
- 发布/订阅模式的子集,它允许许多观察者对象查看事件。
2.分类
2.1传统的监听器模式
传统的监听器模式分为2类角色,一个是被观察者,一个是观察者。举个例子:假如你去4s店买一个车,当你买了一辆车之后,销售员和经理会分别收到你购买车的这个消息,进行不同的处理流程。这里你买车就是被观察者,经理和销售员就是观察者。
java代码设计的思路就是:
- 编写一个关于客户的类,里面定义了客户买车这个动作方法。
- 客户类添加一个观察者集合,需要通知那些人的集合。
- 当客户发生有关行为时,就要去遍历这个集合进行相关通知。
- 不同观察者根据不同行为,做出不同反馈行为。
public interface OrdinaryListener {
void callback(String event);
}
public class ActionListener {
private List<OrdinaryListener> list=new ArrayList<OrdinaryListener>();
public void addListenner(OrdinaryListener listener){this.list.add(listener);}
public void hand(){list.forEach(s->{s.callback("事件发生了");});}
}
/**
* 1.监听者: 等待被监听者通知的事件,等待被回调。实现Listener接口。
* 2.被监听者:ActionListener主要通知监听者事件
*/
public class ListennerMain {
public static void main(String[] args) {
ActionListener actionListener = new ActionListener();
actionListener.addListenner(listener->{
System.out.println("监听者1收到:"+listener);
});
actionListener.addListenner(listener->{
System.out.println("监听者2收到:"+listener);
});
actionListener.hand();
}
}
2.2 spring监听器模式
spring里面的监听模式分为:
- 事件:观察者具体要执行的动作
- 监听器:观察者,可以接受不同的事件做不同的处理
- 事件路由器:spring里面叫多播器,其实就是做的就是被观察者发生行为后,遍历被观察者集合进行遍历通知。
- 事件源:谁来执行发布具体的事件来源
具体的执行过程:
- 事件源发布不同的事件
- 事件发布后,会调用spring里面叫多播器,进行事件的广播路由,触发具体的监听器去执行
- 监听器收到不同事件,进行不同处理。
下面是java代码,没有使用spring里面叫多播器那种模式,后面源码分析会有说明。
public class EventObject {
public EventSource source;
public EventObject(EventSource source) {
this.source = source;
}
}
public interface Listener {
void callback(EventObject event);
}
public class EventSource {
public String eventName;
// 事件源增加监听器对象
private Set<Listener> listenerSet = new HashSet<>();
public void registerEventListener(Listener eventListener){
if (eventListener != null){
listenerSet.add(eventListener);
}
}
public void handle(){
for(Listener listener : listenerSet){
listener.callback(new EventObject(this));
}
System.out.println(this.eventName+"开始处理");
}
}
/**
* 1.事件源 EventSource 具有注册监听器的方法
* 2.事件对象 EventObject 事件
* 3.监听器 Listener 有callback(EventObject)方法,当收到事件发生后的处理。
* 4.事件对象:主要目的是包装事件源,然后将本身(事件对象)交给监听器。
*/
public class ListenMain {
public static void main(String[] args) {
EventSource source1 = new EventSource();
source1.eventName = "source1";
source1.registerEventListener(event -> {
System.out.println("listen1:" + event.source);
});
source1.registerEventListener(event -> {
System.out.println("listen2:" + event.source);
});
source1.handle();
}
}
3.spring关于监听器部分源码分析
大体的处理流程源码中:
- 提前准备好一些事件
- 初始化多播器
- 准备好的监听器
- 多播器中注册自己有的监听器
- 准备事件发布,通知多播器进行相关处理
大家可以想看一下AbstractApplicationContext中refresh()方法中有关的代码
public void refresh() throws BeansException, IllegalStateException {
...................
// Prepare this context for refreshing.
prepareRefresh();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Check for listener beans and register them.
registerListeners();
// Last step: publish corresponding event.
finishRefresh();
...................
}
在prepareRefresh()方法中会初始化一些早起事件集合,早期监听者的集合
// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
在initApplicationEventMulticaster方法中会初始化一个事件多播器,如果容器有,就用已经有的,没有的话,需呀new一个出来,注册到容器,并且赋值beanfatory。
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
在registerListeners()方法中1.查看集合中已经存在的监听器注册到多播器中(这里含有之前的早期监听器集合) 2.查找beanfactory中实现ApplicationListener接口的bean的名字,注册到多播器中 3.因为容器之前初始化了一个早期事件集合,这里面有可能挤压了早期事件,所以这里使用多播器广播早期事件
protected void registerListeners() {
// Register statically specified listeners first.
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
在finishRefresh()方法中会发布一个ContextRefreshedEvent事件
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
clearResourceCaches();
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
if (!NativeDetector.inNativeImage()) {
LiveBeansView.registerApplicationContext(this);
}
}
这里探究一下publishEvent它最后调用的是SimpleApplicationEventMulticaster的multicastEvent方法进行事件路由的。
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
感兴趣的话大家可以探索一下这个类