博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring Boot系列--启动方法解析监听器
阅读量:4135 次
发布时间:2019-05-25

本文共 6825 字,大约阅读时间需要 22 分钟。

参考版本:2.0.8.RELEASE

启动方法run中运行监听器的启动

查找 jar包中META-INF/spring.factories中SpringApplicationRunListener的定义,如果只引入了springbootstarter包的话,这里只定义了一个监听器EventPublishingRunListener 

# Run Listeners

org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();

 SpringApplicationRunListeners:这个类是SpringApplicationRunListener的一个集合

public void starting() {   for (SpringApplicationRunListener listener : this.listeners) {      listener.starting();   }}

下面来看EventPublishingRunListener的starting方法

EventPublishingRunListener:继承了SpringApplicationRunListener,使用初始化好的事件广播器广播Application启动事件,这个类的接口实现主要有initialMulticaster来完成---装饰器模式

@Overridepublic void starting() {   this.initialMulticaster.multicastEvent(         new ApplicationStartingEvent(this.application, this.args));}

 接下来看是如果广播事件的:spring中的事件监控--观察者模式

SimpleApplicationEventMulticaster:是接口ApplicationEventMulticaster的一个简单实现类,将所有的事件广播给所有的监听器,每个监听器只关心自己要监听的事件,不关心的就会忽略。默认在调用(当前)的线程中调用监听器,如果定义了线程池就会在新的线程中调用。
@Overridepublic void multicastEvent(ApplicationEvent event) {   multicastEvent(event, resolveDefaultEventType(event));}@Overridepublic 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); } }}

从代码getApplicationListeners(event, type)的结果来看,有以下四种监听器都监听了ApplicationStartingEvent,接下来每种监听器逐个执行

