springboot 启动分析二


承接上一篇启动分析一,继续学习springboot的启动原理,本文主要讲解springboot的事件发布

静态启动 run 方法

重点分析一下这个run方法,springboot就是通过这个静态的run方法引导启动spring应用程序的

/**
 * 静态方法被使用从指定的资源,使用默认的配置,去启动一个Spring 应用程序
 * @param primarySource 加载的主要资源
 * @param args 应用程序参数,通常从Java主方法中传递过来
 * @return 正在运行的的应用程序上下文
 */
public static ConfigurableApplicationContext run(Class<?> primarySource,
        String... args) {
    // 调用重载的run方法,将单一主资源转为数据
    return run(new Class<?>[] { primarySource }, args);
}

// 重载的run方法,参数均为数组形式
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
        String[] args) {
    // 在这里new了一个SpringApplication对象,实例化成功后调用实例run方法
    return new SpringApplication(primarySources).run(args);
}

这里提以下,静态run方法有2个重载方法

run重载方法

而上图中的第三个run方法,是一个实例方法,并非静态方法,这样就能保证在调用最终的实例run方法之前一定已经实例化了SpringApplication对象,而实例化SpringApplication则必须传入要加载的主资源。可见如果主资源为空,是无法启动SpringBoot应用程序的

我们这里主要看这个run(String... args)的内部实现

/**
 * 运行spring 应用程序,创建和刷新一个新的应用上下文
 *
 * @param args the application arguments (usually passed from a Java main method)
 * @return 一个运行中的应用上下文实例
 */
public ConfigurableApplicationContext run(String... args) {

    // 声明并实例化一个跑表,用于计算springboot应用程序启动时间
    StopWatch stopWatch = new StopWatch();

    // 启动跑表
    stopWatch.start();

    // 声明一个应用程序上下文,注意这里是一个接口声明
    ConfigurableApplicationContext context = null;

    // 声明一个集合,用于记录springboot异常报告
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();

    // 配置不在意的属性 java.awt.headless
    configureHeadlessProperty();

    // 获取用于监听spring应用程序run方法的监听器实例
    SpringApplicationRunListeners listeners = getRunListeners(args);

    // 循环启动用于run方法的监听器
    listeners.starting();
    try {
        // 封装应用参数
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                args);

        // 根据SpringApplication实例化时候推断出来的应用类型 webApplicationType,
        // 去获取不同的环境,然后获取配置要适用的PropertySource以及激活哪个Profile
        ConfigurableEnvironment environment = prepareEnvironment(listeners,
                applicationArguments);

        // 根据环境配置需要忽略的bean的信息
        configureIgnoreBeanInfo(environment);

        // 根据环境配置打印banner,即根据bannerMode 枚举值,决定是否打印banner和banner打印的位置
        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;
}

重点分析run方法

  1. 启动一个跑表计时器,用于记录springboot应用上下文创建所消耗的时间

  2. 开启所有的springApplicationRunListener 监听器,用于监听springboot应用加载与启动信息

      /**
          * SpringApplication类私有的获取Run方法监听器
          *
          * @param args main 方法的参数
          * @return org.springframework.boot.SpringApplicationRunListeners 
          * @date 14:04 2018/9/26
          */
         private SpringApplicationRunListeners getRunListeners(String[] args) {
             // new 一个参数类型Class数组,传入用于构建run方法监听器实例的参数
             Class<?>[] types = new Class<?>[]{SpringApplication.class, String[].class};
     
             // new SpringApplicationRunListeners 
             return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
         }
    

getSpringFactoriesInstances(...)

getSpringFactoriesInstances方法是不是很熟悉,就是从spring.factories文件中加载指定key对应的class 实例

截取自springboot项目下的spring.factories文件

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

也就是这里的getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));会反射实例化EventPublishingRunListener对象。

看下这里EventPublishingRunListener对象的定义,其实现了SpringApplicationRunListener接口以及Ordered接口

SpringApplicationRunListener 接口的定义

