⚙️SpringBoot 源码解析:深度剖析 SpringApplication 构造方法
前言 🚀
各位亲爱的开发者朋友们,今天我们继续深入探讨 SpringApplication
这一 Spring Boot 启动的核心组件。上次我们从整体上看了 SpringApplication.run()
的执行过程,今天则要聚焦于 SpringApplication
的构造方法,带你逐行解密它是如何将应用从启动类传递到 Spring 容器,再到你面前一切正常运行的状态。
你可能会想:“构造方法不就传个参数,做些简单的初始化吗?”错了!这可不是普通的构造方法,它涉及了 Spring Boot 启动过程中的一系列重要配置,自动化的核心就在这里!接下来,我们一起深入源码,看看这背后到底隐藏了多少精彩的细节。🧐
🔧 SpringApplication 构造方法的细节剖析
1. 构造方法的核心:primarySources 和 sources
首先,来看看 SpringApplication
的构造方法,它接收的第一个参数是一个或多个启动类(primarySources
)。这是构造方法中的关键部分,决定了应用的核心配置和初始化内容。
public SpringApplication(Class<?>... primarySources) {
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.sources = new LinkedHashSet<>(Arrays.asList(primarySources));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
}
这一段代码看起来很简单,但它做的事可不小!首先,primarySources
就是你传入的启动类,它们通常会被注解为 @SpringBootApplication
。Spring Boot 使用这些类来进行自动配置,识别应用的配置源。这就是构造方法的第一个关键点。
接着,这些类会被存储在一个 LinkedHashSet
中,这样做的目的是保留启动类的顺序,这对于后续的初始化器和监听器加载来说至关重要。
2. setInitializers:加载初始化器
接下来,我们进入一个非常有趣的部分——初始化器(Initializers)。setInitializers()
方法负责加载所有的 ApplicationContextInitializer
实例,初始化器的任务就是在 Spring 容器初始化之前对环境进行一些定制化的操作。这意味着你可以通过这些初始化器,修改 Spring 环境、调整容器配置,或者执行一些额外的准备工作。
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
通过 getSpringFactoriesInstances()
方法,Spring Boot 会从 spring.factories
文件中加载实现了 ApplicationContextInitializer
接口的类,这些类会在 Spring 容器启动之前自动执行。这一机制让你能够以非常灵活的方式定制 Spring 容器的行为,不再需要每次都手动配置繁琐的步骤。
3. setListeners:加载监听器
setListeners()
方法是 SpringApplication
构造方法中的另一大亮点。它负责加载所有的 ApplicationListener
实例。你可能会想,监听器和初始化器有什么区别?其实很简单:初始化器是用来在应用启动前做一些调整的,而监听器则是在应用生命周期的不同阶段(如应用上下文启动、刷新等)触发特定事件时,做出响应。
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
通过这个方法,Spring Boot 会从 spring.factories
中加载实现了 ApplicationListener
接口的类。监听器为我们提供了一个在应用启动过程中执行自定义操作的机会。你可以在这些监听器中处理像应用上下文启动、刷新和关闭等事件。
4. 如何加载 SpringFactories 实例?
说到 getSpringFactoriesInstances()
,它的作用是从 spring.factories
文件中加载配置项。Spring Boot 通过这种方式来动态加载和注册初始化器和监听器,让我们的启动过程更加灵活。这个方法通过 SpringFactoriesLoader
来实现,SpringFactoriesLoader
会根据提供的类型,加载对应的实现类。这个机制让 Spring Boot 可以根据不同的需求灵活加载各类配置和扩展。
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return SpringFactoriesLoader.loadFactories(type, getClass().getClassLoader());
}
这一段代码的作用是,通过类加载器加载 spring.factories
文件中的所有实例,保证了 Spring Boot 启动过程中的动态配置和自动化。
5. 小结:SpringApplication 构造方法的深度定制
通过上面的剖析,我们可以看到,SpringApplication
的构造方法并不仅仅是简单的赋值操作。它通过加载启动类、初始化器、监听器等多个组件,完成了对应用上下文和环境的配置。这些机制使得 Spring Boot 能够在启动时动态加载配置,最大程度地实现自动化配置。
Spring Boot 之所以如此受欢迎,正是因为它让复杂的配置变得简单,通过这种“构造方法 + 配置”模式,开发者可以专注于业务逻辑的开发,而不必过多关注框架和容器的细节。
6.示例演示
为了帮助大家更好地理解 SpringApplication
构造方法的具体实现,下面我将通过一些实际代码示例来展示每个部分是如何工作的。
1. 启动类(primarySources)
首先,我们来看 SpringApplication
是如何处理启动类 primarySources
的。假设我们有一个简单的 Spring Boot 应用,它的启动类如下:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
这里的 Application
类就是我们的启动类,它被传递给 SpringApplication.run()
方法,最终进入 SpringApplication
的构造方法。primarySources
就是这里传入的 Application.class
,表示我们希望从 Application
类开始初始化 Spring Boot 应用。
2. setInitializers:加载初始化器
在 Spring Boot 启动过程中,我们可能需要在应用上下文初始化之前执行一些自定义操作。ApplicationContextInitializer
就是实现这个需求的一个接口。你可以创建自己的初始化器并通过 SpringApplication
加载。
比如,我们创建一个简单的初始化器,它会在 Spring 容器启动之前打印一些日志:
public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("Spring Boot 应用启动前,初始化容器...");
}
}
然后,在 SpringApplication
中注册这个初始化器:
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.setInitializers(Collections.singletonList(new MyApplicationContextInitializer()));
app.run(args);
}
}
这时,当你启动应用时,MyApplicationContextInitializer
会在 Spring 容器初始化前被执行,输出 Spring Boot 应用启动前,初始化容器...
。
3. setListeners:加载监听器
监听器的作用是在应用生命周期的不同阶段响应事件。你可以通过 ApplicationListener
实现对特定事件的监听。例如,监听应用启动成功事件:
public class MyApplicationListener implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
System.out.println("Spring Boot 应用启动完成!");
}
}
然后,像初始化器一样,我们可以将监听器注册到 SpringApplication
中:
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.setListeners(Collections.singletonList(new MyApplicationListener()));
app.run(args);
}
}
在这个例子中,当 Spring Boot 应用启动完成后,控制台会输出 Spring Boot 应用启动完成!
。
4. 动态加载 SpringFactories 实例
Spring Boot 利用 spring.factories
文件来动态加载初始化器和监听器。这些工厂配置文件通常位于 src/main/resources/META-INF/spring.factories
路径下。
假设我们想要在启动时自动注册一个监听器,首先创建一个 spring.factories
文件:
# src/main/resources/META-INF/spring.factories
org.springframework.context.ApplicationListener=com.example.MyApplicationListener
然后,在 SpringApplication
中,它会通过 SpringFactoriesLoader
自动加载这个文件并将相关的监听器添加到应用中:
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
// Spring Boot 会自动加载 spring.factories 中的配置
app.run(args);
}
}
在这种方式下,你不需要显式地通过代码注册监听器,Spring Boot 会根据 spring.factories
中的配置自动加载。
5. 完整示例
将所有部分结合在一起,下面是一个完整的示例,演示了如何通过 SpringApplication
配置启动类、初始化器、监听器以及如何利用 spring.factories
动态加载配置:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
// 手动添加自定义初始化器
app.setInitializers(Collections.singletonList(new MyApplicationContextInitializer()));
// 手动添加自定义监听器
app.setListeners(Collections.singletonList(new MyApplicationListener()));
// 运行 Spring Boot 应用
app.run(args);
}
}
// 自定义的 ApplicationContextInitializer
class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("Spring Boot 应用启动前,初始化容器...");
}
}
// 自定义的 ApplicationListener
class MyApplicationListener implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
System.out.println("Spring Boot 应用启动完成!");
}
}
通过这些代码,我们可以清楚地看到 SpringApplication
如何在启动时加载和执行初始化器、监听器,以及如何使用 spring.factories
机制动态加载配置。这样,你就可以灵活地定制 Spring Boot 应用的启动过程了!🎉
代码解析:
在本次的代码演示中,我将会深入剖析每句代码,详细阐述其背后的设计思想和实现逻辑。通过这样的讲解方式,我希望能够引导同学们逐步构建起对代码的深刻理解。我会先从代码的结构开始,逐步拆解每个模块的功能和作用,并指出关键的代码段,并解释它们是如何协同运行的。通过这样的讲解和实践相结合的方式,我相信每位同学都能够对代码有更深入的理解,并能够早日将其掌握,应用到自己的学习和工作中。
在这个示例中,您展示了如何通过手动设置 ApplicationContextInitializer
和 ApplicationListener
来扩展 Spring Boot 应用的启动过程。
Application
类:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
// 手动添加自定义初始化器
app.setInitializers(Collections.singletonList(new MyApplicationContextInitializer()));
// 手动添加自定义监听器
app.setListeners(Collections.singletonList(new MyApplicationListener()));
// 运行 Spring Boot 应用
app.run(args);
}
}
SpringApplication
实例化:您通过new SpringApplication(Application.class)
创建了一个SpringApplication
对象。- 添加自定义初始化器:使用
app.setInitializers
方法手动添加了一个自定义的ApplicationContextInitializer
,它会在 Spring 应用上下文刷新之前执行。 - 添加自定义监听器:使用
app.setListeners
方法添加了一个自定义的ApplicationListener
,它会在 Spring Boot 应用启动完成后触发事件。
自定义 ApplicationContextInitializer
:
class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("Spring Boot 应用启动前,初始化容器...");
}
}
ApplicationContextInitializer
是 Spring Boot 在启动时的一个接口,允许您在 Spring 容器刷新之前进行一些初始化操作。initialize
方法会在应用上下文刷新前被调用,您可以在这里执行一些额外的逻辑,例如设置特定的属性、初始化资源等。
自定义 ApplicationListener
:
class MyApplicationListener implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
System.out.println("Spring Boot 应用启动完成!");
}
}
ApplicationListener
是一个监听 Spring 事件的接口。在这个例子中,您监听的是ApplicationReadyEvent
事件,这是 Spring Boot 应用启动完成之后发布的事件。onApplicationEvent
方法会在应用启动完成时被调用,可以在这里执行与应用启动相关的操作。
关键点:
ApplicationContextInitializer
:用于在应用上下文刷新之前进行初始化操作,通常用于修改容器的设置或初始化外部资源。ApplicationListener
:用于监听 Spring 应用启动过程中的事件。在这个例子中,我们监听的是ApplicationReadyEvent
,即应用启动完成后的事件。SpringApplication.run()
:这是 Spring Boot 启动应用的入口方法,调用后会触发 Spring Boot 的启动过程。
运行过程:
- 初始化过程:
- 在
SpringApplication
运行之前,MyApplicationContextInitializer
的initialize()
方法会被调用,输出 “Spring Boot 应用启动前,初始化容器…”。
- 在
- 应用启动:
SpringApplication.run()
会启动 Spring Boot 应用并初始化 Spring 容器。
- 启动完成:
- 当应用完全启动并准备好提供服务时,
MyApplicationListener
的onApplicationEvent()
方法会被调用,输出 “Spring Boot 应用启动完成!”。
- 当应用完全启动并准备好提供服务时,
应用场景:
ApplicationContextInitializer
:常用于在 Spring Boot 应用上下文加载之前做一些容器的初始化,比如注册自定义的Bean
、修改容器配置等。ApplicationListener
:用于监听 Spring Boot 应用生命周期中的特定事件,如应用启动完成、环境准备好等。可以在应用启动完成时执行一些初始化逻辑,或者向外部系统报告应用状态。
🧳 总结:魔法背后,SpringBoot 的“构造秘密”
今天的源码解析,让我们深入了解了 SpringApplication
构造方法的方方面面。从 primarySources
到 setInitializers
和 setListeners
,每一步都在为我们的应用启动做好充分的准备。这一切都是为了让 Spring Boot 在启动时能够自动化地完成大量的配置和初始化工作,从而大大减少了开发者的工作量。
如果你觉得今天的内容有帮助,别忘了点赞和分享!同时,如果你对 Spring Boot 有更多的疑问或者想进一步探索的地方,随时欢迎来和我一起讨论!🔥
🧧福利赠与你🧧
无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学SpringBoot」,bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门SpringBoot,就像滚雪球一样,越滚越大, 无边无际,指数级提升。
最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。
同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板、技术文章Markdown文档等海量资料。
✨️ Who am I?
我是bug菌,CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等社区博客专家,C站博客之星Top30,华为云2023年度十佳博主,掘金多年度人气作者Top40,掘金等各大社区平台签约作者,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者;全网粉丝合计 30w+;更多精彩福利点击这里;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试真题、4000G PDF电子书籍、简历模板等海量资料,你想要的我都有,关键是你不来拿。
-End-
- 点赞
- 收藏
- 关注作者
评论(0)