上一篇文章学习了SpringApplication实例化的过程,这一篇来接着学习。

当springApplication对象创建成功后,将调用run(args)方法。

SpringApplication(primarySources).run(args)方法。

 public ConfigurableApplicationContext run(String... args) {//StopWatch是一个计时类,用来记录任务的开始时间,结束时间等。StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();//设置headless,即不配置鼠标、键盘、显示器等configureHeadlessProperty();//监听器SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();try {//ApplicationArguments,提供用来run springApplication的参数的访问ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//配置环境ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);configureIgnoreBeanInfo(environment);//打印BannerBanner 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);}//监听器监听,发布一个event表明SpringApplication启动listeners.started(context);// 调用Spring容器中的ApplicationRunner和CommandLineRunner接口的实现类callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {//监听器发布ApplicationReady事件listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}return context;}

设置headless模式

private void configureHeadlessProperty() {System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));}

设置监听器SpringApplicationRunListeners listeners = getRunListeners(args);源码:

 private SpringApplicationRunListeners getRunListeners(String[] args) {Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));}private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {return getSpringFactoriesInstances(type, new Class<?>[] {});}private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,Class<?>[] parameterTypes, Object... args) {ClassLoader classLoader = getClassLoader();// Use names and ensure unique to protect against duplicatesSet<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));//创建SpringFactoriesInstances实例List<T> instances = createSpringFactoriesInstances(type, parameterTypes,classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);return instances;}

配置环境ConfigableEnvironment的prepareEnviroment()的源码:

 private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) {// 获得或者创建环境ConfigurableEnvironment environment = getOrCreateEnvironment();//配置环境configureEnvironment(environment, applicationArguments.getSourceArgs());//监听器的环境准备listeners.environmentPrepared(environment);//绑定当前环境到springApplicationbindToSpringApplication(environment);//判断是否为自定义环境if (!this.isCustomEnvironment) {environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);return environment;}

打印Banner的printBanner()方法的源码如下:

private Banner printBanner(ConfigurableEnvironment environment) {//如果设置不显示banner,则返回空if (this.bannerMode == Banner.Mode.OFF) {return null;}ResourceLoader resourceLoader = (this.resourceLoader != null)? this.resourceLoader : new DefaultResourceLoader(getClassLoader());//根据resourceLoader生成bannerPrinterSpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);//判断是哪种模式打印banner,是log日志还是系统输出到consoleif (this.bannerMode == Mode.LOG) {return bannerPrinter.print(environment, this.mainApplicationClass, logger);}return bannerPrinter.print(environment, this.mainApplicationClass, System.out);}

SpringApplicationBannerPrinter的源码如下:

class SpringApplicationBannerPrinter {static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";static final String BANNER_IMAGE_LOCATION_PROPERTY = "spring.banner.image.location";static final String DEFAULT_BANNER_LOCATION = "banner.txt";static final String[] IMAGE_EXTENSION = { "gif", "jpg", "png" };private static final Banner DEFAULT_BANNER = new SpringBootBanner();private final ResourceLoader resourceLoader;private final Banner fallbackBanner;SpringApplicationBannerPrinter(ResourceLoader resourceLoader, Banner fallbackBanner) {this.resourceLoader = resourceLoader;this.fallbackBanner = fallbackBanner;}public Banner print(Environment environment, Class<?> sourceClass, Log logger) {Banner banner = getBanner(environment);try {logger.info(createStringFromBanner(banner, environment, sourceClass));}catch (UnsupportedEncodingException ex) {logger.warn("Failed to create String for banner", ex);}return new PrintedBanner(banner, sourceClass);}public Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {Banner banner = getBanner(environment);banner.printBanner(environment, sourceClass, out);return new PrintedBanner(banner, sourceClass);}private Banner getBanner(Environment environment) {Banners banners = new Banners();banners.addIfNotNull(getImageBanner(environment));banners.addIfNotNull(getTextBanner(environment));if (banners.hasAtLeastOneBanner()) {return banners;}if (this.fallbackBanner != null) {return this.fallbackBanner;}return DEFAULT_BANNER;}private Banner getTextBanner(Environment environment) {String location = environment.getProperty(BANNER_LOCATION_PROPERTY,DEFAULT_BANNER_LOCATION);Resource resource = this.resourceLoader.getResource(location);if (resource.exists()) {return new ResourceBanner(resource);}return null;}private Banner getImageBanner(Environment environment) {String location = environment.getProperty(BANNER_IMAGE_LOCATION_PROPERTY);if (StringUtils.hasLength(location)) {Resource resource = this.resourceLoader.getResource(location);return resource.exists() ? new ImageBanner(resource) : null;}for (String ext : IMAGE_EXTENSION) {Resource resource = this.resourceLoader.getResource("banner." + ext);if (resource.exists()) {return new ImageBanner(resource);}}return null;}private String createStringFromBanner(Banner banner, Environment environment,Class<?> mainApplicationClass) throws UnsupportedEncodingException {ByteArrayOutputStream baos = new ByteArrayOutputStream();banner.printBanner(environment, mainApplicationClass, new PrintStream(baos));String charset = environment.getProperty("spring.banner.charset", "UTF-8");return baos.toString(charset);}/*** {@link Banner} comprised of other {@link Banner Banners}.*/private static class Banners implements Banner {private final List<Banner> banners = new ArrayList<>();public void addIfNotNull(Banner banner) {if (banner != null) {this.banners.add(banner);}}public boolean hasAtLeastOneBanner() {return !this.banners.isEmpty();}@Overridepublic void printBanner(Environment environment, Class<?> sourceClass,PrintStream out) {for (Banner banner : this.banners) {banner.printBanner(environment, sourceClass, out);}}}/*** Decorator that allows a {@link Banner} to be printed again without needing to* specify the source class.*/private static class PrintedBanner implements Banner {private final Banner banner;private final Class<?> sourceClass;PrintedBanner(Banner banner, Class<?> sourceClass) {this.banner = banner;this.sourceClass = sourceClass;}@Overridepublic void printBanner(Environment environment, Class<?> sourceClass,PrintStream out) {sourceClass = (sourceClass != null) ? sourceClass : this.sourceClass;this.banner.printBanner(environment, sourceClass, out);}}}

这里可以看到默认的banner.txt,我们可以在resource文件夹下新建banner.txt,把内容放进去,即可替换原来打印的Springboot的banner。

(可以去这些网站生成banner:

  • http://patorjk.com/software/taag

  • http://www.network-science.de/ascii/

  • http://www.degraeve.com/img2txt.php)

创建应用上下文context = createApplicationContext();的源码

/*** Strategy method used to create the {@link ApplicationContext}. By default this* method will respect any explicitly set (显式设置) application context or application          * context* class before falling back to a suitable default.
* @return the application context (not yet refreshed)
* @see #setApplicationContextClass(Class)
*/protected ConfigurableApplicationContext createApplicationContext() {Class<?> contextClass = this.applicationContextClass;if (contextClass == null) {try {//根据webApplicationType的类型来设置不同的contextClassswitch (this.webApplicationType) {case SERVLET:contextClass = Class.forName(DEFAULT_SERVLET_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);}}//用BeanUtils实例化上下文类return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);}

准备上下文prepareContext(context, environment, listeners, applicationArguments,printedBanner);源码

 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);}// 添加特定于引导的单例beanConfigurableListableBeanFactory beanFactory = context.getBeanFactory();beanFactory.registerSingleton("springApplicationArguments", applicationArguments);//打印banner是单例if (printedBanner != null) {beanFactory.registerSingleton("springBootBanner", printedBanner);}//设置允许重写默认方法if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}// 加载资源Set<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");load(context, sources.toArray(new Object[0]));listeners.contextLoaded(context);}

刷新上下文refreshContext(context);的源码:

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

AbstractApplicationContext的refresh()源码如下:

 @Overridepublic 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 {//允许上下文中子类的bean 工厂进行后置操作// 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(context, applicationArguments);其源码:

/*** Called after the context has been refreshed.* @param context the application context* @param args the application arguments*/protected void afterRefresh(ConfigurableApplicationContext context,ApplicationArguments args) {}

在刷新之后调用该方法,暂时无操作。

监听器监听,发布event表明Application启动

public void started(ConfigurableApplicationContext context) {for (SpringApplicationRunListener listener : this.listeners) {listener.started(context);}}

具体的操作由监听器的实现类来实现,源码如下:

类:org.springframework.boot.context.event.EventPublishingRunListener
@Overridepublic void started(ConfigurableApplicationContext context) {context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));}

callRunners的源码如下

 private void callRunners(ApplicationContext context, ApplicationArguments args) {List<Object> runners = new ArrayList<>();//获取conetxt中的ApplicationRunner的实现类runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());//获取context中CommandLineRunner的实现类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);}}}private void callRunner(ApplicationRunner runner, ApplicationArguments args) {try {(runner).run(args);}catch (Exception ex) {throw new IllegalStateException("Failed to execute ApplicationRunner", ex);}}private void callRunner(CommandLineRunner runner, ApplicationArguments args) {try {(runner).run(args.getSourceArgs());}catch (Exception ex) {throw new IllegalStateException("Failed to execute CommandLineRunner", ex);}}

springboot 启动过程之run相关推荐

  1. 【SpringBoot】面试必杀技-泰山陨石坠,SpringBoot中主启动类的run方法启动流程是什么?

    开头导语由Chatgpt完成 当今互联网行业中,Java后端开发岗位的竞争异常激烈,对于面试者来说,掌握一些技巧和知识点将有助于脱颖而出.而对于SpringBoot框架的使用和运行机制,更是Java后 ...

  2. Springboot启动原理解析

    点击上方"方志朋",选择"置顶公众号" 技术文章第一时间送达! 我们开发任何一个Spring Boot项目,都会用到如下的启动类 @SpringBootAppl ...

  3. 手把手带你剖析 Springboot 启动原理!

    作者:平凡希 cnblogs.com/xiaoxi/p/7999885.html 我们开发任何一个Spring Boot项目,都会用到如下的启动类 @SpringBootApplication pub ...

  4. springboot 启动的时候报错 Error creating bean with name 'solrClient'

    springboot 启动的时候报错: org.springframework.beans.factory.BeanCreationException: Error creating bean wit ...

  5. spring-boot启动源码学习-1

    2019独角兽企业重金招聘Python工程师标准>>> spring-boot启动源码分析-启动初始化 主要对spring-boot的启动流程中的启动初始化进行学习,学习spring ...

  6. springboot启动原理分析

    目录 前言 起步依赖 自动配置 总结 前言 现如今我们使用java搭建工程的时候,使用过springboot的同学很清楚,有很多的默认配置springboot已经帮助我们配置好了,进一步的简化了我们的 ...

  7. springboot启动过程_不要搞笑哈,你用了5年的SpringBoot框架,竟然不了解它的启动过程?...

    SpringBoot的启动很简单,代码如下: @SpringBootApplicationpublic class MyApplication { public static void main(St ...

  8. springboot启动后controller访问404

    首先需要在springboot的启动类上面使用@SpringBootApplication注解,并且指定扫描的包的位置,如下: package com.example; import org.spri ...

  9. SpringBoot启动过程详解

    Spring Boot通常有一个名为*Application的入口类,在入口类里有一个main方法,这个main方法其实就是一个标准的java应用的入口方法. 在main方法中使用SpringAppl ...

最新文章

  1. php7 configure: error: Cannot find OpenSSL‘s <evp.h> 问题解决
  2. 用window.location.href实现刷新另个框架页面
  3. PHP垃圾回收深入理解
  4. Hadoop 00_hadoop伪分布式,完全分布式,HA搭建
  5. OpenCv: 二维坐标的旋转方程
  6. centos7服务器文件同步,centos7文件实时同步工具lsyncd
  7. ssas脚本组织程序_微服务架构:从事务脚本到领域模型
  8. 史上最贵!iPhone 12S系列9月亮相,全系标配激光雷达
  9. Magicodes.Admin.Core开源框架总体介绍
  10. socket编程(十一)
  11. php define函数
  12. 排名前5位的免费Java电子书
  13. laravel框架简单总结
  14. 操作系统系列(三)——编译和链接
  15. wincc 日报表(带注释)
  16. 微信机器人服务器成本,微信机器人案例汇总
  17. CodeForces 1463 C. Busy Robot 模拟
  18. 肖明计算机网络答案,袭肖明
  19. 谷歌Chrome浏览器主页被毒霸篡改
  20. 用户空间与内核空间数据交换-2-generic netlink

热门文章

  1. 如何通过NLP人工智能大规模分析评论文本洞察消费者心声(干货)
  2. 砥砺前行!就从Infortrend媒体共享存储开始
  3. 朋友找工作的奇葩规定
  4. QT(2)-QRegExp
  5. 针对乐视网的主页无法打开的解决办法
  6. 【Educoder作业】问题求解——进制
  7. CentOS 7代理设置(Yum/cURL/Wget/Docker)
  8. ibatis mysql 函数_Ibatis+MySql范例(转)
  9. 专家称谷歌收购摩托罗拉意在专利
  10. html5 meter样式,css – Chrome中的HTML5 Meter样式