SpringbootRun方法运行原理
SpringbootRun方法运行原理
一.Spring Boot的运行原理主要涉及以下几个核心方面:
1.启动流程
Spring Boot应用的启动通常通过SpringApplication.run()方法开始:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2.SpringApplication初始化
创建SpringApplication实例:分析主配置类上的注解(如@SpringBootApplication)
推断应用类型:判断是Web应用(Servlet或Reactive)还是普通应用
加载ApplicationContextInitializer:从spring.factories加载上下文初始化器
加载ApplicationListener:从spring.factories加载事件监听器
推断主配置类:确定包含main方法的启动类
3.run方法执行过程
SpringApplication.run()方法的主要执行步骤:
启动计时器:记录应用启动时间
准备Environment:创建并配置环境变量
打印Banner:显示Spring Boot的ASCII艺术字标识
创建ApplicationContext:根据应用类型创建相应的应用上下文
准备上下文:设置环境、初始化器等
刷新上下文:
注册Bean定义
初始化所有单例Bean
启动内嵌Web服务器(如果是Web应用)
启动完成:发布应用启动完成事件
4.自动配置机制
@EnableAutoConfiguration:启用自动配置功能
条件注解:通过@Conditional系列注解控制Bean的创建条件
spring.factories:定义自动配置类的配置文件
Starter机制:提供开箱即用的依赖集合
5.核心特性
约定优于配置:减少开发者需要编写的配置
内嵌服务器:支持Tomcat、Jetty、Undertow等
外部化配置:支持多种配置方式(properties、yaml、环境变量等)
健康检查和监控:通过Actuator提供应用监控功能
pring Boot通过这些机制大大简化了Spring应用的开发和部署过程。
二.下面我将结合Spring Boot源码详细解释SpringApplication.run()方法的执行原理:
1.SpringApplication.run()入口方法
// SpringApplication.java
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
这里创建了SpringApplication实例并调用其run()方法。
2.SpringApplication构造函数
// SpringApplication.java
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 推断应用类型(NONE, SERVLET, REACTIVE)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 从spring.factories加载ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 从spring.factories加载ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断主配置类
this.mainApplicationClass = deduceMainApplicationClass();
}
3.run()方法核心实现
// SpringApplication.java
public ConfigurableApplicationContext run(String... args) {
// 启动计时器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
// 获取SpringApplicationRunListeners,用于发布事件
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 处理命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备Environment
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 打印Banner
Banner printedBanner = printBanner(environment);
// 创建ApplicationContext
context = createApplicationContext();
// 设置bootstrap上下文
context.setApplicationStartup(this.applicationStartup);
// 准备ApplicationContext
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 刷新ApplicationContext(核心步骤)
refreshContext(context);
// 刷新后的处理
afterRefresh(context, applicationArguments);
stopWatch.stop();
// 发布应用启动完成事件
listeners.started(context);
// 调用Runner接口
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
// 发布运行中事件
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
4.prepareEnvironment方法
// SpringApplication.java
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// 获取或创建Environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置Environment属性源
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 应用Environment后处理器
ConfigurationPropertySources.attach(environment);
// 发布环境准备事件
listeners.environmentPrepared(bootstrapContext, environment);
// 将环境绑定到SpringApplication
bindToSpringApplication(environment);
// 如果是非Web环境且有自定义Environment,则转换为标准Environment
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
5.createApplicationContext方法
// SpringApplication.java
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
// ApplicationContextFactory.java
@Override
public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
try {
return switch (webApplicationType) {
case SERVLET -> new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE -> new AnnotationConfigReactiveWebServerApplicationContext();
default -> new AnnotationConfigApplicationContext();
};
}
catch (Exception ex) {
throw new IllegalStateException("Unable to create configured ApplicationContext", ex);
}
}
6.prepareContext方法
// SpringApplication.java
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// 设置Environment
context.setEnvironment(environment);
// 后置处理ApplicationContext
postProcessApplicationContext(context);
// 应用ApplicationContextInitializer
applyInitializers(context);
// 发布上下文准备事件
listeners.contextPrepared(context);
bootstrapContext.close(context);
// 记录启动日志
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 添加启动相关的单例Bean
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// 加载主配置类作为Bean定义
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
// 发布上下文加载完成事件
listeners.contextLoaded(context);
}
7.refreshContext方法
// SpringApplication.java
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
shutdownHook.registerApplicationContext(context);
}
refresh(context);
}
protected void refresh(ConfigurableApplicationContext context) {
// 调用ApplicationContext的refresh方法
context.refresh();
}
context.refresh()是Spring框架的核心方法,它会完成Bean工厂的创建、Bean定义的加载、Bean实例的创建等核心工作。
8.callRunners方法
// SpringApplication.java
private void callRunners(ApplicationContext context, ApplicationArguments args) throws Exception {
List<Object> runners = new ArrayList<>();
// 获取ApplicationRunner类型的Bean
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
// 获取CommandLineRunner类型的Bean
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
// 依次执行Runner
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
通过以上源码分析可以看出,SpringApplication.run()方法是一个复杂的过程,它整合了Spring框架的核心功能,并在此基础上提供了自动配置、外部化配置、内嵌服务器等Spring Boot特有的功能。