/**
 * 定义SpringApplication run方法监听器,每一次SpringApplication的run方法的运行都会实例化一个    SpringApplicationRunListener的实例,
 * SpringApplicationRunListener接口的派生类应该提供一个公开的构造器,接收一个SpringApplication 参    数实例,以及一个String[]参数。
 * <p>
 * 接口定义:
 * 定义应该监听spring应用程序的run方法哪些点,比如刚开始调用run方法的时机,比如应用环境准备好,    但是应用程序上下文还没有被创建的时机等等
 *
 * @author Phillip Webb
 * @author Dave Syer
 * @author Andy Wilkinson
 */
public interface SpringApplicationRunListener {

/**
 * 当run方法首次启动时立即调用。可以用来做早期的初始化。
 */
void starting();

/**
 * 一旦环境准备好之后,且ApplicationContext被创建之前被调用
 *
 * @param environment the environment
 */
void environmentPrepared(ConfigurableEnvironment environment);

/**
 * Called once the {@link ApplicationContext} has been created and prepared, but
 * before sources have been loaded.
 * 当ApplicationContext 被创建已准备好,但是sources还没有被加载时被调用
 *
 * @param context the application context
 */
void contextPrepared(ConfigurableApplicationContext context);

/**
 * Called once the application context has been loaded but before it has been
 * refreshed.
 * 当应用程序上下文已经被加载但是还没有被刷新时调用
 *
 * @param context the application context
 */
void contextLoaded(ConfigurableApplicationContext context);

/**
 * The context has been refreshed and the application has started but
 * {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner
 * ApplicationRunners} have not been called.
 * 当应用程序上下文被刷新和应用已经启动完成,但是CommandLineRunner 和 ApplicationRunner 还没有被调用时调用started方法
 *
 * @param context the application context.
 * @since 2.0.0
 */
void started(ConfigurableApplicationContext context);

/**
 * Called immediately before the run method finishes, when the application context has
 * been refreshed and all {@link CommandLineRunner CommandLineRunners} and
 * {@link ApplicationRunner ApplicationRunners} have been called.
 * 当run方法结束后立即调用,当应用程序上下文已经被刷新和所有的CommandLineRunners 和 ApplicationRunners也已经被调用
 *
 * @param context the application context.
 * @since 2.0.0
 */
void running(ConfigurableApplicationContext context);

/**
 * Called when a failure occurs when running the application.
 * 当应用程序启动失败时调用
 *
 * @param context   the application context or {@code null} if a failure occurred before
 *                  the context was created
 * @param exception the failure
 * @since 2.0.0
 */
void failed(ConfigurableApplicationContext context, Throwable exception);

}

该接口定义的很多在run方法执行的时候哪些时机需要被监听,比如run方法刚调用时,environment 环境准备好,但应用程序上下文还没有创建时,应用程序启动失败时等等

EventPublishingRunListener 类

下面看其唯一的实现类 EventPublishingRunListener 类定义

其实可以将EventPublishingRunListener 理解为一个事件发布者,而发布的方式就是使用内部定义的一个ApplicationEventMulticaster 应用程序事件广播器,当事件发布者初始化时就会实例化一个广播器,并将spring.factories中定义的所有应用监听器(观察者)添加进来。就好像广播器需要知道我发布事件时需要发布给哪些订阅者(观察者)。

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
// Spring应用
private final SpringApplication application;
// main方法参数
private final String[] args;
// 应用事件广播器 
private final SimpleApplicationEventMulticaster initialMulticaster;

// 构造器,传入SpringApplication实例,以及main方法的参数
public EventPublishingRunListener(SpringApplication application, String[] args) {
    this.application = application;
    this.args = args;
    // 初始化一个ApplicationEventMulticaster (应用事件广播)实例来处理触发事件
    this.initialMulticaster = new SimpleApplicationEventMulticaster();
    
    // 将spring.factories文件中定义的所有key为 ApplicationListener 的监听器(观察者)都加入到需要广播的列表中
    // 即这里可以看做是找到有哪些的观察者,以便在我被观察目标状态发生变化时,我可以通过应用事件广播器将事件全部广播给观察者
    for (ApplicationListener<?> listener : application.getListeners()) {
        this.initialMulticaster.addApplicationListener(listener);
    }
}

}

介绍一下 SimpleApplicationEventMulticaster 类

