SpringBoot启动过程源码解析(二)--------------- listener.starting及监听模式的实现
上一篇讲了SpringBoot启动过程中, SpringApplication实例化之后,现在正式进入到 SpringApplication.run 方法中,看一看启动过程中,SpringBoot到底做了些什么。
本篇博客先讲到 listener.starting() , 通过这个方式 讲一讲 监听器设计模式。
先看,Run方法
[code]public ConfigurableApplicationContext run(String... args) { // 监控启动过程中耗费时间 StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; // 输出启动过程中的异常 Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); // 设置 java.awt.headless , 具体情况另行查阅 configureHeadlessProperty(); // 加载 SpringApplicationRunListener SpringApplicationRunListeners listeners = getRunListeners(args); // 发布事件启动开始事件,广播通知各监听器 listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }
先看一个重要的方法 : getRunListeners(args) , 这个方法是从 META-INF/spring.factories文件中加载 SpringApplicationRunListener实现类。目前SpringApplicationRunListener 唯一实现类为EventPublishingRunListener。
[code]private SpringApplicationRunListeners getRunListeners(String[] args) { // 将命令行参数继续往下传递.通过 class 类型加载,根据实例化工厂加载所需类 Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)); }
通过实例化工厂, SpringApplicationRunListener.class 类型,再META-INF/spring.factories文件下加载类名,实例化EventPublishingRunListener对象。 加载过程细节已在上一篇种讲述,不再赘述。
接下来就是重要的事件发布方法。 listeners.staring()
SpringApplicationRunListeners维护着一个List<SpringApplicationRunListener>集合,方便统一调用RunListener starting()方法。
我们可以自定义一个Listener 实现 SpringApplicationRunListener接口,并注册到META-INF/spring.factories 自己实现启动过程的事件逻辑。EventPublishingRunListener 作为官方唯一实现类。
EventPublishingRunListener种持有SimleApplicationEventMulticaster对象,用于广播发布事件。
[code]@Override public void starting() { // 以广播形式发布 ApplicationStaringEvent事件 this.initialMulticaster.multicastEvent( new ApplicationStartingEvent(this.application, this.args)); }
[code]public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(() -> invokeListener(listener, event)); } else { invokeListener(listener, event); } } }
在发布事件种有重要方法, getAppllicationListeners()
[code]protected Collection<ApplicationListener<?>> getApplicationListeners( ApplicationEvent event, ResolvableType eventType) { Object source = event.getSource(); Class<?> sourceType = (source != null ? source.getClass() : null); // 内部类缓存储存 事件类型 ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType); // Quick check for existing entry on ConcurrentHashMap... // 先检查缓存中是否存在 ListenerRetriever retriever = this.retrieverCache.get(cacheKey); if (retriever != null) { return retriever.getApplicationListeners(); } if (this.beanClassLoader == null || (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) { // Fully synchronized building and caching of a ListenerRetriever synchronized (this.retrievalMutex) { retriever = this.retrieverCache.get(cacheKey); if (retriever != null) { return retriever.getApplicationListeners(); } retriever = new ListenerRetriever(true); Collection<ApplicationListener<?>> listeners = retrieveApplicationListeners(eventType, sourceType, retriever); this.retrieverCache.put(cacheKey, retriever); return listeners; } } else { // No ListenerRetriever caching -> no synchronization necessary return retrieveApplicationListeners(eventType, sourceType, null); } }
先存缓存中判断是否存在 监听器, 如何没有,调用 retrieveApplicationListeners 方法获取。
在实例化EventPublishingRunListener 构造函数中,已将SpringApplication 构造函数中加载的10个Listeners 放入ListenerRriever中,并删除了缓存中 retrieveCache中的数据。
[code]private Collection<ApplicationListener<?>> retrieveApplicationListeners( ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) { List<ApplicationListener<?>> allListeners = new ArrayList<>(); Set<ApplicationListener<?>> listeners; Set<String> listenerBeans; synchronized (this.retrievalMutex) { listeners = n 3ff7 ew LinkedHashSet<>(this.defaultRetriever.applicationListeners); listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans); } for (ApplicationListener<?> listener : listeners) { if (supportsEvent(listener, eventType, sourceType)) { if (retriever != null) { retriever.applicationListeners.add(listener); } allListeners.add(listener); } } if (!listenerBeans.isEmpty()) { BeanFactory beanFactory = getBeanFactory(); for (String listenerBeanName : listenerBeans) { try { Class<?> listenerType = beanFactory.getType(listenerBeanName); if (listenerType == null || supportsEvent(listenerType, eventType)) { ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class); if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) { if (retriever != null) { if (beanFactory.isSingleton(listenerBeanName)) { retriever.applicationListeners.add(listener); } else { retriever.applicationListenerBeans.add(listenerBeanName); } } allListeners.add(listener); } } } catch (NoSuchBeanDefinitionException ex) { // Singleton listener instance (without backing bean definition) disappeared - // probably in the middle of the destruction phase } } }
通过 ApplicationStartingEvent事件类型,过滤出对一个事件的 监听器,并发布事件。
supportsEvent()方法中。用到适配器设计模式,传入事件类型与监听器进行判断。
[code]protected boolean supportsEvent( ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) { GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ? (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener)); return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType)); }
筛选中出监听器后,调用 invokeListener方法通知监听器,监听器做出相应动作。
浅谈监听器模式 :
监听器模式的三要素: 事件源,事件,监听器
事件源 : 需要被监听器的对象。
事件: 对事件源的封装。
监听器: 被监听对象改变后,做出相应动作。
在启动过程中 ,
SpringApplicaton 就是事件源
ApplicationStartingEvent 是事件
ApplicationListeners 为监听器
SpringApplicationRunListener 可以理解成 ListenerManager
- OpenStack建立实例完整过程源码详细分析(13)----依据AMQP通信架构实现消息发送机制解析之二
- 【cs229-Lecture2】Gradient Descent 最小二乘回归问题解析表达式推导过程及实现源码(无需迭代)
- Spring源码解析之:Spring Security启动细节和工作模式
- Mybatis 源码解析二、Mapper接口的代理实现过程 MapperScannerConfigurer 解析
- OpenStack Cinder服务启动过程中的资源加载和扩展源码解析之三
- Android 通过源码解析 Fragment 启动过程
- Activity的启动过程之startActivity源码解析
- Android 插件化开发——应用的启动过程源码解析(简单清晰)
- Springboot实现Java邮件任务过程解析
- azkaban源码解读(二):观察者模式在job执行过程中事件监听应用
- day31:Driver在Cluster模式下的启动、两种不同的资源调度方式源码彻底解析、资源调度
- Android源码解析四大组件系列(一)---Service的启动过程分析
- 源码解析:Activity启动过程全解析
- spring 实现IOC过程源码解析<一>
- Android源码解析之新进程中启动自定义服务过程(startService)的原理分析
- AES源码(java)实现过程解析
- SpringBoot启动过程源码分析
- Tomcat源码分析三:Tomcat启动加载过程(一)的源码解析
- 设计模式精解-GoF 23种设计模式解析附C++实现源码
- 常见设计模式的解析和实现(C++)文档及源码打包下载