iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >SpringBoot中WEB的启动流程是什么
  • 419
分享到

SpringBoot中WEB的启动流程是什么

2023-06-29 17:06:06 419人浏览 八月长安
摘要

这篇文章主要介绍“SpringBoot中WEB的启动流程是什么”,在日常操作中,相信很多人在springBoot中WEB的启动流程是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”SpringBoot中WE

这篇文章主要介绍“SpringBootWEB的启动流程是什么”,在日常操作中,相信很多人在springBoot中WEB的启动流程是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”SpringBoot中WEB的启动流程是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

想必大家都体验过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 incorrectlyreturn 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<MultipartConfigElement> 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 {@Overridepublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {ConditionMessage.Builder message = ConditionMessage.forCondition("Default DispatcherServlet");ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();List<String> 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 {@Overridepublic 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<String> 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<String> 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

@Overridepublic 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默认是trueregistration.setAsyncSupported(isAsyncSupported());        //处理自定义的Filter进来,一般我们Filter不这么加进来,而是自己@WebFilter,或者借助Spring,          //备注:这里添加进来的Filter都仅仅只拦截过滤上面注册的dispatchServletFilter[] filters = getServletFilters();if (!ObjectUtils.isEmpty(filters)) {for (Filter filter : filters) {registerServletFilter(servletContext, filter);}}//这个很清楚:调用者若相对dispatcherServlet有自己更个性化的参数设置,复写此方法即可customizeRegistration(registration);}

1.2 把DispatcherServlet注入Servlet容器

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

@Overrideprotected 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容器中

@Overrideprotected ServletRegistration.Dynamic addRegistration(String description, ServletContext servletContext) {String name = getServletName();return servletContext.addServlet(name, this.servlet);}

到此,关于“SpringBoot中WEB的启动流程是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: SpringBoot中WEB的启动流程是什么

本文链接: https://www.lsjlt.com/news/325987.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • SpringBoot中WEB的启动流程是什么
    这篇文章主要介绍“SpringBoot中WEB的启动流程是什么”,在日常操作中,相信很多人在SpringBoot中WEB的启动流程是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”SpringBoot中WE...
    99+
    2023-06-29
  • springboot启动流程是什么
    Spring Boot 启动流程如下:1. 初始化应用程序上下文:Spring Boot 应用程序启动时,首先会创建一个 Sprin...
    99+
    2023-05-17
    springboot启动流程 springboot
  • SpringBoot中WEB的启动流程分析
    目录一、DispatcherServlet的注册1.1 把DispatcherServlet注入IOC容器1.2 把DispatcherServlet注入Servlet容器想必大家都...
    99+
    2024-04-02
  • SpringBoot 的启动流程
    SpringBoot 的启动流程 一、 生成SpringApplication对象 1. webApplicationType = 推测web应用的类型(NODE(普通项目)、SERVLET(Serv...
    99+
    2023-09-28
    spring boot spring java
  • activity启动流程是什么
    Activity启动流程是指在Android应用中启动Activity的一系列操作。它包括以下步骤:1. 调用startActivi...
    99+
    2023-09-11
    activity
  • android启动流程是什么
    Android启动流程是指从手机开机到系统完全启动的过程。具体的流程如下:1. 电源按下:当用户按下电源键时,电源管理芯片会向处理器...
    99+
    2023-10-11
    android
  • Go程序的启动流程是什么
    这篇文章主要讲解了“Go程序的启动流程是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Go程序的启动流程是什么”吧!Go 引导阶段查找入口首先编译上文提到的示例程序:$ GOF...
    99+
    2023-06-15
  • JAVA中SpringBoot启动流程分析
    目录一丶前言二丶SpringBoot启动流程分析1.获取SpringApplicationRunListener实现类,包装成SpringApplicationRunListener...
    99+
    2023-01-28
    springboot启动流程源码分析 springboot启动流程 springboot启动流程总结
  • android activity启动流程是什么
    Android Activity的启动流程如下:1. 调用`startActivity()`方法或者`startActivityFo...
    99+
    2023-08-08
    android activity
  • android launcher启动流程是什么
    Android Launcher的启动流程如下:1. 用户点击设备上的Home按钮或者通过其他方式启动Launcher应用。2. 系...
    99+
    2023-10-20
    android
  • RocketMQ broker启动流程是什么
    这篇文章主要介绍“RocketMQ broker启动流程是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“RocketMQ broker启动流程是什么”文章能帮助大家解决问题。1. 启动入口本系列...
    99+
    2023-07-05
  • linux系统的启动流程是什么
    Linux系统的启动流程主要分为以下几个阶段: BIOS/UEFI启动:计算机加电后,首先由基本输入输出系统(BIOS)或统一可...
    99+
    2024-04-02
  • 启动CentOS系统的流程是什么
    本篇内容主要讲解“启动CentOS系统的流程是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“启动CentOS系统的流程是什么”吧!当我们按下开机键后,系统背后的秘密我们是否了解呢?这里,我带...
    99+
    2023-06-10
  • Linux开机启动的流程是什么
    这篇文章主要讲解了“Linux开机启动的流程是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Linux开机启动的流程是什么”吧!Linux开机分为以下6个步骤,分别是BIOS, MBR,...
    99+
    2023-06-27
  • SpringBoot嵌入式web容器的启动原理是什么
    这篇文章将为大家详细讲解有关SpringBoot嵌入式web容器的启动原理是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。SpringBoot应用启动run方法SpringApplication.ja...
    99+
    2023-06-25
  • Spring容器启动流程是什么
    本篇内容介绍了“Spring容器启动流程是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!源码解析考虑到直接看源码是一个非常枯燥无味的过程...
    99+
    2023-06-15
  • Android framework ATMS启动流程是什么
    这篇文章主要介绍“Android framework ATMS启动流程是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Android framework ...
    99+
    2023-07-05
  • SpringBoot之启动流程详解
    目录SpringBoot启动过程简介加载应用程序上下文扫描应用程序中的所有组件自动配置应用程序环境启动嵌入式Web服务器总结SpringBoot启动过程简介 SpringBoot应用...
    99+
    2023-05-17
    SpringBoot启动流程 SpringBoot启动过程
  • Android应用程序的启动流程是什么
    本篇内容介绍了“Android应用程序的启动流程是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!应用进程的启动流程本文基于Android...
    99+
    2023-07-05
  • Android广播Broadcast的启动流程是什么
    这篇“Android广播Broadcast的启动流程是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Android广播B...
    99+
    2023-07-05
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作