SimpleApplicationEventMulticaster 类的定义

Simple implementation of the ApplicationEventMulticaster interface.
Multicasts all events to all registered listeners, leaving it up to
the listeners to ignore events that they are not interested in.
Listeners will usually perform corresponding {@code instanceof}
checks on the passed-in event object.
By default, all listeners are invoked in the calling thread.
This allows the danger of a rogue listener blocking the entire application,
but adds minimal overhead. Specify an alternative task executor to have
listeners executed in different threads, for example from a thread pool.

ApplicationEventMulticaster 应用事件广播器接口的一个简单实现类, 广播所有的事件给所有注册的监听器(观察者)们,监听器们可以忽略他们不感兴趣的事件,监听器会执行相应的instanceof去检查传入的事件对象是否是其感兴趣的
默认情况下,在调用线程中调用所有的监听器(即这里会用当前线程调用,非异步),这样就有可能出现流氓监听器阻塞整个应用程序的危险情况,也可以定义一个线程池,将监听器在不同的线程中执行,这样可以带来一个最小的开销。

接口 ApplicationEventMulticaster 应用事件广播器

Interface to be implemented by objects that can manage a number of ApplicationListener objects, and publish events to them.
应用事件广播器的实现类可以管理应用监听器对象们,并发布事件给他们

定义了如下方法,如添加一个监听器以通知它所有的事件,从通知列表中删除指定的监听器,删除所有注册到这个广播器的监听器,以及广播指定事件等方法。

public interface ApplicationEventMulticaster {

/**
 * Add a listener to be notified of all events.
 * @param listener the listener to add
 */
void addApplicationListener(ApplicationListener<?> listener);

/**
 * Add a listener bean to be notified of all events.
 * @param listenerBeanName the name of the listener bean to add
 */
void addApplicationListenerBean(String listenerBeanName);

/**
 * Remove a listener from the notification list.
 * @param listener the listener to remove
 */
void removeApplicationListener(ApplicationListener<?> listener);

/**
 * Remove a listener bean from the notification list.
 * @param listenerBeanName the name of the listener bean to add
 */
void removeApplicationListenerBean(String listenerBeanName);

/**
 * Remove all listeners registered with this multicaster.
 * <p>After a remove call, the multicaster will perform no action
 * on event notification until new listeners are being registered.
 */
void removeAllListeners();

/**
 * Multicast the given application event to appropriate listeners.
 * <p>Consider using {@link #multicastEvent(ApplicationEvent, ResolvableType)}
 * if possible as it provides a better support for generics-based events.
 * @param event the event to multicast
 */
void multicastEvent(ApplicationEvent event);

/**
 * Multicast the given application event to appropriate listeners.
 * <p>If the {@code eventType} is {@code null}, a default type is built
 * based on the {@code event} instance.
 * @param event the event to multicast
 * @param eventType the type of event (can be null)
 * @since 4.2
 */
void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);

}

下面看其实现类,AbstractApplicationEventMulticaster 抽象类和派生类 SimpleApplicationEventMulticaster

SimpleApplicationEventMulticaster 简单应用事件广播器

发布事件方法定义:参数为需要发布的事件类型

@Override
public void multicastEvent(ApplicationEvent event) {
    multicastEvent(event, resolveDefaultEventType(event));
}

事件发布

run 方法启动事件发布 listeners.starting();

当SpringApplication 的run方法首次启动时, 就应该调用SpringApplicationRunListener 的starting方法,所以调用该方法

SpringApplicationRunListeners 类中调用starting()如下所示

