springboot web - 启动(2) run()
接上一篇
在创建 SpringApplication 之后, 调用了 run() 方法.
public ConfigurableApplicationContext run(String... args) { //定时器, 监控启动时间 StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); //java.awt.headless是一种模式用于在缺少显示屏、键盘或者鼠标时的系统配置,很多监控工具如jconsole 需要将该值设置为true,系统变量默认为true configureHeadlessProperty(); //从 spring.factories 配置中获取监听器 SpringApplicationRunListeners listeners = getRunListeners(args); //启动监听器 listeners.starting(); try { //对 args 进行封装, 此处args 是 {} ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); //构造容器环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); //设置需要忽略的bean configureIgnoreBeanInfo(environment); //打印banner Banner printedBanner = printBanner(environment); //创建容器, 此处创建的是 AnnotationConfigServletWebServerApplicationContext context = createApplicationContext(); //实例化SpringBootExceptionReporter.class,用来支持报告关于启动的错误 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); }
//遍历调用监听器的started()方法, 发布 ApplicationStartedEvent 事件 listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try {
//遍历调用监听器的 running() 方法, 发布 ApplicationReadyEvent 事件 listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }
configureHeadlessProperty()
private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless"; private boolean headless = true; private void configureHeadlessProperty() { System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty( SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless))); }
这里会默认设置为 true.
getRunListeners()
private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)); }
这里是获取配置的监听器, 并封装到 SpringApplicationRunListeners 了中的 this.liseners 属性中.
这里获取到的是: org.springframework.boot.context.event.EventPublishingRunListener
listeners 这块内容比较多, 放在后面去详细解析
prepareEnvironment()
private ConfigurableEnvironment prepareEnvironment( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { //根据webApplicationType, 创建运行环境, 此处创建的是 StandardServletEnviroment ConfigurableEnvironment environment = getOrCreateEnvironment(); //配置环境 configureEnvironment(environment, applicationArguments.getSourceArgs()); //给监听器设置环境,遍历监听器,调用其 enviromentParepared() 方法,发布环境已准备事件 listeners.environmentPrepared(environment); bindToSpringApplication(environment); if (this.webApplicationType == WebApplicationType.NONE) { environment = new EnvironmentConverter(getClassLoader()) .convertToStandardEnvironmentIfNecessary(environment); } ConfigurationPropertySources.attach(environment); return environment; }
configureIgnoreBeanInfo()
public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore"; private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) { if (System.getProperty( CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) { Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE); System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString()); } }
默认设置 spring.beaninfo.ignore 为 true
printBanner()
private Banner printBanner(ConfigurableEnvironment environment) { if (this.bannerMode == Banner.Mode.OFF) { return null; } ResourceLoader resourceLoader = (this.resourceLoader != null ? this.resourceLoader : new DefaultResourceLoader(getClassLoader())); SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter( resourceLoader, this.banner); if (this.bannerMode == Mode.LOG) { return bannerPrinter.print(environment, this.mainApplicationClass, logger); } return bannerPrinter.print(environment, this.mainApplicationClass, System.out); }
这里是打印 banner , 在 application.yml 中, 加入配置
spring:
main:
banner-mode: "off"
可以关闭 banner 打印, 当然这里也可以自定义自己的 banner . 可有可无的功能, 不去管它. 打印就打印吧.
createApplicationContext()
public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework.boot." + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext"; public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework." + "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext"; public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context." + "annotation.AnnotationConfigApplicationContext"; protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { switch (this.webApplicationType) { case SERVLET: contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS); break; case REACTIVE: contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS); break; default: contextClass = Class.forName(DEFAULT_CONTEXT_CLASS); } } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); }
根据环境类型, 创建 ApplicationContext 对象 : AnnotationConfigServletWebServerApplicationContext
prepareContext()
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment); //容器的后置处理 postProcessApplicationContext(context); //对this.initializers中存放的类进行初始化操作, 调用其initialize()方法 applyInitializers(context); //遍历监听器, 调用其 contextPrepared() 方法, 进行容器准备好的操作, 此处为空操作, 留给子类重写扩展 listeners.contextPrepared(context); //日志打印 if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); } //拿this.primarySources + this.sources, 此处拿到的是SbmvcApplication Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); //将SbmvcApplication注册到容器里 load(context, sources.toArray(new Object[0])); //遍历监听器, 调用其contextLoaded()方法, 进行容器加载后的操作 listeners.contextLoaded(context); }
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(); } @Override 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(); } } }
这里执行的内容非常多, 不在此解析了.
afterRefresh()
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) { }
这里是一个空方法, 可以留个子类重写, 进行扩展操作
callRunners()
private void callRunners(ApplicationContext context, ApplicationArguments args) { List<Object> runners = new ArrayList<>(); runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); AnnotationAwareOrderComparator.sort(runners); for (Object runner : new LinkedHashSet<>(runners)) { if (runner instanceof ApplicationRunner) { callRunner((ApplicationRunner) runner, args); } if (runner instanceof CommandLineRunner) { callRunner((CommandLineRunner) runner, args); } } }
执行到这里是, 容器里面还没有哪两个类, 所以 runners.size() = 0. 没有执行什么逻辑.
总结:
run() 方法主要进行了以下几个操作
1. 获取并启动了监听器, 发布了 容器启动事件(ApplicationStartingEvent )
2. 构造容器环境
3. 创建容器
4. 实例化 SpringBootExceptionReporter , 用来支持报告关于启动的错误
5. 准备容器
6. 刷新容器
7. 执行刷新完容器的操作(暂时为空操作)
8. 发布了 容器启动完成事件(ApplicationStartedEvent)
9. 发布了 容器已准备好事件(ApplicationReadyEvent), 如果执行失败, 则会发布容器失败事件(ApplicationFailedEvent)