spring boot的启动过程是一个精心设计的自动化流程,下面我将详细阐述从main方法开始到内嵌tomcat启动的全过程。
1. 入口:main方法
一切始于一个简单的main方法:
@springbootapplication
public class myapplication {
public static void main(string[] args) {
springapplication.run(myapplication.class, args);
}
}
2. springapplication初始化
springapplication.run()方法内部会创建一个springapplication实例:
public static configurableapplicationcontext run(class<?> primarysource, string... args) {
return new springapplication(primarysource).run(args);
}
2.1 构造阶段
在springapplication构造函数中完成以下关键操作:
- 推断应用类型:判断是servlet应用(spring mvc)还是reactive应用(spring webflux)
- 加载applicationcontextinitializer:通过meta-inf/spring.factories加载
- 加载applicationlistener:同样通过spring.factories机制加载
- 推断主配置类:通过堆栈分析找到包含main方法的类
3. 运行阶段:run()方法
run()方法是整个启动过程的核心:
public configurableapplicationcontext run(string... args) {
// 1. 创建并启动计时器
stopwatch stopwatch = new stopwatch();
stopwatch.start();
// 2. 初始化应用上下文和异常报告器
configurableapplicationcontext context = null;
collection<springbootexceptionreporter> exceptionreporters = new arraylist<>();
configureheadlessproperty();
// 3. 获取springapplicationrunlisteners并启动
springapplicationrunlisteners listeners = getrunlisteners(args);
listeners.starting();
try {
// 4. 准备环境
applicationarguments applicationarguments = new defaultapplicationarguments(args);
configurableenvironment environment = prepareenvironment(listeners, applicationarguments);
// 5. 打印banner
banner printedbanner = printbanner(environment);
// 6. 创建应用上下文
context = createapplicationcontext();
// 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);
}
listeners.started(context);
// 11. 执行runner
callrunners(context, applicationarguments);
}
catch (throwable ex) {
handlerunfailure(context, ex, exceptionreporters, listeners);
throw new illegalstateexception(ex);
}
try {
listeners.running(context);
}
catch (throwable ex) {
handlerunfailure(context, ex, exceptionreporters, null);
throw new illegalstateexception(ex);
}
return context;
}4. 创建应用上下文
createapplicationcontext()方法根据应用类型创建不同的应用上下文:
- servlet环境:创建
annotationconfigservletwebserverapplicationcontext - reactive环境:创建
annotationconfigreactivewebserverapplicationcontext - 普通环境:创建
annotationconfigapplicationcontext
对于web应用,会创建annotationconfigservletwebserverapplicationcontext,它继承自servletwebserverapplicationcontext。
5. 准备应用上下文
preparecontext()方法完成以下工作:
- 将环境绑定到上下文
- 后置处理上下文
- 应用所有初始化器
- 发布contextprepared事件
- 注册主配置类bean定义
- 发布contextloaded事件
6. 刷新应用上下文
refreshcontext()最终调用abstractapplicationcontext.refresh(),这是spring容器的核心刷新流程:
public void refresh() throws beansexception, illegalstateexception {
synchronized (this.startupshutdownmonitor) {
// 1. 准备刷新
preparerefresh();
// 2. 获取新的beanfactory
configurablelistablebeanfactory beanfactory = obtainfreshbeanfactory();
// 3. 准备beanfactory
preparebeanfactory(beanfactory);
try {
// 4. 后置处理beanfactory
postprocessbeanfactory(beanfactory);
// 5. 调用beanfactorypostprocessor
invokebeanfactorypostprocessors(beanfactory);
// 6. 注册beanpostprocessor
registerbeanpostprocessors(beanfactory);
// 7. 初始化messagesource
initmessagesource();
// 8. 初始化事件广播器
initapplicationeventmulticaster();
// 9. 初始化特殊bean(由子类实现)
onrefresh();
// 10. 注册监听器
registerlisteners();
// 11. 初始化所有非懒加载单例
finishbeanfactoryinitialization(beanfactory);
// 12. 完成刷新
finishrefresh();
}
catch (beansexception ex) {
// 处理异常...
}
}
}7. 内嵌tomcat启动的关键:onrefresh()
对于servlet web应用,servletwebserverapplicationcontext重写了onrefresh()方法:
protected void onrefresh() {
super.onrefresh();
try {
createwebserver();
}
catch (throwable ex) {
throw new applicationcontextexception("unable to start web server", ex);
}
}createwebserver()是内嵌服务器启动的关键:
private void createwebserver() {
webserver webserver = this.webserver;
servletcontext servletcontext = getservletcontext();
if (webserver == null && servletcontext == null) {
// 1. 获取webserver工厂(tomcat, jetty或undertow)
servletwebserverfactory factory = getwebserverfactory();
// 2. 创建webserver
this.webserver = factory.getwebserver(getselfinitializer());
}
else if (servletcontext != null) {
try {
getselfinitializer().onstartup(servletcontext);
}
catch (servletexception ex) {
throw new applicationcontextexception("cannot initialize servlet context", ex);
}
}
initpropertysources();
}8. tomcat服务器创建过程
以tomcat为例,tomcatservletwebserverfactory.getwebserver()方法:
public webserver getwebserver(servletcontextinitializer... initializers) {
// 1. 创建tomcat实例
tomcat tomcat = new tomcat();
// 2. 配置基础目录
file basedir = (this.basedirectory != null) ? this.basedirectory : createtempdir("tomcat");
tomcat.setbasedir(basedir.getabsolutepath());
// 3. 配置连接器
connector connector = new connector(this.protocol);
connector.setthrowonfailure(true);
tomcat.getservice().addconnector(connector);
customizeconnector(connector);
tomcat.setconnector(connector);
// 4. 配置host
tomcat.gethost().setautodeploy(false);
configureengine(tomcat.getengine());
// 5. 准备上下文
preparecontext(tomcat.gethost(), initializers);
// 6. 创建tomcatwebserver并启动
return gettomcatwebserver(tomcat);
}9. 启动tomcat
在tomcatwebserver构造函数中完成tomcat的启动:
public tomcatwebserver(tomcat tomcat, boolean autostart) {
this.tomcat = tomcat;
this.autostart = autostart;
initialize();
}
private void initialize() throws webserverexception {
// 启动tomcat
this.tomcat.start();
// 启动一个守护线程来等待停止命令
startdaemonawaitthread();
}10. 自动配置的关键
整个过程中,自动配置是通过@springbootapplication注解中的@enableautoconfiguration实现的:
- 在
invokebeanfactorypostprocessors()阶段会处理自动配置 autoconfigurationimportselector会加载meta-inf/spring/org.springframework.boot.autoconfigure.autoconfiguration.imports文件中的配置类- 对于tomcat,会加载
servletwebserverfactoryautoconfiguration - 这个配置类通过
@import引入了embeddedtomcat等配置
总结流程
- 启动main方法
- 创建springapplication实例
- 运行run()方法
- 准备环境
- 创建应用上下文(annotationconfigservletwebserverapplicationcontext)
- 准备上下文(注册配置类等)
- 刷新上下文(核心)
- 调用onrefresh()
- 创建内嵌web服务器(tomcat)
- 启动tomcat
- 发布启动完成事件
- 执行runner
到此这篇关于spring boot从main方法到内嵌tomcat的全过程(自动化流程)的文章就介绍到这了,更多相关spring boot启动过程内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论