spring源码学习之容器监听器篇
2017-04-12 13:32
363 查看
一、监听器相关接口
1、ApplicationEventPublisher容器的事件发布者//该接口规范了发布事件的基本功能 public interface ApplicationEventPublisher { /** * 发布事件 */ void publishEvent(ApplicationEvent event); /** * 发布事件 */ void publishEvent(Object event); }
2、ApplicationEvent事件基类
//不同的事件继承自这个类 通过instanceof运算符来区分到底产生的是什么事件 public abstract class ApplicationEvent extends EventObject { ... }
3、ApplicationEventMulticaster事件传播者
//该接口定义了一些监听器的增删改的方法可以参考下jdk的java.util.Observable很相像 public interface ApplicationEventMulticaster { ... }
4、ApplicationListener事件监听器接口
//实现了该接口 就可以监听容器产生的相关事件了 public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * 当容器中发布事件时,其实就是通过ApplicationEventMulticaster的实现类遍历监听器调用的该方法 */ void onApplicationEvent(E event); }
5、事件类型
二、容器中监听器相关接口的实现
1、ApplicationEventPublisher事件发布者ApplicationContextspring在AbstractApplicationContext中实现了ApplicationEventPublisher相关功能
通过下面的代码可以看出其实ApplicationEventPublisher中的事件最终是由ApplicationEventMulticaster
来实现事件发布的
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean { ... @Override public void publishEvent(ApplicationEvent event) { publishEvent(event, null); } @Override public void publishEvent(Object event) { publishEvent(event, null); } protected void publishEvent(Object event, ResolvableType eventType) { Assert.notNull(event, "Event must not be null"); if (logger.isTraceEnabled()) { logger.trace("Publishing event in " + getDisplayName() + ": " + event); } // 在这里确定要发布的事件对象 ApplicationEvent applicationEvent; if (event instanceof ApplicationEvent) { applicationEvent = (ApplicationEvent) event; } else { applicationEvent = new PayloadApplicationEvent<Object>(this, event); if (eventType == null) { eventType = ResolvableType.forClassWithGenerics(PayloadApplicationEvent.class, event.getClass()); } } // 在这里委托ApplicationEventMulticaster进行事件发布 if (this.earlyApplicationEvents != null) { //在注册完毕监听器时会将这里的事件发布出去然后置为null(防止publish的事件在注册监听器之前广播) this.earlyApplicationEvents.add(applicationEvent); } else { //获取容器的广播者进行事件广播 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); } // Publish event via parent context as well... if (this.parent != null) { if (this.parent instanceof AbstractApplicationContext) { ((AbstractApplicationContext) this.parent).publishEvent(event, eventType); } else { this.parent.publishEvent(event); } } } }
2、ApplicationEvent实现
//从这里可以看出事件的实现并没有定义太多功能,更多的只是作为一种标示,利用类来表示是什么事件而已 //当然也可以定义一些字段来传递信息 public class ContextStartedEvent extends ApplicationContextEvent { public ContextStartedEvent(ApplicationContext source) { super(source); } }
3、ApplicationEventMulticaster的实现AbstractApplicationEventMulticaster、SimpleApplicationEventMulticaster
AbstractApplicationEventMulticaster提供一个基本的事件广播的监听器的增删功能,而广播事件
multicastEvent(ApplicationEvent event)
multicastEvent(ApplicationEvent event, ResolvableType eventType)
的方法交给交给了子类SimpleApplicationEventMulticaster来实现
ResolvableType 这个类其实就是封装的java.lang.reflect.Type
4000 //实现事件广播 public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster { ... @Override public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) { //如果定义了事件类型则只判断支持该类型的监听器进行广播事件(判断是否支持通过子接口里的supportsEventType(ResolvableType eventType)进行判断的) ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(new Runnable() { @Override public void run() { //在这里就是调用listener.onApplicationEvent(event)方法通知监听器 invokeListener(listener, event); } }); } else { invokeListener(listener, event); } } } ... }
4、ApplicationListener的实现
其实到这里 就是可以任意扩展的地方啦,只要你的对象是交给Spring容器管理的,在容器
初始化时就会注册监听器,然后在容器发布事件的时候就能接收到相应的事件了
这里看一下SqlSessionFactoryBean的实现:
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> { ... @Override public void onApplicationEvent(ApplicationEvent event) { //这里由于容器产生任何事件都会调用该方法,所以使用instanceof 来区分是什么事件。 if (failFast && event instanceof ContextRefreshedEvent) { // fail-fast -> check all statements are completed this.sqlSessionFactory.getConfiguration().getMappedStatementNames(); } } ... }
总结:
其实监听器就是观察者模式的实现,可以参考jdk提供的java.util.Observable,java.util.Observer就更能理解spring在这里的设计,spring将各个环节都进行了接口抽象,而且在实现时也会使用abstract类进行具有通用性的方法进行分层实现,使得很多方法就更具有复用性,当然这样扩展性也提现出来了,如果有特殊需求,可以继承一下就得到了很多基本功能,很好的提现了从抽象到具体的面向对象的设计思想。而像getTaskExecutor()这种获取一些对象通过一个protected的get方法来获取,使得程序的灵活性大大的提高了,充分的利用多态的特性。
相关文章推荐
- Spring源码学习-容器初始化之FileSystemXmlApplicationContext(二)路径格式及解析方式(上) 推荐
- Spring源码学习-容器初始化之FileSystemXmlApplicationContext(一)构造函数
- spring源码初步学习-容器的功能扩展(ApplicationContext)
- Spring IOC学习心得之源码级分析ContextLoaderListener的作用(IOC容器初始化入口)
- Spring源码学习之:模拟实现BeanFactory,从而说明IOC容器的大致原理
- spring源码学习之路---深度分析IOC容器初始化过程(四)
- Spring 源码学习(二) IOC容器启动过程
- spring源码初步学习-自己实现的ioc容器结构
- spring3 bean容器相关源码学习----ApplicationContext接口
- spring源码学习之路---IOC容器初始化要义之bean定义载入(五)
- spring源码学习之路---深度分析IOC容器初始化过程(四)
- Spring源码学习(一) IOC容器
- spring源码学习之路---IOC容器初始化要义之bean定义载入
- Spring源码学习-4.IoC容器其他特征分析
- Spring源码学习-容器初始化之FileSystemXmlApplicationContext(一)构造函数 推荐
- spring源码学习之路---IOC容器初始化要义之bean定义载入(五)
- Spring源码学习IOC(3):IoC容器载入Bean定义资源文件
- Spring源码学习IOC(4):IoC容器解析Bean定义资源并注册解析后的Bean
- Spring源码学习之容器的功能扩展
- spring源码学习之:spring容器的applicationContext启动过程