likes
comments
collection
share

SpringBoot系列(二) SpringBoot启动流程-关于Launcher类

作者站长头像
站长
· 阅读数 15

org.springframework.boot.loader.Launcher类是Spring Boot启动过程的入口点,也是Spring Boot的核心类之一。在Spring Boot应用程序启动时,Launcher类的静态方法main()将被执行,它主要负责设置Spring Boot运行环境和启动应用程序的主类。下面是对Launcher类的详细解释。

构造函数

Launcher类只有一个私有的构造函数:

private Launcher() {
}

这是一个私有构造函数,用于确保无法实例化Launcher类。由于Launcher类只有静态方法,因此该构造函数不会被调用。

main()方法

Launcher类中所有的静态方法都是由main()方法调用的。因此,main()方法是Spring Boot应用程序启动流程的入口点。在main()方法中,首先执行以下步骤:

  1. 创建Logger对象
  2. 打印Banner
  3. 设置SystemProperties
public static void main(String[] args) throws Exception {
		...
		PropertiesLauncher launcher = new PropertiesLauncher();
		...
		launcher.launch(args);
	}

在以上步骤之后,main()方法创建了一个PropertiesLauncher对象,并执行了launch()方法。PropertiesLauncher是Spring Boot的默认启动器,并提供了一组必要的类和资源,以便Spring Boot应用程序可以被正确地启动和执行。

launch()方法

PropertiesLauncher类的launch()方法是应用程序启动过程的核心方法。它主要负责以下任务:

  1. 解析应用程序的Classpath
  2. 加载应用程序的JAR和CLASSPATH中的所有JAR
  3. 加载应用程序主类
  4. 创建SpringApplication对象
  5. 启动应用程序
private ClassLoader createClassLoader(
		List<Archive> archives, ClassLoader parent) throws Exception {
		...
		return new LaunchedURLClassLoader(urls.toArray(new URL[0]), parent);
	}

PropertiesLauncher类中,createClassLoader()方法被用于创建一个LaunchedURLClassLoader对象,这个ClassLoader可以从本地磁盘或网络下载的多个JAR文件中加载应用程序的类和资源。由于LaunchedURLClassLoader是基于URL的ClassLoader,它可以从多个远程或本地位置加载类和资源。

加载应用程序的主类

PropertiesLauncher类的另一个重要方法是load方法,该方法负责查找并加载应用程序的主类。实际上,load()方法是main()方法中最重要的一部分,因为它确定了应用程序如何启动和运行。在Spring Boot应用程序中,主类通常是带有@SpringBootApplication注解的类。

创建SpringApplication对象

在加载应用程序的主类之后,PropertiesLauncher将使用主类名称创建一个SpringApplication对象。这个对象是Spring Boot应用程序的入口点,并负责加载所有bean,处理成bean之间的依赖关系以及启动应用程序。

private SpringApplication createSpringApplication() {
		SpringApplication application = new SpringApplication(this.mainClass);
		return application;
	}

这里,createSpringApplication()方法负责创建Spring Boot应用程序的核心类SpringApplication对象,并将主类传递给它。一旦SpringApplication对象创建成功,就可以准备启动应用程序了。

启动应用程序

在创建了SpringApplication对象之后,Spring Boot调用run()方法启动应用程序。这个方法是非常复杂的,并包含了大量的代码,其中包括以下步骤:

  1. 获取SpringBoot的配置类(ApplicationClassList)并把它们添加到应用程序上下文中
  2. 应用程序上下文的Environment(环境)初始化
  3. 如果存在:spring.main.sources属性、或使用SpringApplicationsources()方法添加了源文件,则将这些类和资源添加到应用程序上下文中
  4. 对自定义的ApplicationContextInitializer进行调用。这些可以根据应用程序上下文进行配置,用于对ApplicationContext进行分析和修改,例如,添加propertySources或profiles等
  5. 如果存在:spring.application.admin.enabled属性的值为true,则创建一个SpringApplicationAdminMXBean实例,提供对Spring Boot应用程序的管理方法
  6. 创建并配置应用程序上下文
  7. 执行ApplicationContext的refresh()方法,完成应用程序上下文的初始化
  8. 对自定义的ApplicationRunner和CommandLineRunner进行执行。这些Runner是在ApplicationContext刷新之后开始执行的
  9. 向外部环境发布一个ApplicationStartedEvent通知,表示应用程序已启动
public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner 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);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}
		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

run()方法执行完成后,应用程序已启动并准备好接收客户端请求了。

在启动过程中,SpringApplication对象扮演了非常重要的角色,它是Spring Boot应用程序的核心类之一。因此,了解SpringApplication对象的创建和配置对于理解Spring Boot应用程序的启动过程至关重要。在使用Spring Boot时,在进行应用程序开发和维护时,我们应该始终牢记应用程序启动过程的核心原则,以避免一些常见问题并优化应用程序的性能。

结论

在本文中,我们对Spring Boot应用程序启动过程做了一个总体介绍,并深入了解了各个步骤的细节。了解Spring Boot启动流程是非常重要的,因为它可以使我们更好地理解应用程序的工作原理,并帮助我们在出现问题时更好地排除故障。通过对Spring Boot启动流程的阐明,我们可以更好地维护和优化自己的应用程序。

在本文中,我们了解了以下内容:

  • Launcher类的作用和主要构造函数
  • PropertiesLauncher的作用和启动过程
  • SpringApplication对象的创建和配置
  • 应用程序的启动过程

感谢您阅读本文。如果您有任何疑问或反馈,请在下面的评论区留言。