启动流程
-
主方法:
应用程序从main
方法开始,调用SpringApplication.run()
,传入主类和命令行参数。 -
创建应用上下文:
SpringApplication
通过createApplicationContext()
方法根据应用类型创建ApplicationContext
实例(通常是AnnotationConfigApplicationContext
或WebApplicationContext
)。 -
设置上下文环境:
通过prepareEnvironment()
方法配置Environment
,加载系统属性、环境变量、配置文件等,确保环境在应用启动时可用。 -
加载配置:
load()
方法根据配置类、配置文件(如application.properties
或application.yml
)以及@PropertySource
注解加载属性,准备应用配置。 -
注册Bean:
执行registerBean()
,扫描@ComponentScan
指定的包,查找并注册被@Component
、@Service
、@Repository
、@Controller
等注解标记的类为Spring Bean。 -
处理条件注解:
使用@Conditional
等注解进行条件判断,决定是否加载特定的Bean。这一过程涉及到ConditionEvaluator
,它根据条件逻辑判断Bean的注册。 -
事件发布:
发布ApplicationEnvironmentPreparedEvent
事件,允许监听器在上下文环境准备后进行配置。发布ApplicationPreparedEvent
事件,表示上下文已准备好,但尚未刷新。 -
执行CommandLineRunner和ApplicationRunner:
在上下文刷新后,执行实现了CommandLineRunner
或ApplicationRunner
接口的run
方法,用于执行自定义的初始化逻辑。 -
启动Web服务器(如果是Web应用):
对于Web应用,SpringApplication
会创建并启动嵌入式Web服务器(如Tomcat、Jetty),调用WebServerFactory
进行配置。 -
应用就绪:
最后发布ApplicationReadyEvent
,标志着应用已完全启动,所有Bean均已初始化并可供使用。
结合Spring Boot的源码进行详细分析
1. 主方法
在Spring Boot应用的主类中,我们通常会看到如下代码:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
-
SpringApplication.run()
是启动的入口,实质上是调用了SpringApplication
类的方法。
SpringApplication
类是核心类之一,其构造函数如下:
public SpringApplication(Class<?>... primarySources) {
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
}
-
primarySources
参数指定了主应用类,用于后续的上下文创建和Bean注册。
2. 创建应用上下文
SpringApplication.run()
的实现:
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return new SpringApplication(primarySource).run(args);
}
-
run(args)
会创建ApplicationContext
,通常是AnnotationConfigApplicationContext
或WebApplicationContext
。
3. 设置上下文环境
run()
方法内部:
private ConfigurableApplicationContext run(String[] args) {
ConfigurableApplicationContext context = createApplicationContext();
prepareEnvironment(context.getEnvironment());
context.refresh();
return context;
}
-
prepareEnvironment(context.getEnvironment())
加载系统属性、环境变量和配置文件(如application.properties
)到Environment
中。
4. 加载配置
在prepareContext()
方法中,会使用ApplicationConfigFileApplicationListener
来处理配置文件:
protected void prepareContext(ConfigurableApplicationContext context, Environment environment) {
context.setEnvironment(environment);
// 处理配置文件
new ApplicationConfigFileApplicationListener().onApplicationEvent(event);
}
-
ApplicationConfigFileApplicationListener
会解析application.properties
和application.yml
,并将其属性加载到环境中。
5. 注册Bean
refresh()
方法会触发Bean注册:
public void refresh() {
// 创建并注册所有Bean
this.beanFactory = createBeanFactory();
registerBeanDefinitions();
}
-
registerBeanDefinitions()
会扫描被@Component
、@Service
等注解标记的类,并注册为Spring Bean。
6. 处理条件注解
在Bean的注册过程中,Spring Boot会处理条件注解:
if (condition.matches(context, metadata)) {
// 注册条件符合的Bean
}
-
ConditionEvaluator
类会根据条件判断是否加载特定的Bean。
7. 事件发布
在上下文准备好后,Spring Boot会发布事件:
publishEvent(new ApplicationEnvironmentPreparedEvent(this, environment, args));
-
ApplicationPreparedEvent
和其他事件允许开发者注册监听器进行响应。
8. 执行CommandLineRunner和ApplicationRunner
在上下文刷新后,执行实现了CommandLineRunner
或ApplicationRunner
的Bean:
for (CommandLineRunner runner : getCommandLineRunners()) {
runner.run(args);
}
-
这允许开发者在应用启动后执行自定义逻辑。
9. 启动Web服务器
对于Web应用,Spring Boot会启动嵌入式Web服务器:
this.webServer = this.webServerFactory.getWebServer(this::onStartup);
-
WebServerFactory
负责创建并启动如Tomcat、Jetty等服务器。
10. 应用就绪
最后,发布ApplicationReadyEvent
:
publishEvent(new ApplicationReadyEvent(this, args));
-
这标志着应用完全启动,所有Bean均已初始化,可以接受请求。