本文次要钻研一下springboot的启动事件

SpringApplicationEvent

org/springframework/boot/context/event/SpringApplicationEvent.java

public abstract class SpringApplicationEvent extends ApplicationEvent {    private final String[] args;    public SpringApplicationEvent(SpringApplication application, String[] args) {        super(application);        this.args = args;    }    public SpringApplication getSpringApplication() {        return (SpringApplication) getSource();    }    public final String[] getArgs() {        return this.args;    }}
SpringApplicationEvent继承了ApplicationEvent,它有几个子类分表是ApplicationStartingEvent、ApplicationEnvironmentPreparedEvent、ApplicationContextInitializedEvent、ApplicationPreparedEvent、ApplicationStartedEvent、ApplicationReadyEvent,期间有异样则抛出ApplicationFailedEvent

SpringApplication.run

org/springframework/boot/SpringApplication.java

    public ConfigurableApplicationContext run(String... args) {        StopWatch stopWatch = new StopWatch();        stopWatch.start();        ConfigurableApplicationContext context = null;        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();        configureHeadlessProperty();        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;    }
SpringApplication的run办法,先触发listeners.starting(),而后执行了prepareEnvironment,之后createApplicationContext,再进行prepareContext和refreshContext,最初触发listeners.started(context),之后执行callRunners,最初触发listeners.running(context),如有异样则会执行handleRunFailure

prepareEnvironment

    private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,            ApplicationArguments applicationArguments) {        // Create and configure the environment        ConfigurableEnvironment environment = getOrCreateEnvironment();        configureEnvironment(environment, applicationArguments.getSourceArgs());        ConfigurationPropertySources.attach(environment);        listeners.environmentPrepared(environment);        bindToSpringApplication(environment);        if (!this.isCustomEnvironment) {            environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,                    deduceEnvironmentClass());        }        ConfigurationPropertySources.attach(environment);        return environment;    }
prepareEnvironment会触发listeners.environmentPrepared(environment),即公布ApplicationEnvironmentPreparedEvent

prepareContext

    private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,            SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {        context.setEnvironment(environment);        postProcessApplicationContext(context);        applyInitializers(context);        listeners.contextPrepared(context);        if (this.logStartupInfo) {            logStartupInfo(context.getParent() == null);            logStartupProfileInfo(context);        }        // Add boot specific singleton beans        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);        if (printedBanner != null) {            beanFactory.registerSingleton("springBootBanner", printedBanner);        }        if (beanFactory instanceof DefaultListableBeanFactory) {            ((DefaultListableBeanFactory) beanFactory)                    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);        }        if (this.lazyInitialization) {            context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());        }        // Load the sources        Set<Object> sources = getAllSources();        Assert.notEmpty(sources, "Sources must not be empty");        load(context, sources.toArray(new Object[0]));        listeners.contextLoaded(context);    }
prepareContext会触发listeners.contextPrepared(context),即公布ApplicationContextInitializedEvent,执行实现之后触发listeners.contextLoaded(context),即公布ApplicationPreparedEvent

refreshContext

    private void refreshContext(ConfigurableApplicationContext context) {        refresh(context);        if (this.registerShutdownHook) {            try {                context.registerShutdownHook();            }            catch (AccessControlException ex) {                // Not allowed in some environments.            }        }    }    protected void refresh(ApplicationContext applicationContext) {        Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);        ((AbstractApplicationContext) applicationContext).refresh();    }    
refreshContext会执行refresh办法

org/springframework/context/support/AbstractApplicationContext.java

    public void refresh() throws BeansException, IllegalStateException {        synchronized (this.startupShutdownMonitor) {            // Prepare this context for refreshing.            prepareRefresh();            // Tell the subclass to refresh the internal bean factory.            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();            // Prepare the bean factory for use in this context.            prepareBeanFactory(beanFactory);            try {                // Allows post-processing of the bean factory in context subclasses.                postProcessBeanFactory(beanFactory);                // Invoke factory processors registered as beans in the context.                invokeBeanFactoryPostProcessors(beanFactory);                // Register bean processors that intercept bean creation.                registerBeanPostProcessors(beanFactory);                // Initialize message source for this context.                initMessageSource();                // Initialize event multicaster for this context.                initApplicationEventMulticaster();                // Initialize other special beans in specific context subclasses.                onRefresh();                // Check for listener beans and register them.                registerListeners();                // Instantiate all remaining (non-lazy-init) singletons.                finishBeanFactoryInitialization(beanFactory);                // Last step: publish corresponding event.                finishRefresh();            }            catch (BeansException ex) {                if (logger.isWarnEnabled()) {                    logger.warn("Exception encountered during context initialization - " +                            "cancelling refresh attempt: " + ex);                }                // Destroy already created singletons to avoid dangling resources.                destroyBeans();                // Reset 'active' flag.                cancelRefresh(ex);                // Propagate exception to caller.                throw ex;            }            finally {                // Reset common introspection caches in Spring's core, since we                // might not ever need metadata for singleton beans anymore...                resetCommonCaches();            }        }    }
refresh先执行postProcessBeanFactory,比方增加BeanPostProcessors,之后执行invokeBeanFactoryPostProcessors,即执行BeanFactoryPostProcessor的postProcessBeanFactory办法
refresh执行完之后触发listeners.started(context)即公布ApplicationStartedEvent
执行完callRunners之后触发listeners.running(context)即公布ApplicationReadyEvent

handleRunFailure

    private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,            Collection<SpringBootExceptionReporter> exceptionReporters, SpringApplicationRunListeners listeners) {        try {            try {                handleExitCode(context, exception);                if (listeners != null) {                    listeners.failed(context, exception);                }            }            finally {                reportFailure(exceptionReporters, exception);                if (context != null) {                    context.close();                }            }        }        catch (Exception ex) {            logger.warn("Unable to close ApplicationContext", ex);        }        ReflectionUtils.rethrowRuntimeException(exception);    }
触发listeners.failed(context, exception)即公布ApplicationFailedEvent

小结

SpringApplication的run办法,先触发listeners.starting()(ApplicationStartingEvent),而后执行了prepareEnvironment(ApplicationEnvironmentPreparedEvent),之后createApplicationContext,再进行prepareContext和refreshContext(ApplicationContextInitializedEvent-->ApplicationPreparedEvent),最初触发listeners.started(context)(ApplicationStartedEvent),之后执行callRunners,最初触发listeners.running(context)(ApplicationReadyEvent),期间有异样会执行handleRunFailure,触发listeners.failed(context, exception)(ApplicationFailedEvent)

其中refresh的时候会执行BeanFactoryPostProcessor的postProcessBeanFactory办法
整体程序如下:ApplicationStartingEvent --> ApplicationEnvironmentPreparedEvent --> ApplicationContextInitializedEvent --> ApplicationPreparedEvent --> ApplicationStartedEvent --> ApplicationReadyEvent,期间有异样则抛出ApplicationFailedEvent