Spring中的事件机制,监听器模式
1. Spring中的事件机制(广播器)
1.1 事件传播机制在Spring中的作用
ApplicationEvent事件的存在是为了,在应用完成Spring容器的初始化后,紧接着需要将容器完成初始化这一事件动作通知广播给其他事件监听器,让接受该应用事件ApplicationEvent的事件监听器ApplicationListener的实现者完成后续动作。比如SqlSessionFactoryBean其实也是一个应用事件监听器ApplicationListener以及ScheduledAnnotationBeanPostProcessor也是一个ApplicationListener。
Q:SqlSessionFactoryBean为什么要是一个ApplicationListener?
A:mybatis提供了一种fail-fast机制,这个机制是校验mybatis的statement语句。当ApplicationContext完成初始化后,生成一个ApplicationEvent的事件,该事件经由SimpleApplicationEventMulticaster广播到所有的监听器中去。
Q:ScheduledAnnotationBeanPostProcessor为什么要是一个ApplicationListener?
A:Spring将调度任务的执行器的创建的执行时机放到了application完成初始化这段时间。为了给Spring其他的事件监听器一个同时执行他们工作的机会完成注册登记。e.g. Spring Batch’s job registration
Q:SourceFilterListener的作用
A:当一个Spring Web应用初始化的时候,触发Spring子容器MVC初始化完成时,被该监听器监听到,并处理,执行DispatchServlet的初始化策略。在这个初始化策略中,将handlerMappings以及handlerAdapters等赋值。
1.2 ApplicationEvent,ApplicationListener,ApplicationEventMulticaster的关系
ApplicationEvent(事件)经由ApplicationEventMulticaster(广播器)传播到所有该监听该事件的ApplicationListener(监听器中)。这个监听器模式是扩展自jdk中的事件。
ApplicationEvent(事件对象,abstract class) extends EventObject
ApplicationListener(事件监听器,interface)extends EventListener,它会处理这个事件。
ApplicationEventMulticaster(事件广播器,interface),Spring中自定义的一个接口,该接口的存在,是为了对所有的事件监听器进行统一的管理,表现为,有一个ApplicationListener的集合;并且,还会将接收到的事件对象ApplicationEvent广播到所有的事件监听器中去(ApplicationListener)。
1.3 Spring通过这种设计模式产生了什么样的效果?
易于扩展,这是最显而易见的。当我们需要对Spring扩展的时候,我们有这样一个需求,我们后续功能需要在Spring应用完成初始化后,被告知来实现,就可以实现一个ApplicationListener。
掌握这种设计模式,关键的就是什么时候应用。当一个功能与时机有关的时候,就可以利用监听器模式;或者,我们需要将一个动作产生的对象进行传递的时候,且又便于扩展的时候(利用ApplicationEvent会有一个事件源)。
总结:
- 继承EventObject的Event
- 继承EventListener的Listener的onXxxEvent(Event),用户自定义的处理事件的方法。
- 自定义一个EventMulticaster,管理所有的Listener,以及向所有的Listener发布事件multicastEvent方法。
3.1 获取所有的Listener
3.2 invokeListener(listener, event)
3.3 doInvokeListener(listener, event)
3.4 listener.onXxxEvent(event);
2. Netty中的事件机制(基于事件驱动的)
药量理解Netty是基于事件驱动的,首先得需要知道,Netty都有哪些事件。
Netty中的事件监听器。
Netty中的编程是异步编程,通过事件通知的方式保证了异步编程的程序执行的逻辑正确性,因此如官方介绍的,是基于事件驱动的。具体怎么事件驱动,可以查看我的excel的Netty源代码执行顺序图,以便更好的理解什么是基于事件驱动的编程。Netty服务端源代码执行时序图
/**
* Listens to the result of a {@link Future}. The result of the asynchronous operation is notified once this listener
* is added by calling {@link Future#addListener(GenericFutureListener)}.
*/
public interface GenericFutureListener<F extends Future<?>> extends EventListener {
/**
* Invoked when the operation associated with the {@link Future} has been completed.
*
* @param future the source {@link Future} which called this callback
*/
void operationComplete(F future) throws Exception;
}
FutureListener是扩展GenericFutureListener,仅仅是为了方便,隐藏了类型参数。
/**
* A subtype of {@link GenericFutureListener} that hides type parameter for convenience.
* <pre>
* Future f = new DefaultPromise(..);
* f.addListener(new FutureListener() {
* public void operationComplete(Future f) { .. }
* });
* </pre>
*/
public interface FutureListener<V> extends GenericFutureListener<Future<V>> { }
Netty中的FutureListener对应的事件,没有继承EventObject,而是自定义的“事件”,即Future。换句话说,此事件非彼事件,监听的是异步操作的结果(监听的不是事件,而是操作)。以Future的子类CompletFuture为例来说明如何完成对监听器的通知。
@Override
public Future<V> addListener(GenericFutureListener<? extends Future<? super V>> listener) {
if (listener == null) {
throw new NullPointerException("listener");
}
DefaultPromise.notifyListener(executor(), this, listener);
return this;
}
具体的事件:
ChannelFuture扩展了Future,提供了channel方法。
ChannelFutureListener扩展了GenericFutureListener,用于监听ChannelFuture的结果。
// 调用Netty的线程执行
private ChannelFuture doBind(final SocketAddress localAddress) {
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
return regFuture;
}
if (regFuture.isDone()) {
// At this point we know that the registration was complete and successful.
ChannelPromise promise = channel.newPromise();
doBind0(regFuture, channel, localAddress, promise);
return promise;
} else {
// Registration future is almost always fulfilled already, but just in case it's not.
final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
regFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
// nioEventLoop线程执行
Throwable cause = future.cause();
if (cause != null) {
// Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an
// IllegalStateException once we try to access the EventLoop of the Channel.
promise.setFailure(cause);
} else {
// Registration was successful, so set the correct executor to use.
// See https://github.com/netty/netty/issues/2586
promise.registered();
doBind0(regFuture, channel, localAddress, promise);
}
}
});
return promise;
}
}