spring boot 通过 main 方法启动 web 项目的过程涉及多个核心组件和自动化机制,下面从源码角度详细拆解:
1. 启动入口:springapplication.run()
@springbootapplication
public class demoapplication {
public static void main(string[] args) {
springapplication.run(demoapplication.class, args);
}
}
springapplication.run() 是启动的核心入口,它主要完成以下工作:
2. springapplication初始化
// springapplication 构造函数核心逻辑
public springapplication(resourceloader resourceloader, class<?>... primarysources) {
// 1. 设置资源加载器
this.resourceloader = resourceloader;
// 2. 校验并保存主配置类(即 @springbootapplication 标注的类)
this.primarysources = new linkedhashset<>(arrays.aslist(primarysources));
// 3. 推断应用类型(reactive、servlet、none)
this.webapplicationtype = webapplicationtype.deducefromclasspath();
// 4. 加载并实例化 applicationcontextinitializer
setinitializers((collection) getspringfactoriesinstances(applicationcontextinitializer.class));
// 5. 加载并实例化 applicationlistener
setlisteners((collection) getspringfactoriesinstances(applicationlistener.class));
// 6. 推断 main 方法所在类
this.mainapplicationclass = deducemainapplicationclass();
}
关键步骤:
- 应用类型推断:通过检查类路径中是否存在
org.springframework.web.reactive.dispatcherhandler(reactive)或javax.servlet.servlet(servlet)来确定应用类型。 - 初始化器(initializer):从
meta-inf/spring.factories加载applicationcontextinitializer,用于在applicationcontext刷新前自定义配置。 - 监听器(listener):加载
applicationlistener,监听启动过程中的事件(如applicationstartingevent)。
3. run()方法核心流程
public configurableapplicationcontext run(string... args) {
// 1. 计时和发布启动事件
stopwatch stopwatch = new stopwatch();
stopwatch.start();
configurableapplicationcontext context = null;
collection<springbootexceptionreporter> exceptionreporters = new arraylist<>();
configureheadlessproperty();
// 2. 获取并启动监听器
springapplicationrunlisteners listeners = getrunlisteners(args);
listeners.starting();
try {
// 3. 构建应用参数和环境配置
applicationarguments applicationarguments = new defaultapplicationarguments(args);
configurableenvironment environment = prepareenvironment(listeners, applicationarguments);
// 4. 创建并配置 applicationcontext
context = createapplicationcontext();
exceptionreporters = getspringfactoriesinstances(springbootexceptionreporter.class,
new class[] { configurableapplicationcontext.class }, context);
// 5. 准备上下文(加载 bean 定义)
preparecontext(context, environment, listeners, applicationarguments, printedbanner);
// 6. 刷新上下文(核心启动逻辑)
refreshcontext(context);
// 7. 刷新后的回调处理
afterrefresh(context, applicationarguments);
// 8. 发布应用就绪事件
listeners.started(context);
// 9. 执行 runner(如 commandlinerunner)
callrunners(context, applicationarguments);
}
catch (throwable ex) {
handlerunfailure(context, ex, exceptionreporters, listeners);
throw new illegalstateexception(ex);
}
stopwatch.stop();
if (this.logstartupinfo) {
new startupinfologger(this.mainapplicationclass).logstarted(getapplicationlog(), stopwatch);
}
// 10. 发布应用运行中事件
listeners.running(context);
return context;
}
4. 嵌入式 web 服务器启动关键点
4.1refreshcontext()方法触发服务器启动
private void refreshcontext(configurableapplicationcontext context) {
refresh(context);
if (this.registershutdownhook) {
try {
context.registershutdownhook();
}
catch (accesscontrolexception ex) {
// not allowed in some environments.
}
}
}
protected void refresh(configurableapplicationcontext context) {
// 调用 abstractapplicationcontext 的 refresh() 方法
context.refresh();
}
4.2servletwebserverapplicationcontext的核心作用
对于 web 应用,applicationcontext 实际类型为 annotationconfigservletwebserverapplicationcontext,它继承自 servletwebserverapplicationcontext,后者在 refresh() 过程中会:
// servletwebserverapplicationcontext 核心方法
@override
protected void onrefresh() {
super.onrefresh();
try {
// 创建并启动嵌入式 web 服务器
createwebserver();
}
catch (throwable ex) {
throw new applicationcontextexception("unable to start web server", ex);
}
}
private void createwebserver() {
webserver webserver = this.webserver;
servletcontext servletcontext = getservletcontext();
if (webserver == null && servletcontext == null) {
// 1. 获取 servletwebserverfactory(如 tomcatservletwebserverfactory)
servletwebserverfactory factory = getwebserverfactory();
// 2. 创建并配置 web 服务器
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();
}
4.3servletwebserverfactory实例化服务器
以 tomcat 为例,tomcatservletwebserverfactory 的 getwebserver() 方法会:
@override
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());
connector connector = new connector(this.protocol);
tomcat.getservice().addconnector(connector);
customizeconnector(connector);
tomcat.setconnector(connector);
tomcat.gethost().setautodeploy(false);
// 3. 配置 servletcontextinitializer(如 dispatcherservlet)
preparecontext(tomcat.gethost(), initializers);
// 4. 启动服务器
return gettomcatwebserver(tomcat);
}
5. spring mvc 组件自动配置
通过 webmvcautoconfiguration 自动配置核心组件:
dispatcherservlet:作为前端控制器,处理所有 http 请求。handlermapping:映射 url 到具体的 controller 方法。viewresolver:解析视图名称到实际视图。
关键代码(webmvcautoconfiguration):
@bean
@primary
@conditionalonmissingbean(dispatcherservlet.class)
public dispatcherservlet dispatcherservlet(webmvcproperties properties) {
dispatcherservlet dispatcherservlet = new dispatcherservlet();
dispatcherservlet.setdispatchoptionsrequest(properties.isdispatchoptionsrequest());
dispatcherservlet.setdispatchtracerequest(properties.isdispatchtracerequest());
dispatcherservlet.setthrowexceptionifnohandlerfound(properties.isthrowexceptionifnohandlerfound());
dispatcherservlet.setpublishevents(properties.ispublishrequesthandledevents());
dispatcherservlet.setenableloggingrequestdetails(properties.islogrequestdetails());
return dispatcherservlet;
}
6. 最终启动结果
- 嵌入式服务器(如 tomcat)启动并监听指定端口(默认 8080)。
dispatcherservlet注册到 servlet 容器,作为所有请求的入口。- spring 上下文初始化完成,所有 bean 已加载并可用。
applicationreadyevent发布,标志应用可处理外部请求。
总结:启动流程关键点
springapplication初始化:推断应用类型、加载初始化器和监听器。- 环境配置:加载
application.properties等配置源。 applicationcontext创建:根据 web 类型选择相应的上下文实现。- 自动配置:基于依赖和条件注解,自动配置 web 组件(如
dispatcherservlet)。 - 嵌入式服务器启动:通过
servletwebserverfactory创建并启动 tomcat/jetty。 - spring mvc 初始化:配置请求映射、视图解析等核心组件。
通过这种机制,spring boot 实现了“零配置”启动 web 项目的能力,开发者只需关注业务逻辑,无需手动处理服务器配置和组件装配。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论