上一篇文章学习了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. seq2seq与Attention机制
  2. 卫星覆盖区域分析 基于网格点法
  3. python 加速器 numba 示例
  4. 合理设置apache参数
  5. 缓冲流、转换流、序列化流、打印流
  6. wxWidgets:使用自定义对话框和 sizer
  7. jvm学习笔记(三)
  8. linux x86板级文件,Linux driver 板级文件跟踪一般方法
  9. iOS-数据库sqlite的使用
  10. 解决 display 和 transition 冲突的问题
  11. 10月21日下午PHP常用函数
  12. java web应用程序_说说Java Web中的Web应用程序|乐字节
  13. 构造模式(Builder Pattern)
  14. 声波转字符c语言代码,声波传输解码
  15. 2020牛客暑期多校训练营(第九场) The Escape Plan of Groundhog
  16. 【音频系列】——MTK6735模块耳机通道外接功放的处理
  17. python微信公众号翻译功能怎么用_Watson使用指南(七)在微信公众号中实现识图作诗功能...
  18. 券业零售业务转型方向已显现?从打造个人IP开始
  19. 清除node_modules 缓存
  20. 【单片机毕业设计】【mcuclub-jj-003】基于单片机的八层电梯的设计

热门文章

  1. Journal日志与oplog日志的区别
  2. 如何通过网络赚钱(1年纯赚7000万有感)
  3. php框架symfony,Symfony框架配置
  4. 误删了php文件怎么恢复,【问题】phpstorm误删文件后,恢复成了0KB
  5. 【Python+OpenCV 图像透视变换 warpPerspective函数】
  6. 【Flask】response响应
  7. node04-buffer
  8. Android 文件存储系统
  9. 毕业了,你有多少本钱?(文/徐小平)
  10. 中央批准!985大学,迎来院士校长(副部长级)