SpringApplication Explain

The SpringApplication class provides a convenient way to bootstrap a Spring application that is started from a main() method. In many situations, you can delegate to the static SpringApplication.run method, as shown in the following example.

(SpringApplication类提供了一种便利的方式以便引导Spring应用从#main启动,大多数情况下,可以通过静态方法SpringApplication#run代理启动)

How TO Use SpringApplication

  1. @EnableAutoConfiguration
  2. public class MyApplication {
  3. // ... Bean definitions
  4. public static void main(String[] args) throws Exception {
  5. SpringApplication.run(MyApplication.class, args);
  6. }
  7. }

Customize SpringApplication

UseSpringApplicationAPI To Change

  1. public static void main(String[] args) {
  2. SpringApplication app = new SpringApplication(MySpringConfiguration.class);
  3. app.setBannerMode(Banner.Mode.OFF);
  4. app.run(args);
  5. }

UseSpringApplicationBuilder API To Change

  1. new SpringApplicationBuilder()
  2. .sources(Parent.class)
  3. .child(Application.class)
  4. .bannerMode(Banner.Mode.OFF)
  5. .run(args);

SpringApplication Preparing Stage

Configure Spring Boot Bean's Sources

Java 配置类或XML上下文配置集合,用于Spring Boot BeanDefinitionLoader读取,并且将配置源解析加载为Spring Bean 定义。

  • 数量,一个或者多个

Java Configuration Class

使用Spring 注解驱动中的Java配置类,也就是Spring 模式注解所标注的类,例如@Configuration

  1. package com.yi23.backend.springboot.bootstrap;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. /**
  5. * {@link SpringApplication} 启动引导类
  6. *
  7. * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a>
  8. * @see
  9. * @since
  10. */
  11. @SpringBootApplication
  12. public class SpringApplicationBootstrap {
  13. public static void main(String[] args) {
  14. SpringApplication.run(SpringApplicationBootstrap.class,args);
  15. }
  16. }

XML Configure

用户Spring 传统配置驱动的XML文件

  1. ...
  2. //设置Annotation配置源
  3. Set<String> sources = new HashSet<>();
  4. //A source can be: a class name, package name, or an XML resource location.
  5. sources.add(Yi23ApplicationConfiguration.class.getName());
  6. springApplication.setSources(sources);
  7. ...

Deduce Web Application Type

根据当前应用CLassPath中是否存在相关实现来推断Web Application Type,包括:

  • Web Reactive : WebApplicationType.REACTIVE
  • Web Servlet : WebApplicationType.SERVLET
  • 非Web : WebApplicationType.NONE

参考:org.springframework.boot.SpringApplication#deduceWebApplicationType

  1. private WebApplicationType deduceWebApplicationType() {
  2. if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
  3. && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
  4. return WebApplicationType.REACTIVE;
  5. }
  6. for (String className : WEB_ENVIRONMENT_CLASSES) {
  7. if (!ClassUtils.isPresent(className, null)) {
  8. return WebApplicationType.NONE;
  9. }
  10. }
  11. return WebApplicationType.SERVLET;
  12. }
  • 版本意识,下图为Spring Boot 2.1.3中的推断实现

    ![image-20190306144854302](/Users/zhangpan/Library/Application Support/typora-user-images/image-20190306144854302.png)

Deduce Main Class

跟住main线程的执行堆栈判断当前实际的引导类

参考:org.springframework.boot.SpringApplication#deduceMainApplicationClass

  1. private Class<?> deduceMainApplicationClass() {
  2. try {
  3. StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
  4. for (StackTraceElement stackTraceElement : stackTrace) {
  5. if ("main".equals(stackTraceElement.getMethodName())) {
  6. return Class.forName(stackTraceElement.getClassName());
  7. }
  8. }
  9. }
  10. catch (ClassNotFoundException ex) {
  11. // Swallow and continue
  12. }
  13. return null;
  14. }

Load ApplicationContextInitializer

