Spring Boot 应用启动机制详解
IDEA 中启动 Spring Boot 的详细过程
1. 预启动阶段
1.1 环境检测与验证
- JDK 版本兼容性验证
- 项目依赖完整性检查
- Spring Boot 版本与插件匹配
- 构建工具配置验证(Maven/Gradle)
- 应用配置文件语法检查
1.2 类路径构建
类路径组成:
├── 项目编译输出目录 (target/classes 或 build/classes)
├── 依赖库 (Maven: ~/.m2/repository, Gradle: ~/.gradle/caches)
├── 资源文件 (src/main/resources)
├── 测试资源文件 (src/test/resources) [测试时]
└── IDEA 特定模块路径
2. Spring Boot 应用启动核心流程
2.1 SpringApplication 初始化阶段
public class SpringApplication {public SpringApplication(Class<?>... primarySources) {this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));this.webApplicationType = WebApplicationType.deduceFromClasspath();setInitializers(getSpringFactoriesInstances(ApplicationContextInitializer.class));setListeners(getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass = deduceMainApplicationClass();}
}
2.2 运行阶段详细分解
public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();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();context.setApplicationStartup(this.applicationStartup);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);listeners.ready(context, stopWatch);} catch (Throwable ex) {handleRunFailure(context, listeners, ex);throw new IllegalStateException(ex);}return context;
}
3. 上下文刷新详细过程
3.1 BeanFactory 初始化流程
@Override
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");prepareRefresh();ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();prepareBeanFactory(beanFactory);try {postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");invokeBeanFactoryPostProcessors(beanFactory);registerBeanPostProcessors(beanFactory);beanPostProcess.end();initMessageSource();initApplicationEventMulticaster();onRefresh();registerListeners();finishBeanFactoryInitialization(beanFactory);finishRefresh();} catch (BeansException ex) {} finally {resetCommonCaches();contextRefresh.end();}}
}
3.2 Bean 创建生命周期
1. 实例化 Bean (构造函数调用)
2. 属性注入 (@Autowired, @Value, @Resource)
3. Aware 接口回调 (BeanNameAware, BeanFactoryAware, ApplicationContextAware)
4. BeanPostProcessor.postProcessBeforeInitialization()
5. @PostConstruct 方法执行
6. InitializingBean.afterPropertiesSet() 执行
7. 自定义初始化方法 (init-method)
8. BeanPostProcessor.postProcessAfterInitialization()
9. Bean 就绪,加入单例池
10. 应用场景:- 单例 Bean: 启动时创建- 原型 Bean: 每次获取时创建- 延迟加载: 第一次使用时创建
4. Spring Boot 自动配置机制
4.1 条件化配置加载
@SpringBootApplication
├── @SpringBootConfiguration
├── @EnableAutoConfiguration
│ └── @Import(AutoConfigurationImportSelector.class)
└── @ComponentScan
1. 加载 META-INF/spring.factories 中所有 EnableAutoConfiguration 配置
2. 根据条件注解过滤:- @ConditionalOnClass- @ConditionalOnBean- @ConditionalOnProperty- @ConditionalOnWebApplication- @ConditionalOnMissingBean
3. 按 @AutoConfigureOrder、@Order 排序
4. 去重并应用配置类
4.2 内嵌 Web 服务器启动
1. ServletWebServerApplicationContext.onRefresh()
2. createWebServer() 创建 WebServer
3. TomcatServletWebServerFactory.getWebServer()- 创建 Tomcat 实例- 配置 Engine 和 Host- 创建 Connector(配置端口、协议等)- 创建 Context 并配置- 加载 DispatcherServlet- 配置 Session、ErrorPage 等
4. 启动 Tomcat- 启动 Connector 监听端口- 启动 Engine 处理请求
5. 发布 ServletWebServerInitializedEvent
服务器部署启动的详细过程
1. 打包与部署准备
1.1 可执行 JAR 结构
my-application.jar
├── META-INF/
│ └── MANIFEST.MF
├── BOOT-INF/
│ ├── classes/ # 应用类文件
│ │ ├── com/yourcompany/Application.class
│ │ └── application.properties
│ └── lib/ # 依赖库
│ ├── spring-boot-2.7.x.jar
│ ├── spring-core-5.3.x.jar
│ └── ...
└── org/springframework/boot/loader/├── JarLauncher.class└── LaunchedURLClassLoader.class
1.2 启动脚本示例
#!/bin/bash
JAVA_OPTS="-server -Xms2g -Xmx2g -XX:+UseG1GC"
JAVA_OPTS="$JAVA_OPTS -XX:MaxGCPauseMillis=200"
JAVA_OPTS="$JAVA_OPTS -Dspring.profiles.active=prod"
JAVA_OPTS="$JAVA_OPTS -Dlogging.file=/var/log/myapp/application.log"
java $JAVA_OPTS -jar my-application.jar
2. 生产环境启动流程
2.1 启动类加载器机制
JarLauncher -> LaunchedURLClassLoader↓
加载 BOOT-INF/classes 和 BOOT-INF/lib
2.2 生产环境特定配置
spring:datasource:url: jdbc:mysql://prod-db:3306/myappusername: ${DB_USERNAME}password: ${DB_PASSWORD}redis:host: redis-clusterport: 6379server:port: 8080compression:enabled: trueservlet:session:timeout: 30mmanagement:endpoints:web:exposure:include: health,info,metricsendpoint:health:show-details: always
本地启动与服务器启动的异同点对比
1. 环境配置差异
特性 | IDEA 本地启动 | 服务器部署启动 |
---|
类加载机制 | 标准 ClassLoader | LaunchedURLClassLoader |
配置文件加载 | 文件系统直接读取 | JAR 包内资源读取 |
热部署支持 | DevTools 自动重启 | 需要手动重启 |
调试支持 | 完整调试功能 | 远程调试需配置 |
资源监控 | IDEA 内置工具 | JMX/Actuator 监控 |
2. 性能特征对比
2.1 启动时间分析
启动阶段 | 时间占比
------------------------------------
类路径扫描和加载 | 15-20%
Bean 定义解析 | 20-25%
Bean 实例化和依赖注入 | 30-35%
Web 服务器启动 | 15-20%
其他初始化 | 10-15%
启动阶段 | 时间占比
------------------------------------
JAR 解压和类加载 | 25-30%
Bean 定义解析 | 20-25%
Bean 实例化和依赖注入 | 25-30%
Web 服务器启动 | 15-20%
其他初始化 | 5-10%
2.2 内存使用对比
-Xms512m -Xmx1024m -XX:MaxMetaspaceSize=256m
-Xms2g -Xmx2g -XX:MaxMetaspaceSize=512m
-XX:+UseG1GC -XX:MaxGCPauseMillis=200
3. 配置管理差异
3.1 配置文件加载策略
# 开发环境配置优先级
1. @TestPropertySource
2. 命令行参数 (IDEA Run Configuration)
3. SPRING_APPLICATION_JSON
4. ServletConfig 初始化参数
5. ServletContext 初始化参数
6. JNDI 属性
7. Java 系统属性
8. 操作系统环境变量
9. random.* 属性
10. application-{profile}.properties/yml
11. application.properties/yml
12. @PropertySource
13. 默认属性# 生产环境配置优先级
1. 命令行参数 (启动脚本)
2. SPRING_APPLICATION_JSON
3. Java 系统属性
4. 操作系统环境变量
5. random.* 属性
6. application-{profile}.properties/yml (打包在JAR内)
7. application.properties/yml (打包在JAR内)
8. 默认属性
3.2 日志配置差异
logging:level:com.yourcompany: DEBUGorg.springframework: INFOpattern:console: "%clr(%d{HH:mm:ss.SSS}){faint} %clr(%-5level) %clr(${PID}){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wEx"
logging:file:path: /var/log/myappname: /var/log/myapp/application.loglevel:com.yourcompany: INFOorg.springframework: WARNpattern:file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
4. 监控和管理差异
4.1 开发环境监控
- 内存使用情况实时监控
- CPU 使用率分析
- 线程状态查看
- 断点调试和变量查看
- 方法执行时间分析
- 自动重启
- LiveReload
- 全局配置
- 远程调试支持
4.2 生产环境监控
management:endpoints:web:exposure:include: health,info,metrics,env,beansbase-path: /manageendpoint:health:show-details: alwaysprobes:enabled: truemetrics:enabled: truemetrics:export:prometheus:enabled: true
spring:boot:admin:client:url: http://monitoring-server:8080
性能优化建议
1. 启动性能优化
1.1 类路径优化
@SpringBootApplication
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class,DataSourceTransactionManagerAuto.class
})
public class Application {public static void main(String[] args) {SpringApplication app = new SpringApplication(Application.class);app.setLazyInitialization(true); app.run(args);}
}
1.2 Bean 初始化优化
@Component
public class HeavyBean {@PostConstructpublic void init() {CompletableFuture.runAsync(() -> {heavyInitialization();});}@Bean@Lazypublic ExpensiveService expensiveService() {return new ExpensiveService();}
}
2. 内存使用优化
2.1 JVM 参数调优
java -server -Xms2g -Xmx2g \-XX:+UseG1GC -XX:MaxGCPauseMillis=200 \-XX:InitiatingHeapOccupancyPercent=45 \-XX:+ExplicitGCInvokesConcurrent \-Xlog:gc*:file=/var/log/myapp/gc.log:time,uptime,level,tags:filecount=5,filesize=10m \-jar my-application.jar
常见问题与解决方案
1. 启动失败问题
1.1 类冲突问题
<dependency><groupId>com.some.library</groupId><artifactId>problematic-lib</artifactId><exclusions><exclusion><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId></exclusion></exclusions>
</dependency>
<dependencyManagement><dependencies><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-bom</artifactId><version>2.13.0</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement>
1.2 配置加载问题
# 配置加载顺序问题解决方案
# 1. 使用明确的配置文件
spring.config.location=classpath:/,classpath:/config/,file:./,file:./config/# 2. 环境变量覆盖
export SPRING_APPLICATION_JSON='{"server":{"port":8080}}'# 3. 配置属性验证
@Component
@ConfigurationProperties(prefix = "app.datasource")
@Validated
public class DataSourceProperties {@NotEmptyprivate String url;// getters and setters
}
2. 性能问题诊断
2.1 启动时间分析
@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication app = new SpringApplication(Application.class);app.addListeners(new ApplicationListener<ApplicationReadyEvent>() {@Overridepublic void onApplicationEvent(ApplicationReadyEvent event) {log.info("Application started in {} seconds", ManagementFactory.getRuntimeMXBean().getUptime() / 1000.0);}});app.run(args);}
}
management.endpoints.web.exposure.include=startup