idea中启动springboot的过程
1. 预启动阶段
1.1 环境检测与验证
// idea 执行的前置检查
- - 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) {
// 1. 主配置类存储
this.primarysources = new linkedhashset<>(arrays.aslist(primarysources));
// 2. 推断应用类型
this.webapplicationtype = webapplicationtype.deducefromclasspath();
// 3. 加载 applicationcontextinitializer
setinitializers(getspringfactoriesinstances(
applicationcontextinitializer.class));
// 4. 加载 applicationlistener
setlisteners(getspringfactoriesinstances(applicationlistener.class));
// 5. 推断主应用类
this.mainapplicationclass = deducemainapplicationclass();
}
}
2.2 运行阶段详细分解
public configurableapplicationcontext run(string... args) {
// 阶段 1: 启动准备
stopwatch stopwatch = new stopwatch();
stopwatch.start();
// 阶段 2: 监听器通知 - applicationstartingevent
springapplicationrunlisteners listeners = getrunlisteners(args);
listeners.starting();
try {
// 阶段 3: 环境准备
applicationarguments applicationarguments =
new defaultapplicationarguments(args);
configurableenvironment environment = prepareenvironment(listeners, applicationarguments);
// 阶段 4: 配置忽略的 bean 信息
configureignorebeaninfo(environment);
// 阶段 5: 打印 banner
banner printedbanner = printbanner(environment);
// 阶段 6: 创建应用上下文
context = createapplicationcontext();
context.setapplicationstartup(this.applicationstartup);
// 阶段 7: 准备上下文
preparecontext(context, environment, listeners,
applicationarguments, printedbanner);
// 阶段 8: 刷新上下文(核心)
refreshcontext(context);
// 阶段 9: 刷新后处理
afterrefresh(context, applicationarguments);
// 阶段 10: 启动完成通知
stopwatch.stop();
if (this.logstartupinfo) {
new startupinfologger(this.mainapplicationclass)
.logstarted(getapplicationlog(), stopwatch);
}
// 阶段 11: 发布 applicationreadyevent
listeners.started(context);
// 阶段 12: 执行 runner bean
callrunners(context, applicationarguments);
// 阶段 13: 发布 applicationstartedevent
listeners.ready(context, stopwatch);
} catch (throwable ex) {
handlerunfailure(context, listeners, ex);
throw new illegalstateexception(ex);
}
return context;
}
3. 上下文刷新详细过程
3.1 beanfactory 初始化流程
// abstractapplicationcontext.refresh() 完整流程
@override
public void refresh() throws beansexception, illegalstateexception {
synchronized (this.startupshutdownmonitor) {
startupstep contextrefresh = this.applicationstartup.start("spring.context.refresh");
// 步骤 1: 准备刷新 - 设置启动日期、激活状态等
preparerefresh();
// 步骤 2: 获取新的 beanfactory
configurablelistablebeanfactory beanfactory = obtainfreshbeanfactory();
// 步骤 3: 准备 beanfactory 使用
preparebeanfactory(beanfactory);
try {
// 步骤 4: 允许 beanfactory 后处理
postprocessbeanfactory(beanfactory);
startupstep beanpostprocess = this.applicationstartup.start("spring.context.beans.post-process");
// 步骤 5: 调用 beanfactorypostprocessor
invokebeanfactorypostprocessors(beanfactory);
// 步骤 6: 注册 beanpostprocessor
registerbeanpostprocessors(beanfactory);
beanpostprocess.end();
// 步骤 7: 初始化消息源
initmessagesource();
// 步骤 8: 初始化事件广播器
initapplicationeventmulticaster();
// 步骤 9: 初始化特殊 bean(模板方法)
onrefresh();
// 步骤 10: 注册监听器
registerlisteners();
// 步骤 11: 完成 beanfactory 初始化
finishbeanfactoryinitialization(beanfactory);
// 步骤 12: 完成刷新
finishrefresh();
} catch (beansexception ex) {
// 异常处理...
} finally {
resetcommoncaches();
contextrefresh.end();
}
}
}
3.2 bean 创建生命周期
// 单个 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 // autoconfigurationimportselector 工作流程: 1. 加载 meta-inf/spring.factories 中所有 enableautoconfiguration 配置 2. 根据条件注解过滤: - @conditionalonclass - @conditionalonbean - @conditionalonproperty - @conditionalonwebapplication - @conditionalonmissingbean 3. 按 @autoconfigureorder、@order 排序 4. 去重并应用配置类
4.2 内嵌 web 服务器启动
// tomcat 启动详细过程 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 # 生产环境启动脚本 # jvm 参数配置 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 启动类加载器机制
// spring boot launcher 工作机制
jarlauncher -> launchedurlclassloader
↓
加载 boot-inf/classes 和 boot-inf/lib/*.jar
↓
反射调用应用的 main 方法
↓
后续流程与 idea 启动相同
2.2 生产环境特定配置
# application-prod.yml
spring:
datasource:
url: jdbc:mysql://prod-db:3306/myapp
username: ${db_username}
password: ${db_password}
redis:
host: redis-cluster
port: 6379
server:
port: 8080
compression:
enabled: true
servlet:
session:
timeout: 30m
management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: always
本地启动与服务器启动的异同点对比
1. 环境配置差异
| 特性 | idea 本地启动 | 服务器部署启动 |
|---|---|---|
| 类加载机制 | 标准 classloader | launchedurlclassloader |
| 配置文件加载 | 文件系统直接读取 | jar 包内资源读取 |
| 热部署支持 | devtools 自动重启 | 需要手动重启 |
| 调试支持 | 完整调试功能 | 远程调试需配置 |
| 资源监控 | idea 内置工具 | jmx/actuator 监控 |
2. 性能特征对比
2.1 启动时间分析
// 本地开发环境(idea) 启动阶段 | 时间占比 ------------------------------------ 类路径扫描和加载 | 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: debug
org.springframework: info
pattern:
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/myapp
name: /var/log/myapp/application.log
level:
com.yourcompany: info
org.springframework: warn
pattern:
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 开发环境监控
// idea 内置工具 - 内存使用情况实时监控 - cpu 使用率分析 - 线程状态查看 - 断点调试和变量查看 - 方法执行时间分析 // spring boot devtools - 自动重启 - livereload - 全局配置 - 远程调试支持
4.2 生产环境监控
# spring boot actuator 配置
management:
endpoints:
web:
exposure:
include: health,info,metrics,env,beans
base-path: /manage
endpoint:
health:
show-details: always
probes:
enabled: true
metrics:
enabled: true
metrics:
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 {
@postconstruct
public void init() {
// 异步初始化耗时操作
completablefuture.runasync(() -> {
// 耗时初始化逻辑
heavyinitialization();
});
}
// 使用 @lazy 延迟加载
@bean
@lazy
public 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 统一版本
<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 {
@notempty
private 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>() {
@override
public void onapplicationevent(applicationreadyevent event) {
// 记录启动时间
log.info("application started in {} seconds",
managementfactory.getruntimemxbean().getuptime() / 1000.0);
}
});
app.run(args);
}
}
// 或者使用 spring boot 的启动指标
management.endpoints.web.exposure.include=startup
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论