// 该类就是一个简单的SpringApplicationRunListener的集合类而已
// 后续如果扩展了多个run方法的监听器就会满足需求了
class SpringApplicationRunListeners {

private final Log log;

private final List<SpringApplicationRunListener> listeners;

SpringApplicationRunListeners(Log log,
        Collection<? extends SpringApplicationRunListener> listeners) {
    this.log = log;
    this.listeners = new ArrayList<>(listeners);
}

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

这里就是简单的for循环进行run 方法启动事件发布,继续向下看,调用SpringApplicationRunListener实现类EventPublishingRunListener的方法 starting()

@Override
public void starting() {
    // 利用实例属性-初始化广播器去广播事件(ApplicationStartingEvent 应用正在启动事件)
    // 之前的分析我们知道了在EventPublishingRunListener实例化的时候就已经在其实例属性-初始化广播器中加入了所有的观察者(应用监听器)。
    this.initialMulticaster.multicastEvent(
            new ApplicationStartingEvent(this.application, this.args));
}

继续向下看,调用SimpleApplicationEventMulticastermulticastEvent(ApplicationEvent event)方法

@Override
public void multicastEvent(ApplicationEvent event) {
    multicastEvent(event, resolveDefaultEventType(event));
}

调用了私有的resolveDefaultEventType(ApplicationEvent event) 方法,解决默认的事件泛型类型
jdk从1.5开始提供了用于表示泛型类型的几个实现类,接口为Type

private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
    return ResolvableType.forInstance(event);
}

该方法返回了一个封装了事件的默认类型(ApplicationStartingEvent)的ResolvableType对象

接下去看SimpleApplicationEventMulticaster类提供的发布事件的核心方法,该方法是接口ApplicationEventMulticaster中定义的方法的实现

@Override
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);
        }
    }
}
  1. 判断这里的事件的类型是否为null,为null就再去resolveDefaultEventType方法以获取一次事件的ResolvableType类型

  2. 遍历将事件发布给需要关心该事件的监听器,通过getApplicationListeners(event, type)方法获取这些关心该事件的监听器列表,有几个监听器,就遍历几次发布事件

  3. 每一次事件发布,都会去获取一次是否有针对该发布的任务执行器(异步),如果有,就交给任务执行器异步去发布事件给这个监听器,否则就是同步发布事件

下面分析如何获取关心该事件的监听器列表方法,getApplicationListeners(event, type)

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);
    }
}

方法定义:
返回匹配给定事件的应用监听器列表,不匹配的监听器被排除在外,基于缓存的匹配信息,这里用到了缓存。代码上会分析

  1. 获取事件源,即事件最初发生的地方,即SpringApplication对象

jdk1.1提供的事件对象EventObject类中的source属性,就是事件源,Spring启动的每一个应用事件(ApplicationEvent抽象类继承自EventObject)在被创建的时候都会初始化其事件发生的源

  1. 获取事件源的class类型,判断事件源是否为空,不为空就取其class类型,否则为null

  2. new一个ListenerCacheKey对象,该对象有两个属性,分别为事件的resolvableType类型,一个是事件源的class类型。

  3. 根据3中new出的ListenerCacheKey对象,去广播器的缓存retrieverCache 中获取是否有针对该key的ListenerRetriever缓存

  4. 如果缓存不为空,直接返回缓存的ListenerRetriever 对象中保存的目标监听器集合

该类为AbstractApplicationEventMulticaster 的内部类,类定义就是帮助保存不同的事件下的特定关心的监听器列表,其有一个属性为final修饰的Set<ApplicationListener<?>> applicationListeners; 就是保存特定的监听器列表的。

  1. 如果key对应的缓存为空,则完全同步地构建和缓存一个ListenerRetriever,new一个ListenerRetriever对象,调用retrieveApplicationListeners(eventType, sourceType, retriever);方法获取关心的目标监听器列表,并将其put进缓存中,后返回该监听器列表。

  2. 看retrieveApplicationListeners(eventType, sourceType, retriever);该方法是AbstractApplicationEventMulticaster类的一个私有的方法,就是根据
    指定的eventType, sourceType, 获取整个监听器列表中,关心该事件的监听器,并存入传入的retriever对象的applicationListeners集合属性中。

    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 = new 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) {
                             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
             }
         }
     }
     AnnotationAwareOrderComparator.sort(allListeners);
     return allListeners;
    

    }

注意一下如何匹配监听器到底是不是关心该事件的监听器就看supportsEvent(listener, eventType, sourceType)方法的判断结果是否为true,根据判断监听器是否是GenericApplicationListener类型,如果是就调用自己重写的supportsEventType(ResolvableType resolvableType)方法和supportsSourceType(Class<?> sourceType)方法进行判断

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));
}