ApplicationContextInitializer是应用上下文的加载器,利用Spring 工厂加载机制,实例化ApplicationContextInitializer实现类,并实现对象集合排序

  • 代码
  1. private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
  2. Class<?>[] parameterTypes, Object... args) {
  3. ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  4. // Use names and ensure unique to protect against duplicates
  5. Set<String> names = new LinkedHashSet<>(
  6. SpringFactoriesLoader.loadFactoryNames(type, classLoader));
  7. List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
  8. classLoader, args, names);
  9. AnnotationAwareOrderComparator.sort(instances);
  10. return instances;
  11. }
  • 实现技术

    • 实现类:org.springframework.core.io.support.SpringFactoriesLoader
    • 配置文件:META-INF/spring.factories
    • 排序:org.springframework.core.annotation.AnnotationAwareOrderComparator#sort
  1. package com.yi23.backend.springboot.context;
  2. import org.springframework.context.ApplicationContextInitializer;
  3. import org.springframework.context.ConfigurableApplicationContext;
  4. import org.springframework.core.Ordered;
  5. import org.springframework.core.annotation.Order;
  6. /**
  7. * 自定义高优先级{@link ApplicationContextInitializer}初始化加载器
  8. *
  9. * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a>
  10. * @see
  11. * @since
  12. */
  13. @Order(Ordered.HIGHEST_PRECEDENCE)
  14. public class HelloYi23ApplicationContextInitializer implements ApplicationContextInitializer {
  15. @Override
  16. public void initialize(ConfigurableApplicationContext applicationContext) {
  17. System.out.println("高优先级初始化加载class : "
  18. + applicationContext.getId());
  19. }
  20. }
  1. # Initializers
  2. org.springframework.context.ApplicationContextInitializer=\
  3. com.yi23.backend.springboot.context.AfterHelloYi23ApplicationContextInitializer,\
  4. com.yi23.backend.springboot.context.HelloYi23ApplicationContextInitializer

Load ApplicationListener

利用Spring 工厂加载机制,实例化ApplicationLisener实现类,并实现对象集合排序

  1. package com.yi23.backend.springboot.event.listener;
  2. import org.springframework.context.ApplicationListener;
  3. import org.springframework.context.event.ContextRefreshedEvent;
  4. import org.springframework.core.Ordered;
  5. /**
  6. * hello yi23 {@link ApplicationListener} 监听 {@link ContextRefreshedEvent}事件
  7. *
  8. * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a>
  9. * @see
  10. * @since
  11. */
  12. public class HelloYi23ApplicationListener
  13. implements ApplicationListener<ContextRefreshedEvent>,Ordered {
  14. @Override
  15. public void onApplicationEvent(ContextRefreshedEvent event) {
  16. System.out.printf("上下文内容id:%s,timestamp:%s.\r\n",
  17. event.getApplicationContext().getId(), event.getTimestamp());
  18. }
  19. @Override
  20. public int getOrder() {
  21. return Ordered.HIGHEST_PRECEDENCE;
  22. }
  23. }

SpringApplication Running Stage

Load SpringApplication Run Listener

org.springframework.boot.SpringApplicationRunListeners

利用工厂加载机制,读取SpringApplicationRunListener对象集合,并封装到组合对象SpringApplicationRunListeners

  1. private SpringApplicationRunListeners getRunListeners(String[] args) {
  2. Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
  3. return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
  4. SpringApplicationRunListener.class, types, this, args));
  5. }

Running SpringApplication Run Listeners

SpringApplicationRunListener 监听多个运行状态方法

监听方法 阶段说明 Springboot 起始版本
starting Spring 应用刚刚启动 1.0
environmentPrepared(ConfigurableEnvironment) ConfigurableEnvironment准确之后,允许将其修改 1.0
contextPrepared(ConfigurableApplicationContext) ConfigurableApplicationContext准备之后,允许将其修改 1.0
contextLoaded(ConfigurableApplicationContext) ConfigurableApplicationContext已加载,但未启动 1.0
started(ConfigurableApplicationContext) ConfigurableApplicationContext已启动,当前Spring Bean已初始化完成 2.0.0
running(ConfigurableApplicationContext) Spring Application 正在运行 2.0.0
failed(ConfigurableApplicationContex,Throwable) Spring Application运行失败 2.0.0

Monitor Spring-Boot Event / Spring Event

SpringBoot 通过SpringApplicationRunListener的实现类EventPublishingRunListener,利用Spring Framework事件API,广播Spring Boot 事件

Spring Framework Event/Listener Model

  • Spring 应用事件

    • 普通应用事件:ApplicationEvent
    • 应用上下文事件:ApplicationContextEvent
  • Spring 应用监听器
    • 接口编程模型:ApplicationListener
    • 注解编程模型:@EventListener
  • Spring 应用事件广播器
    • 接口:ApplicationEventMulticaster
    • 实现类:SimpleApplicationEventMulticaster
      • 执行模式:同步/异步

EventPublishingRunListener relationship of Monitor‘s Method & Spring Boot Events

