springboot启动流程总结,springboot启动过程分析简书

  springboot启动流程总结,springboot启动过程分析简书

  

目录

一、调度员服务网的注册1.1 把前端控制器注入国际奥林匹克委员会容器1.2 把前端控制器注入小型应用程序容器想必大家都体验过跳羚的便捷,以前想要运行网项目,我们首先需要将项目打成战争包,然后再运行雄猫启动项目,不过自从有了跳羚队,我们可以像启动冲突包一样简单的启动一个网项目,今天我们就来分析下跳羚启动网项目整个流程。

 

  老规矩,我们从春天.工厂文件开始。

  弹簧靴起动器网下没有春天.工厂文件

  所以我们从弹簧引导自动配置下的春天.工厂开始

  

一、DispatcherServlet的注册

 

  

1.1 把DispatcherServlet注入IOC容器

调度员服务网是通过DispatcherServletAutoConfiguration注册的

 

  @AutoConfigureOrder(已订购HIGHEST _ PRECEDENCE)@ Configuration(proxy bean methods=false)@ ConditionalOnWebApplication(Type=Type .SERVLET)@条件类(dispatcherServlet。class)@ auto configure after(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= DISPATCHER SERVLET REGISTRATION ;@ Configuration(proxy bean methods=false)@ Conditional(defaultdispatcherservletcondition。class)@条件类(SERVLET注册。class)@ EnableConfigurationProperties({ http properties。class,WebMvcProperties.class })受保护的静态类DISPATCHER SERVLET configuration { @ Bean(NAME=DEFAULT _ DISPATCHER _ SERVLET _ Bean _ NAME)public DISPATCHER SERVLET DISPATCHER SERVLET(http properties,webmvc properties){ DISPATCHER DISPATCHER SERVLET。setdispatchpoptions请求(webmvc属性。isdispatchoptions request());调度程序servlet。setdispatchtracerequest(webmvc属性。isdispatchtracerequest());调度程序servlet。setthrowexceptionifnohandlerfound(web MVC属性。isthrowexceptionifnohandlerfound());调度程序servlet。setpublishevents(webmvc属性。ispublishrequesthandleevents());调度程序servlet。setenableloggingrequestdetails(http属性。islogrequestdetails());返回dispatcher servlet } @ Bean @ conditional Bean(多部分解析程序。class)@ conditional missing bean(name=dispatcher servlet .多部分_RE

  SOLVER_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的启动的文章就介绍到这了,更多相关SpringBootWEB启动内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

 

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: