当前位置:

首页 > 编程开发 > SpringBoot中WEB的启动流程是什么

SpringBoot中WEB的启动流程是什么

WebStorm macOS版
WebStorm macOS版

JetBrains WebStorm 是面向 JavaScript、TypeScript 和现代 Web 技术的专业集成开发环境,可智能理解项目结构,提供代码补全、重构、错误检查、运行调试、测试及 Git 工具。

立即下载
Mac 2026-10-14
数据库 编程开发 web开发 服务器管理 集成开发环境

想必大家都体验过springboot的便捷,以前想要运行web项目,我们首先需要将项目打成war包,然后再运行Tomcat启动项目,不过自从有了springboot,我们可以像启动jar包一样简单的启动一个web项目,今天我们就来分析下springboot启动web项目整个流程。老规矩,我们从spring.factories文件开始。spring-boot-starter-web下没有spring.factories文件所以我们从spring-boot-autoconfigure下的spring.fact

本文目录

    想必大家都体验过springboot的便捷,以前想要运行web项目,我们首先需要将项目打成war包,然后再运行Tomcat启动项目,不过自从有了springboot,我们可以像启动jar包一样简单的启动一个web项目,今天我们就来分析下springboot启动web项目整个流程。

    老规矩,我们从spring.factories文件开始。

    spring-boot-starter-web下没有spring.factories文件

    SpringBoot中WEB的启动流程是什么

    所以我们从spring-boot-autoconfigure下的spring.factories开始

    SpringBoot中WEB的启动流程是什么

    一、DispatcherServlet的注册

    1.1 把DispatcherServlet注入IOC容器

    DispatcherServlet是通过DispatcherServletAutoConfiguration注册的

    @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnWebApplication(type = Type.SERVLET)
    @ConditionalOnClass(DispatcherServlet.class)
    @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
    public class DispatcherServletAutoConfiguration {
    
    	public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";
    
    	public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration";
    
    	@Configuration(proxyBeanMethods = false)
    	@Conditional(DefaultDispatcherServletCondition.class)
    	@ConditionalOnClass(ServletRegistration.class)
    	@EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class })
    	protected static class DispatcherServletConfiguration {
    
    		@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
    		public DispatcherServlet dispatcherServlet(HttpProperties httpProperties, WebMvcProperties webMvcProperties) {
    			DispatcherServlet dispatcherServlet = new DispatcherServlet();
    			dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
    			dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
    			dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
    			dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
    			dispatcherServlet.setEnableLoggingRequestDetails(httpProperties.isLogRequestDetails());
    			return dispatcherServlet;
    		}
    
    		@Bean
    		@ConditionalOnBean(MultipartResolver.class)
    		@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
    		public MultipartResolver multipartResolver(MultipartResolver resolver) {
    			// Detect if the user has created a MultipartResolver but named it incorrectly
    			return resolver;
    		}
    
    	}
    
    	@Configuration(proxyBeanMethods = false)
    	@Conditional(DispatcherServletRegistrationCondition.class)
    	@ConditionalOnClass(ServletRegistration.class)
    	@EnableConfigurationProperties(WebMvcProperties.class)
    	@Import(DispatcherServletConfiguration.class)
    	protected static class DispatcherServletRegistrationConfiguration {
    
    		@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
    		@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
    		public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
    				WebMvcProperties webMvcProperties, ObjectProvider multipartConfig) {
    			DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
    					webMvcProperties.getServlet().getPath());
    			registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
    			registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup()); 
    			multipartConfig.ifAvailable(registration::setMultipartConfig);
    			return registration;
    		}
    
    	}
    
    	@Order(Ordered.LOWEST_PRECEDENCE - 10)
    	private static class DefaultDispatcherServletCondition extends SpringBootCondition {
    
    		@Override
    		public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
    			ConditionMessage.Builder message = ConditionMessage.forCondition("Default DispatcherServlet");
    			ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    			List dispatchServletBeans = Arrays
    					.asList(beanFactory.getBeanNamesForType(DispatcherServlet.class, false, false));
    			if (dispatchServletBeans.contains(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {
    				return ConditionOutcome
    						.noMatch(message.found("dispatcher servlet bean").items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
    			}
    			if (beanFactory.containsBean(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {
    				return ConditionOutcome.noMatch(
    						message.found("non dispatcher servlet bean").items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
    			}
    			if (dispatchServletBeans.isEmpty()) {
    				return ConditionOutcome.match(message.didNotFind("dispatcher servlet beans").atAll());
    			}
    			return ConditionOutcome.match(message.found("dispatcher servlet bean", "dispatcher servlet beans")
    					.items(Style.QUOTE, dispatchServletBeans)
    					.append("and none is named " + DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
    		}
    
    	}
    
    	@Order(Ordered.LOWEST_PRECEDENCE - 10)
    	private static class DispatcherServletRegistrationCondition extends SpringBootCondition {
    
    		@Override
    		public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
    			ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    			ConditionOutcome outcome = checkDefaultDispatcherName(beanFactory);
    			if (!outcome.isMatch()) {
    				return outcome;
    			}
    			return checkServletRegistration(beanFactory);
    		}
    
    		private ConditionOutcome checkDefaultDispatcherName(ConfigurableListableBeanFactory beanFactory) {
    			List servlets = Arrays
    					.asList(beanFactory.getBeanNamesForType(DispatcherServlet.class, false, false));
    			boolean containsDispatcherBean = beanFactory.containsBean(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
    			if (containsDispatcherBean && !servlets.contains(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {
    				return ConditionOutcome.noMatch(
    						startMessage().found("non dispatcher servlet").items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
    			}
    			return ConditionOutcome.match();
    		}
    
    		private ConditionOutcome checkServletRegistration(ConfigurableListableBeanFactory beanFactory) {
    			ConditionMessage.Builder message = startMessage();
    			List registrations = Arrays
    					.asList(beanFactory.getBeanNamesForType(ServletRegistrationBean.class, false, false));
    			boolean containsDispatcherRegistrationBean = beanFactory
    					.containsBean(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
    			if (registrations.isEmpty()) {
    				if (containsDispatcherRegistrationBean) {
    					return ConditionOutcome.noMatch(message.found("non servlet registration bean")
    							.items(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
    				}
    				return ConditionOutcome.match(message.didNotFind("servlet registration bean").atAll());
    			}
    			if (registrations.contains(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)) {
    				return ConditionOutcome.noMatch(message.found("servlet registration bean")
    						.items(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
    			}
    			if (containsDispatcherRegistrationBean) {
    				return ConditionOutcome.noMatch(message.found("non servlet registration bean")
    						.items(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
    			}
    			return ConditionOutcome.match(message.found("servlet registration beans").items(Style.QUOTE, registrations)
    					.append("and none is named " + DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
    		}
    
    		private ConditionMessage.Builder startMessage() {
    			return ConditionMessage.forCondition("DispatcherServlet Registration");
    		}
    
    	}
    
    }

    这也是SpringBoot中IOC容器和WEB容器是同一个的原因

    Spring把DispatcherServlet放到容器中后,在DispatcherServlet的初始化中会执行ApplicationContextAwareProcessor的postProcessBeforeInitialization方法,而其postProcessBeforeInitialization底层如下

    private void invokeAwareInterfaces(Object bean) {
    		if (bean instanceof EnvironmentAware) {
    			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
    		}
    		if (bean instanceof EmbeddedValueResolverAware) {
    			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
    		}
    		if (bean instanceof ResourceLoaderAware) {
    			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
    		}
    		if (bean instanceof ApplicationEventPublisherAware) {
    			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
    		}
    		if (bean instanceof MessageSourceAware) {
    			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
    		}
    		if (bean instanceof ApplicationContextAware) {
    			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
    		}
    	}

    而DispatcherServlet是一个ApplicationContextAware,所以会执行其setApplicationContext方法,设置其属性webApplicationContext

    @Override
    	public void setApplicationContext(ApplicationContext applicationContext) {
    	   //传入ioc容器
    		if (this.webApplicationContext == null && applicationContext instanceof WebApplicationContext) {
    			this.webApplicationContext = (WebApplicationContext) applicationContext;
    			this.webApplicationContextInjected = true;
    		}
    	}

    所以在web容器启动过程会把web容器设置成和ioc容器一样,springMVC容器创建代码如下,参考文章springMVC全注解启动和容器的初始化

    protected WebApplicationContext initWebApplicationContext() {
    		WebApplicationContext rootContext =
    				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    		WebApplicationContext wac = null;
            //因为webApplicationContext这里有值了,所以会进入这里
    		if (this.webApplicationContext != null) {
    	        //把web容器设置成和ioc容器一样
    			wac = this.webApplicationContext;
    			if (wac instanceof ConfigurableWebApplicationContext) {
    				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
    				if (!cwac.isActive()) {
    					if (cwac.getParent() == null) 
    						cwac.setParent(rootContext);
    					}
    					configureAndRefreshWebApplicationContext(cwac);
    				}
    			}
    		}
    		if (wac == null) {
    			wac = findWebApplicationContext();
    			wac = createWebApplicationContext(rootContext);
    		if (!this.refreshEventReceived) {
    			synchronized (this.onRefreshMonitor) {
    				onRefresh(wac);
    		if (this.publishContext) {
    			String attrName = getServletContextAttributeName();
    			getServletContext().setAttribute(attrName, wac);
    		return wac;
    	}

    这里可能要有人问了,为什么在springMVC环境中,this.webApplicationContext为null,因为在springMVC中DispatcherServlet没有通过spring容器管理

    protected void registerDispatcherServlet(ServletContext servletContext) {
    		String servletName = getServletName();
    		Assert.hasLength(servletName, "getServletName() must not return null or empty");
            //创建web容器
    		WebApplicationContext servletAppContext = createServletApplicationContext();
    		Assert.notNull(servletAppContext, "createServletApplicationContext() must not return null");
            //创建DispatcherServlet对象
    		FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
    		Assert.notNull(dispatcherServlet, "createDispatcherServlet(WebApplicationContext) must not return null");
    		dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());
            //把dispatcherServlet作为Servlet注册到上下文中
    		ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
    		if (registration == null) {
    			throw new IllegalStateException("Failed to register servlet with name '" + servletName + "'. " +
    					"Check if there is another servlet registered under the same name.");
    		}
            //容器在启动的时候加载这个servlet,其优先级为1(正数的值越小,该servlet的优先级越高,应用启动时就越先加载)
    		registration.setLoadOnStartup(1);
    		//设置Servlet映射mapping路径
    		//getServletMappings()是模版方法,需要我们自己配置
    		registration.addMapping(getServletMappings());
    		//设置是否支持异步请求
    		//isAsyncSupported默认是true
    		registration.setAsyncSupported(isAsyncSupported());
            //处理自定义的Filter进来,一般我们Filter不这么加进来,而是自己@WebFilter,或者借助Spring,  
            //备注:这里添加进来的Filter都仅仅只拦截过滤上面注册的dispatchServlet
    		Filter[] filters = getServletFilters();
    		if (!ObjectUtils.isEmpty(filters)) {
    			for (Filter filter : filters) {
    				registerServletFilter(servletContext, filter);
    			}
    		}
    		//这个很清楚:调用者若相对dispatcherServlet有自己更个性化的参数设置,复写此方法即可
    		customizeRegistration(registration);
    	}

    1.2 把DispatcherServlet注入Servlet容器

    SpringBoot中容器是AnnotationConfigServletWebServerApplicationContext,其onRefresh()方法如下

    @Override
    protected void onRefresh() {
    	super.onRefresh();
    	try {
    		createWebServer(); //创建Servlet容器
    	}
    	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) {
    			ServletWebServerFactory factory = getWebServerFactory(); 
    			this.webServer = factory.getWebServer(getSelfInitializer());//创建容器,并执行所有ServletContextInitializer的onStartup
    		}
    		else if (servletContext != null) {
    			try {
    				getSelfInitializer().onStartup(servletContext);
    			}
    			catch (ServletException ex) {
    				throw new ApplicationContextException("Cannot initialize servlet context", ex);
    			}
    		}
    		initPropertySources();
    	}

    注意,这里他不会执行SpringServletContainerInitializer。

    流程如下
    1、通过getSelfInitializer()方法执行容器中所有的ServletContextInitializer

    private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
    	return this::selfInitialize;
    }
    private void selfInitialize(ServletContext servletContext) throws ServletException {
    	prepareWebApplicationContext(servletContext);
    	registerApplicationScope(servletContext);
    	WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
    	for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
    		beans.onStartup(servletContext);
    	}
    }

    而ServletContextInitializer有个子类ServletRegistrationBean,通过其addRegistration方法注入Servlet容器中

    @Override
    protected ServletRegistration.Dynamic addRegistration(String description, ServletContext servletContext) {
    	String name = getServletName();
    	return servletContext.addServlet(name, this.servlet);
    }
    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 web
    相关文章 更多
    Win10怎么升级专业版 系统激活与版本切换方法
    Win10怎么升级专业版 系统激活与版本切换方法

    Win10 家庭版升级专业版,可在“设置→更新和安全→激活”确认当前系统已激活,再通过“更改产品密钥”输入有效的专业版密钥,或在商店提供升级时购买并安装。版本切换通常可保留应用和文件,但家庭版许可证不会自动变成专业版授权。

    Win10升级更新报错怎么解决 系统更新缓存与重置方法
    Win10升级更新报错怎么解决 系统更新缓存与重置方法

    Win10 更新反复报错且基础排查无效时,可先停止相关更新服务,把 SoftwareDistribution 与 catroot2 缓存目录改名,再启动服务、重启电脑并重新检查更新。缓存重置会重新下载更新,但不能解决硬件不兼容、空间不足和产品许可限制。

    Win10如何强制升级系统 系统更新策略与命令行方法
    Win10如何强制升级系统 系统更新策略与命令行方法

    Win10 没有能无视兼容性、管理策略和许可限制的通用“强制升级”命令。需要主动升级时,应先恢复更新、核对目标版本策略,再通过 Windows 更新或微软升级工具发起;命令行可刷新策略和打开更新入口,但不代表系统一定会立即下载新版本。

    Win10升级后软件不兼容怎么办 系统兼容模式与修复方法
    Win10升级后软件不兼容怎么办 系统兼容模式与修复方法

    Win10 升级后软件不兼容,先更新软件和相关驱动,再对可信的旧桌面程序运行“兼容性疑难解答”或设置兼容模式。兼容模式只能调整部分运行行为,不能让旧驱动、16 位程序或不受支持的安全软件自动兼容新系统。

    Slack团队11月维护怎么安排:旧设备升级与日本AI区域申请
    Slack团队11月维护怎么安排:旧设备升级与日本AI区域申请

    Slack团队应分别检查11月9日到期的系统、客户端与浏览器,并由符合新版Business+或Enterprise+条件的主所有者申请日本AI区域推理;数据驻留和无跨区回退限制需单独确认。

    Win10怎么升级显卡驱动 系统设备管理器与更新方法
    Win10怎么升级显卡驱动 系统设备管理器与更新方法

    Win10 升级显卡驱动,先在设备管理器的“显示适配器”中确认显卡型号和当前驱动,再通过 Windows 更新或厂商正式安装包更新。设备管理器适合识别设备、安装已有驱动和回退版本;提示已安装最佳驱动,不代表厂商没有更新版本。

    Win10升级提示空间不足怎么办 系统存储清理与扩容方法
    Win10升级提示空间不足怎么办 系统存储清理与扩容方法

    Win10 升级提示空间不足,先在“设置→系统→存储→临时文件”清理可删除项目,再移动个人大文件并重试。仍不足时,可按安装程序提示使用外部存储;需要扩容 C 盘时,先确认同一磁盘右侧紧邻未分配空间,不要直接删除恢复分区或个人数据。

    Win10如何离线升级系统 系统镜像与安装介质方法
    Win10如何离线升级系统 系统镜像与安装介质方法

    Win10 离线升级可先在联网电脑上取得与目标电脑匹配的官方 ISO 或安装介质,再在目标 Win10 内运行 setup.exe,选择暂不下载更新并核对保留内容。要保留应用和资料,应走当前系统内的原地升级路线,不要直接从 USB 启动后进行全新安装。

    Win10升级后怎么回退 系统恢复功能与回滚方法
    Win10升级后怎么回退 系统恢复功能与回滚方法

    Win10 升级后回退,要先看当前系统和回退窗口:升级到 Win11 后进入“设置→系统→恢复→返回”,Win10 功能版本升级后则在“更新和安全→恢复”查找回退入口。通常只在升级后的 10 天内且旧安装文件完整时可用,开始前仍需备份新增资料。

    Win10怎么手动升级系统 系统更新助手与安装方法
    Win10怎么手动升级系统 系统更新助手与安装方法

    Win10 手动升级到最终功能版本,可运行微软 Windows 10 更新助手,检查当前版本后点击更新,等待下载与安装完成并重启。需要安装介质或保留选项时,可使用媒体创建工具;更新助手用于 Win10 功能版本升级,不等同于 Win11 安装助手。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。

    即将离开本站
    您即将前往第三方网站,请确认是否继续?