比如LoggingApplicationListener 日志监听器其实现了GenericApplicationListener接口,其内部属性定义的EVENT_TYPES 如下

private static final Class<?>[] EVENT_TYPES = { ApplicationStartingEvent.class,
ApplicationEnvironmentPreparedEvent.class, ApplicationPreparedEvent.class,
ContextClosedEvent.class, ApplicationFailedEvent.class };

private static final Class<?>[] SOURCE_TYPES = { SpringApplication.class,
ApplicationContext.class };

@Override
public boolean supportsEventType(ResolvableType resolvableType) {
    return isAssignableFrom(resolvableType.getRawClass(), EVENT_TYPES);
}

@Override
public boolean supportsSourceType(Class<?> sourceType) {
    return isAssignableFrom(sourceType, SOURCE_TYPES);
}

private boolean isAssignableFrom(Class<?> type, Class<?>... supportedTypes) {
    if (type != null) {
        for (Class<?> supportedType : supportedTypes) {
            if (supportedType.isAssignableFrom(type)) {
                return true;
            }
        }
    }
    return false;
}

isAssignableFrom(type) 方法为一个native方法,就是比较类型是否匹配(超类)

public native boolean isAssignableFrom(Class<?> cls);

到这里已经获取到了指定事件对应的目标监听器列表了,回到之前的发布事件的方法,开始遍历发布事件给这些监听器

具体发布事件方法 invokeListener(listener, event)

在执行具体的发布事件方法之前,会先判断事件广播器是否自定义的任务执行器(异步),如果没有就执行同步发布,否则交给任务执行器异步execute(Runnable runnable)开启一个新的线程发布事件。

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);
    }
}
  1. 获取该事件广播器的异常处理器errorHandler

  2. 判断异常处理器是否为null,不是的话就说明自定义了异常处理器,那么就将doInvokeListener(listener, event);方法try一下,在catch中调用自定义的异常处理器errorHandler.handlerError(err)方法,否则就不用try catch处理

  3. 继续看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().getName())) {
             // 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;
         }
     }
    

    }

  4. 终于在这里执行了各个listener的onApplicationEvent(event)方法,让各个监听器执行。

  5. 这里看一下catch的部分,由于各个监听器会在自己的onApplicationEvent方法实现中处理自己关心的各种事件,比如LoggingApplicationListener监听器就关注ApplicationStartingEvent事件,ApplicationEnvironmentPreparedEvent事件,ApplicationPreparedEvent事件等,所以会在其onApplicationEvent将传入的ApplicationEvent事件进行类型转换,就可能会抛出类型转换异常,如果抛出了此异常,那么就向上继续抛,否则如果是lambda定义的监听器,springboot是无法处理通用事件的,这里只是简单的debug记录一下日志。

  6. 举例贴一下LoggingApplicationListener的onApplicationEvent方法

     public 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();
     }
     }
    
     private void onApplicationStartingEvent(ApplicationStartingEvent event) {
     this.loggingSystem = LoggingSystem
             .get(event.getSpringApplication().getClassLoader());
     this.loggingSystem.beforeInitialize();
     }
    

这里就是做一写日志上下文的初始化之前的工作,即日志应用监听器在ApplicationStartingEvent事件上做的处理就是这些。

总结

以上源码解读主要讲解的关于springboot在执行run方法之初关于发布ApplicationStartingEvent事件的整个流程,后续会进行run方法后面的源码学习。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 事件和平时所用的回调思想在与GUI(JavaScript,Swing)相关的技术中非常流行。而在Web应用程序的服...
    Java小铺阅读 1,072评论 0 0
  • EventBus基本使用 EventBus基于观察者模式的Android事件分发总线。 从这个图可以看出,Even...
    顾氏名清明阅读 616评论 0 1
  • 项目到了一定阶段会出现一种甜蜜的负担:业务的不断发展与人员的流动性越来越大,代码维护与测试回归流程越来越繁琐。这个...
    fdacc6a1e764阅读 3,158评论 0 6
  • 2016年9月中旬,有几个睡觉睡眠质量不好,我自己也不明白个中原因。9月18日在医院陪老妈时,我请来帮老妈量血压的...
    愫姐阅读 368评论 0 0