监听方法 Spring Boot 事件 Spring boot 起始版本
starting ApplicationStartingEvent 1.5.0
environmentPrepared(ConfigurableEnvironment) ApplicationEnvironmentPreparedEvent 1.0
contextPrepared(ConfigurableApplicationContext)
contextLoaded(ConfigurableApplicationContext) ApplicationPreparedEvent 1.0
started(ConfigurableApplicationContext) ApplicationStartedEvent 2.0.0
running(ConfigurableApplicationContext) ApplicationReadyEvent 1.3.0
failed(ConfigurableApplicationContex,Throwable) ApplicationFailedEvent 1.0

Validate ConfigFileApplicationListener Order

  1. package com.yi23.backend.springboot.event.listener;
  2. import org.springframework.boot.context.config.ConfigFileApplicationListener;
  3. import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
  4. import org.springframework.boot.context.event.ApplicationPreparedEvent;
  5. import org.springframework.context.ApplicationEvent;
  6. import org.springframework.context.event.SmartApplicationListener;
  7. import org.springframework.core.Ordered;
  8. import org.springframework.core.env.Environment;
  9. /**
  10. * Before {@link ConfigFileApplicationListener}
  11. *
  12. * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a>
  13. * @see
  14. * @since
  15. */
  16. public class BeforeConfigFileApplicationListener implements SmartApplicationListener, Ordered {
  17. @Override
  18. public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
  19. return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
  20. || ApplicationPreparedEvent.class.isAssignableFrom(eventType);
  21. }
  22. @Override
  23. public boolean supportsSourceType(Class<?> aClass) {
  24. return true;
  25. }
  26. @Override
  27. public void onApplicationEvent(ApplicationEvent event) {
  28. if (event instanceof ApplicationEnvironmentPreparedEvent) {
  29. ApplicationEnvironmentPreparedEvent environmentPreparedEvent = (ApplicationEnvironmentPreparedEvent) event;
  30. Environment environment = environmentPreparedEvent.getEnvironment();
  31. System.out.println("environment.getProperty(\"name\"): " + environment.getProperty("name"));
  32. }
  33. if (event instanceof ApplicationPreparedEvent) {
  34. }
  35. }
  36. @Override
  37. public int getOrder() {
  38. //比 ConfigFileApplicationListener 优先级高
  39. return ConfigFileApplicationListener.DEFAULT_ORDER - 1;
  40. }
  41. }

Create Spring Application Context(ConfigurableApplicationContext)

根据前面提到的Prepared 阶段推断出的Web 应用类型对应的ConfigurableApplicationContext实例:

  • Web Reactive: AnnotationConfigReactiveWebServerApplicationContext
  • Web Servlet: AnnotationConfigServletWebServerApplicationContext
  • 非Web: AnnotationConfigApplicationContext
  1. /**
  2. * Strategy method used to create the {@link ApplicationContext}. By default this
  3. * method will respect any explicitly set application context or application context
  4. * class before falling back to a suitable default.
  5. * @return the application context (not yet refreshed)
  6. * @see #setApplicationContextClass(Class)
  7. */
  8. protected ConfigurableApplicationContext createApplicationContext() {
  9. Class<?> contextClass = this.applicationContextClass;
  10. if (contextClass == null) {
  11. try {
  12. switch (this.webApplicationType) {
  13. case SERVLET:
  14. contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS);
  15. break;
  16. case REACTIVE:
  17. contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
  18. break;
  19. default:
  20. contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
  21. }
  22. }
  23. catch (ClassNotFoundException ex) {
  24. throw new IllegalStateException(
  25. "Unable create a default ApplicationContext, "
  26. + "please specify an ApplicationContextClass",
  27. ex);
  28. }
  29. }
  30. return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
  31. }

Create Environment

根据Prepead 阶段推断的Web应用类型创建对应的 ConfigurableEnvironment

  • Web Servlet: StandardServletEnvironment
  • Web Reactive: StandardEnvironment
  • 非Web: StandardEnvironment
  1. private ConfigurableEnvironment getOrCreateEnvironment() {
  2. if (this.environment != null) {
  3. return this.environment;
  4. }
  5. if (this.webApplicationType == WebApplicationType.SERVLET) {
  6. return new StandardServletEnvironment();
  7. }
  8. return new StandardEnvironment();
  9. }

