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 项目的能力,开发者只需关注业务逻辑,无需手动处理服务器配置和组件装配。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论