返回顶部
首页 > 资讯 > 精选 >SpringBoot应用是如何启动的
  • 399
分享到

SpringBoot应用是如何启动的

springboot 2023-05-31 08:05:30 399人浏览 安东尼
摘要

这篇文章将为大家详细讲解有关SpringBoot应用是如何启动的,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。 springBoot项目通过SpringApplication.ru

这篇文章将为大家详细讲解有关SpringBoot应用是如何启动的,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

 springBoot项目通过SpringApplication.run(App.class, args)来启动:

@Configurationpublic class App { public static void main(String[] args) { SpringApplication.run(App.class, args); }}

接下来,通过源码来看看SpringApplication.run()方法的执行过程。如果对源码不感兴趣,直接下拉到文章末尾,看启动框图。

调用SpringApplication类的静态方法

 public static ConfigurableApplicationContext run(Object source, String... args) {  return run(new Object[] { source }, args); } public static ConfigurableApplicationContext run(Object[] sources, String[] args) {  return new SpringApplication(sources).run(args); }

SpringApplication对象初始化

public SpringApplication(Object... sources) {  initialize(sources); } @SuppressWarnings({ "unchecked", "rawtypes" }) private void initialize(Object[] sources) {  if (sources != null && sources.length > 0) {   this.sources.addAll(Arrays.asList(sources));  }  // 判断是否为WEB环境  this.webEnvironment = deduceWebEnvironment();  // 找到META-INF/spring.factories中ApplicationContextInitializer所有实现类,并将其实例化  setInitializers((Collection) getSpringFactoriesInstances(    ApplicationContextInitializer.class));  // 找到META-INF/spring.factories中ApplicationListener所有实现类,并将其实例化  setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));  // 获取当前main方法类对象,即测试类中的App实例  this.mainApplicationClass = deduceMainApplicationClass(); }

对象初始化过程中,使用到了getSpringFactoriesInstances方法:

 private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {  return getSpringFactoriesInstances(type, new Class<?>[] {}); } private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,   Class<?>[] parameterTypes, Object... args) {  ClassLoader classLoader = Thread.currentThread().getContextClassLoader();  // Use names and ensure unique to protect against duplicates  // 读取META-INF/spring.factories指定接口的实现类  Set<String> names = new LinkedHashSet<String>(    SpringFactoriesLoader.loadFactoryNames(type, classLoader));  List<T> instances = createSpringFactoriesInstances(type, parameterTypes,    classLoader, args, names);  AnnotationAwareOrderComparator.sort(instances);  return instances; } @SuppressWarnings("unchecked") private <T> List<T> createSpringFactoriesInstances(Class<T> type,   Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,   Set<String> names) {  List<T> instances = new ArrayList<T>(names.size());  for (String name : names) {   try {    Class<?> instanceClass = ClassUtils.forName(name, classLoader);    Assert.isAssignable(type, instanceClass);    Constructor<?> constructor = instanceClass.getConstructor(parameterTypes);    T instance = (T) constructor.newInstance(args);    instances.add(instance);   }   catch (Throwable ex) {    throw new IllegalArgumentException(      "Cannot instantiate " + type + " : " + name, ex);   }  }  return instances; } // 读取META-INF/spring.factories文件 public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {  String factoryClassName = factoryClass.getName();  try {   Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :     ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));   List<String> result = new ArrayList<String>();   while (urls.hasMoreElements()) {    URL url = urls.nextElement();    Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));    String factoryClassNames = properties.getProperty(factoryClassName);    result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));   }   return result;  }  catch (IOException ex) {   throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +     "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);  } }
META-INF/spring.factories文件内容,spring boot版本1.3.6.RELEASE# PropertySource Loadersorg.springframework.boot.env.PropertySourceLoader=\org.springframework.boot.env.PropertiesPropertySourceLoader,\org.springframework.boot.env.YamlPropertySourceLoader# Run Listenersorg.springframework.boot.SpringApplicationRunListener=\org.springframework.boot.context.event.EventPublishingRunListener# Application Context Initializersorg.springframework.context.ApplicationContextInitializer=\org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\org.springframework.boot.context.ContextIdApplicationContextInitializer,\org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer# Application Listenersorg.springframework.context.ApplicationListener=\org.springframework.boot.builder.ParentContextCloserApplicationListener,\org.springframework.boot.context.FileEncodingApplicationListener,\org.springframework.boot.context.config.AnsiOutputApplicationListener,\org.springframework.boot.context.config.ConfigFileApplicationListener,\org.springframework.boot.context.config.DelegatingApplicationListener,\org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\org.springframework.boot.logging.ClasspathLoggingApplicationListener,\org.springframework.boot.logging.LoggingApplicationListener# Environment Post Processorsorg.springframework.boot.env.EnvironmentPostProcessor=\org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\org.springframework.boot.env.SpringApplicationJSONEnvironmentPostProcessor

ApplicationListener接口是Spring框架的事件监听器,其作用可理解为SpringApplicationRunListener发布通知事件时,由ApplicationListener负责接收。SpringApplicationRunListener接口的实现类就是EventPublishingRunListener,其在SpringBoot启动过程中,负责注册ApplicationListener监听器,在不同时间节点发布不同事件类型,如果有ApplicationListener实现类监听了该事件,则接收处理。

public interface SpringApplicationRunListener {  void started();  void environmentPrepared(ConfigurableEnvironment environment);  void contextPrepared(ConfigurableApplicationContext context);  void contextLoaded(ConfigurableApplicationContext context);  void finished(ConfigurableApplicationContext context, Throwable exception);}

附图为ApplicationListener监听接口实现类,每个类对应了一种事件。

SpringBoot应用是如何启动的

SpringApplication核心run方法

 public ConfigurableApplicationContext run(String... args) {  // 任务执行时间监听,记录起止时间差  StopWatch stopWatch = new StopWatch();  stopWatch.start();  ConfigurableApplicationContext context = null;  configureHeadlessProperty();  // 启动SpringApplicationRunListener监听器  SpringApplicationRunListeners listeners = getRunListeners(args);  listeners.started();  try {   ApplicationArguments applicationArguments = new DefaultApplicationArguments(     args);   // 创建并刷新ApplicationContext   context = createAndRefreshContext(listeners, applicationArguments);   afterRefresh(context, applicationArguments);   // 通知监听器,应用启动完毕   listeners.finished(context, null);   stopWatch.stop();   if (this.logStartupInfo) {    new StartupInfoLogger(this.mainApplicationClass)      .logStarted(getApplicationLog(), stopWatch);   }   return context;  }  catch (Throwable ex) {   handleRunFailure(context, listeners, ex);   throw new IllegalStateException(ex);  } }

这里,需要看看createAndRefreshContext()方法是如何创建并刷新ApplicationContext。

private ConfigurableApplicationContext createAndRefreshContext(   SpringApplicationRunListeners listeners,   ApplicationArguments applicationArguments) {  ConfigurableApplicationContext context;  // Create and configure the environment  // 创建并配置运行环境,WebEnvironment与StandardEnvironment选其一  ConfigurableEnvironment environment = getOrCreateEnvironment();  configureEnvironment(environment, applicationArguments.getSourceArgs());  listeners.environmentPrepared(environment);  if (isWebEnvironment(environment) && !this.webEnvironment) {   environment = convertToStandardEnvironment(environment);  }  // 是否打印Banner,就是启动程序时出现的图形  if (this.bannerMode != Banner.Mode.OFF) {   printBanner(environment);  }  // Create, load, refresh and run the ApplicationContext  // 创建、装置、刷新、运行ApplicationContext  context = createApplicationContext();  context.setEnvironment(environment);  postProcessApplicationContext(context);  applyInitializers(context);  // 通知监听器,ApplicationContext创建完毕  listeners.contextPrepared(context);  if (this.logStartupInfo) {   logStartupInfo(context.getParent() == null);   logStartupProfileInfo(context);  }  // Add boot specific singleton beans  context.getBeanFactory().reGISterSingleton("springApplicationArguments",    applicationArguments);  // Load the sources  // 将beans载入到ApplicationContext容器中  Set<Object> sources = getSources();  Assert.notEmpty(sources, "Sources must not be empty");  load(context, sources.toArray(new Object[sources.size()]));  // 通知监听器,beans载入ApplicationContext完毕  listeners.contextLoaded(context);  // Refresh the context  refresh(context);  if (this.registerShutdownHook) {   try {    context.registerShutdownHook();   }   catch (AccessControlException ex) {    // Not allowed in some environments.   }  }  return context; }

其中利用createApplicationContext()来实例化ApplicationContext对象,即DEFAULT_WEB_CONTEXT_CLASS 、DEFAULT_CONTEXT_CLASS两个对象其中一个。

protected ConfigurableApplicationContext createApplicationContext() {  Class<?> contextClass = this.applicationContextClass;  if (contextClass == null) {   try {    contextClass = Class.forName(this.webEnvironment      ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);   }   catch (ClassNotFoundException ex) {    throw new IllegalStateException(      "Unable create a default ApplicationContext, "        + "please specify an ApplicationContextClass",      ex);   }  }  return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass); }

postProcessApplicationContext(context)、applyInitializers(context)均为初始化ApplicationContext工作。

SpringBoot启动过程分析就先到这里,过程中关注几个对象:

ApplicationContext:Spring高级容器,与BeanFactory类似。

SpringApplicationRunListener:SprintBoot启动监听器,负责向ApplicationListener注册各类事件。

Environment:运行环境。

启动过程框图

SpringBoot应用是如何启动的

关于SpringBoot应用是如何启动的就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

--结束END--

本文标题: SpringBoot应用是如何启动的

本文链接: https://lsjlt.com/news/224413.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • SpringBoot应用是如何启动的
    这篇文章将为大家详细讲解有关SpringBoot应用是如何启动的,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。 SpringBoot项目通过SpringApplication.ru...
    99+
    2023-05-31
    springboot
  • Tomcat中SpringBoot应用无法启动如何解决
    Tomcat中SpringBoot应用无法启动如何解决?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。问题描述我修改pom.xml将打包方式改成war<packagin...
    99+
    2023-05-31
    springboot omc tomcat
  • Springboot通过run启动web应用的方法
    目录一、SpringBootApplication背后的秘密1、@Configuration2、@ComponentScan3、@EnableAutoConfiguration二、深...
    99+
    2024-04-02
  • 快速掌握SpringBoot应用的启动入口
    目录1、一切的开始2、总结 Springboot可以说是Java程序员必备技能了,大家都知道Springboot最终可以通过maven打成jar包,然后直接使用java -jar命令...
    99+
    2024-04-02
  • SpringBoot应用的启动入口怎么封装
    这篇文章主要介绍了SpringBoot应用的启动入口怎么封装的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringBoot应用的启动入口怎么封装文章都会有所收获,下面我们一起来看看吧。Springboot可...
    99+
    2023-06-30
  • 如何在SpringBoot中启动tomcat
    如何在SpringBoot中启动tomcat?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。springboot是什么springboot一种全新的编程规范,其设计目的是用来...
    99+
    2023-06-14
  • eclipse如何启动springboot项目
    要在Eclipse中启动Spring Boot项目,可以按照以下步骤进行操作:1. 在Eclipse中导入Spring Boot项目...
    99+
    2023-10-08
    springboot eclipse
  • springboot如何创建启动类
    在Spring Boot中创建启动类非常简单,只需要遵循以下步骤: 创建一个新的Java类,例如Application。 在类上添...
    99+
    2023-10-24
    springboot
  • SpringBoot的jar包如何启动的实现
    目录一、简介二、jar包的内部结构三、加载过程1.使用到的一些类2.过程分析四、总结一、简介 ​ 使用过SprongBoot打过jar包的都应该知道,目标文件一般都会生成两个文件,一...
    99+
    2024-04-02
  • Springboot应用到底启动了哪些bean
    本篇文章为大家展示了Springboot应用到底启动了哪些bean,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。1. 概述我们将探索在...
    99+
    2024-04-02
  • SpringBoot应用jar包启动原理详解
    目录1、maven打包2、Jar包目录结构3、可执行Jar(JarLauncher)4、WarLauncher5、总结1、maven打包 Spring Boot项目的pom.xml文...
    99+
    2024-04-02
  • springboot启动的原理是什么
    Spring Boot的启动原理可以分为以下几个步骤: 加载依赖:Spring Boot会根据项目的配置文件(如pom.xml)...
    99+
    2023-10-26
    springboot
  • Springboot如何设置启动内存
    目录java-jar运行springboot项目时内存设置例如springboot启动命令,限制内存大小java -jar 运行springboot项目时内存设置 java -Xms...
    99+
    2024-04-02
  • springboot启动时如何指定spring.profiles.active
    目录springboot启动指定spring.profiles.activeSpringBoot激活profiles你知道几种方式激活Profiles的方式系统变量方式Java系统属...
    99+
    2023-05-15
    springboot启动 spring.profiles.active 指定spring.profiles.active
  • springboot 启动如何修改application.properties的参数
    目录修改application.properties的参数1、方法一:直接在cmd中执行2、方法二:配置3、方法三4、方法四springboot项目启动参数以下几种方式都可以被@Va...
    99+
    2024-04-02
  • springboot应用服务启动事件的监听实现
    目录一、简介二、常用场景介绍二、代码小实验 通过@Component定义方式实现通过@Bean定义方式实现三、执行测试四、总结五、问题总结一、简介 Spring Boot提供了两个接...
    99+
    2024-04-02
  • springboot启动流程是什么
    Spring Boot 启动流程如下:1. 初始化应用程序上下文:Spring Boot 应用程序启动时,首先会创建一个 Sprin...
    99+
    2023-05-17
    springboot启动流程 springboot
  • SpringBoot启动原理是什么
    今天小编给大家分享一下SpringBoot启动原理是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。入口版本: 2.1.8...
    99+
    2023-07-05
  • win11如何添加应用自启动
    要在Windows 11中添加应用自启动,您可以按照以下步骤操作:1. 打开“设置”应用。您可以通过在任务栏上点击“开始”按钮,然后...
    99+
    2023-10-09
    win11
  • win101909应用自启动如何关闭
    今天小编给大家分享一下win101909应用自启动如何关闭的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。方法一: 卸载设备中...
    99+
    2023-07-01
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作