SpringBoot之SpringApplication Explain的更多相关文章

  1. SpringBoot之SpringApplication

    简介 可以用于从java主方法中引导和启动Spring应用程序的类,在默认情况下,通过以下步骤来启动应用: 创建一个ApplicationContext实例 注册CommandLineProperty ...

  2. springboot自定义SpringApplication启动类

    如果默认的SpringApplication不符合你的口味,你可以创建一个本地的实例并自定义它.例如,关闭banner你可以这样写: public static void main(String[] ...

  3. 入门到熟练-SpringBoot

    Spring Boot概述 1.1. Spring Boot是什么 Spring Boot是一套基于Spring框架的微服务框架. 1.2. Spring Boot框架出现的背景 由于Spring是一 ...

  4. [SpringBoot guides系列翻译]调度任务

    原文 调度任务 用spring实现一个任务调度. 你将做的 你将做一个应用每5秒钟打印当前时间,用@Scheduled注解. 你需要啥 15分钟 文本编辑器或者IDE JDK1.8+ Gradle4+ ...

  5. Spring-boot简单的理解

    SpringBoot启动 SpringApplication.run(MyBootApplication.class); SpringApplication.run启动SpringBoot应用,主要过 ...

  6. SpringBoot入门(1)

    一.初始 ①.首先还是要创建一个maven工程 ②.然后编写Controller 让SpringBoot跑起来并不需要太多的代码,就能实现了我们平时要配置很多的功能,这是怎么做到的呢?我们就下面一个入 ...

  7. SpringBoot 入门 Demo

    SpringBoot   入门 Demo Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从 ...

  8. idea实现第一个springboot程序

    1.环境准备 JDK:1.8 Apache Maven: 3.6.1 IntelliJ IDEA 2019.1.3 x64 SpringBoot 1.5.9.RELEASE:1.5.9: 1.1.MA ...

  9. 自己动手实现springboot配置(非)中心

    好久没写博客了,这段时间主要是各种充电,因为前面写的一些东西,可能大家不太感兴趣或者是嫌弃没啥技术含量,所以这次特意下了一番功夫.这篇博客其实我花了周末整整两天写好了第一个版本,已经开源出去了,同样是 ...

随机推荐

  1. WPF MVVM笔记

    学习了一番WPF MVVM,记录一下,微软的连接(https://msdn.microsoft.com/zh-cn/magazine/dd419663.aspx) 1.mvvm就是model,view ...

  2. asp.net下ueditor上传大容量视频报http请求错误的解决方法

    故障现象: 当使用百度编辑器ueditor上传大容量视频或大容量图片的时候,编辑器报“http请求错误”的解决方法详解: 原因分析: 目前很多CMS整合了百度的ueditor编辑器,但是上传稍微大一点 ...

  3. Android零基础入门第47节:自动完成文本框AutoCompleteTextView

    原文:Android零基础入门第47节:自动完成文本框AutoCompleteTextView 上一期学习的Spinner的使用,掌握的怎么样?本期一起来学习AutoCompleteTextView的 ...

  4. 指针与 const --- 指针常量与常量指针

    注:该文主要来源于 网易公开课之<C++ 程序设计入门(上)>课件. 在 C 语言标准中,const 修饰的变量称之为 只读变量, 在 C++ 语言标准中,const 修饰的变量称之为 常 ...

  5. Hadoop集群(第6期)JDK和SSH无密码配置

    1.Linux配置java环境变量 1.1 解压安装jdk 在shell终端下进入jdk-6u14-linux-i586.bin文件所在目录,执行命令 ./jdk-6u14-linux-i586.bi ...

  6. Python之二叉树Binarytree

    二叉树是树的简化版,除根节点之外的所有节点都有一个父节点,任意节点都可以最多有一个左子节点和右子节点. 二叉树的遍历是非常重要的算法,主要分为深度优先遍历和广度优先遍历. 其中深度优先遍历按照访问根节 ...

  7. 剖析Unreal Engine超真实人类的渲染技术Part 1 - 概述和皮肤渲染

    一.概述 1.1 数字人类的概要 数字人类(Digital Human)是利用计算机模拟真实人类的一种综合性的渲染技术.也被称为虚拟人类.超真实人类.照片级人类. 它是一种技术和艺术相结合的综合性模拟 ...

  8. 第二章 python如何运行程序

    一.python解释器介绍 Python解释器是一种让程序运行起来的程序.实际上,解释器是代码与机器的计算机硬件之间的软件逻辑层.当Python包安装在机器上后,它包含了一些最小化的组件:一个解释器和 ...

  9. 宜信开源|数据库审核软件Themis的规则解析与部署攻略

    一.介绍 Themis是宜信公司DBA团队开发的一款数据库审核产品,可帮助DBA.开发人员快速发现数据库质量问题,提升工作效率.其名称源自希腊神话中的正义与法律女神.项目取此名称,寓意此平台对数据库质 ...

  10. Swift的访问控制讲解

    Swift中访问修饰符总共有5种,分别为fileprivate,private,internal,public和open,其中,fileprivate以及open是Swift 3新添加的.因为过去的S ...