/** * Invoke the given listener with the given event. * @param listener the ApplicationListener to invoke * @param event the current event to propagate * @since 4.1 */protected void invokeListener(ApplicationListener
listener, ApplicationEvent event) { ErrorHandler errorHandler = getErrorHandler(); if (errorHandler != null) { try { doInvokeListener(listener, event); } catch (Throwable err) { errorHandler.handleError(err); } } else { doInvokeListener(listener, event); }}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {   try {      listener.onApplicationEvent(event);//这句是重点啦,要到具体对应的监听器中查看   }   catch (ClassCastException ex) {      String msg = ex.getMessage();      if (msg == null || matchesClassCastMessage(msg, event.getClass())) {         // Possibly a lambda-defined listener which we could not resolve the generic event type for         // -> let's suppress the exception and just log a debug message.         Log logger = LogFactory.getLog(getClass());         if (logger.isDebugEnabled()) {            logger.debug("Non-matching event type for listener: " + listener, ex);         }      }      else {         throw ex;      }   }}

接下来一个个看每个监听器在监听事件发生后都做了哪些事情 :

1、DelegatingApplicationListener:委派监听器,委派给那些在环境属性context.listener.classes指定的那些监听器。

@Overridepublic void onApplicationEvent(ApplicationEvent event) {   if (event instanceof ApplicationEnvironmentPreparedEvent) {      List
> delegates = getListeners( ((ApplicationEnvironmentPreparedEvent) event).getEnvironment()); if (delegates.isEmpty()) { return; } this.multicaster = new SimpleApplicationEventMulticaster(); for (ApplicationListener
listener : delegates) { this.multicaster.addApplicationListener(listener); } } if (this.multicaster != null) { this.multicaster.multicastEvent(event); }}

2、LiquibaseServiceLocatorApplicationListener

3、BackgroundPreinitializer:对于一些耗时的任务使用一个后台线程尽早触发它们开始执行初始化,这是Springboot的缺省行为。这些初始化动作也可以叫做预初始化。 设置系统属性spring.backgroundpreinitializer.ignore为true可以禁用该机制。 该机制被禁用时,相应的初始化任务会发生在前台线程。

看看都做了哪些初始化任务:

// 记录预初始化任务是否已经在执行,初始值设置为false,表示未开始

    private static final AtomicBoolean preinitializationStarted = new AtomicBoolean(
            false);

    // 记录预初始化任务是否已经完成,1表示未完成,0表示完成

    private static final CountDownLatch preinitializationComplete = new CountDownLatch(1);

@Overridepublic void onApplicationEvent(SpringApplicationEvent event) {   if (event instanceof ApplicationStartingEvent         && preinitializationStarted.compareAndSet(false, true)) {           //如果当前事件是ApplicationStartingEvent,并且预初始化任务尚未执行            // 则 :将preinitializationStarted设置为预初始化任务开始执行;            // 开始执行预初始化任务;      performPreinitialization();   }   if ((event instanceof ApplicationReadyEvent         || event instanceof ApplicationFailedEvent)         && preinitializationStarted.get()) {      try {         preinitializationComplete.await();      }      catch (InterruptedException ex) {         Thread.currentThread().interrupt();      }   }}private void performPreinitialization() {   try {      Thread thread = new Thread(new Runnable() {         @Override         public void run() {            runSafely(new ConversionServiceInitializer());            runSafely(new ValidationInitializer());            runSafely(new MessageConverterInitializer());            runSafely(new MBeanFactoryInitializer());            runSafely(new JacksonInitializer());            runSafely(new CharsetInitializer());            preinitializationComplete.countDown();         }         public void runSafely(Runnable runnable) {            try {               runnable.run();            }            catch (Throwable ex) {               // Ignore            }         }      }, "background-preinit");      thread.start();   }   catch (Exception ex) {      // This will fail on GAE where creating threads is prohibited. We can safely      // continue but startup will be slightly slower as the initialization will now      // happen on the main thread.      preinitializationComplete.countDown();   }}
4、LoggingApplicationListener:配置日志系统。如果有logging.config配置文件,就使用它启动日志系统,如果没有就使用默认配置。 
@Overridepublic void onApplicationEvent(ApplicationEvent event) {   if (event instanceof ApplicationStartingEvent) {      onApplicationStartingEvent((ApplicationStartingEvent) event);   }   else if (event instanceof ApplicationEnvironmentPreparedEvent) {      onApplicationEnvironmentPreparedEvent(            (ApplicationEnvironmentPreparedEvent) event);   }   else if (event instanceof ApplicationPreparedEvent) {      onApplicationPreparedEvent((ApplicationPreparedEvent) event);   }   else if (event instanceof ContextClosedEvent && ((ContextClosedEvent) event)         .getApplicationContext().getParent() == null) {      onContextClosedEvent();   }   else if (event instanceof ApplicationFailedEvent) {      onApplicationFailedEvent();   }}

本文通过查看监听器启动方法了解到springboot的一些内置监听器的作用,有一篇博客写的非常详细可参考:

转载地址:http://grivi.baihongyu.com/

你可能感兴趣的文章
RunTime.getRuntime().exec()
查看>>
Oracle 分组排序函数
查看>>
删除weblogic 域
查看>>
VMware Workstation 14中文破解版下载(附密钥)(笔记)
查看>>
日志框架学习
查看>>
日志框架学习2
查看>>
SVN-无法查看log,提示Want to go offline,时间显示1970问题,error主要是 url中 有一层的中文进行了2次encode
查看>>
NGINX
查看>>
Qt文件夹选择对话框
查看>>
1062 Talent and Virtue (25 分)
查看>>
1061 Dating (20 分)
查看>>
1060 Are They Equal (25 分)
查看>>
83. Remove Duplicates from Sorted List(easy)
查看>>
88. Merge Sorted Array(easy)
查看>>
leetcode刷题191 位1的个数 Number of 1 Bits(简单) Python Java
查看>>
leetcode刷题198 打家劫舍 House Robber(简单) Python Java
查看>>
NG深度学习第一门课作业2 通过一个隐藏层的神经网络来做平面数据的分类
查看>>
leetcode刷题234 回文链表 Palindrome Linked List(简单) Python Java
查看>>
NG深度学习第二门课作业1-1 深度学习的实践
查看>>
Ubuntu下安装Qt
查看>>