根据自动装配原理:会初始化该类
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.SERVLET) //类路径下要有DispatcherServlet类才会进行自动装配 @ConditionalOnClass(DispatcherServlet.class) //一定要在ServletWebServerFactoryAutoConfiguration类后面装配 @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class) public class DispatcherServletAutoConfiguration {
声明DispatcherServlet 注入spring容器中
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) { DispatcherServlet dispatcherServlet = new DispatcherServlet(); dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest()); dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest()); dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound()); dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents()); dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails()); return dispatcherServlet; }
将注入到servlet容器中
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; }
注意上面这个DispatcherServletRegistrationBean,这个类public class DispatcherServletRegistrationBean extends ServletRegistrationBean<DispatcherServlet> implements DispatcherServletPath {
继承ServletRegistrationBean,这个类支持3种组件的注册:servlet,Listener,Filter,同时实现了ServletContextInitializer这个借口,重写onstartup方法,并调用register来想servlet注册相关组件
org.springframework.boot.web.servlet.RegistrationBean#onStartup
public final void onStartup(ServletContext servletContext) throws ServletException { String description = getDescription(); if (!isEnabled()) { logger.info(StringUtils.capitalize(description) + " was not registered (disabled)"); return; } register(description, servletContext); }
org.springframework.boot.web.servlet.DynamicRegistrationBean#register
protected final void register(String description, ServletContext servletContext) { //添加registration,返回Registration.Dynamic D registration = addRegistration(description, servletContext); if (registration == null) { logger.info(StringUtils.capitalize(description) + " was not registered (possibly already registered?)"); return; } //执行配置逻辑 configure(registration); }
总结:ServletRegistrationBean向ServletContext动态注册Servlet的逻辑,基本可以断定在这个逻辑中,DispatcherServlet注册到ServletContext中
基本组件已经分析完,那么ServletWebServer的启动过程中如何获取ServletRegistrationbean调用并进行注册?
在tomcat中的:
上节说道:
private void createWebServer() { WebServer webServer = this.webServer; ServletContext servletContext = getServletContext(); if (webServer == null && servletContext == null) { ServletWebServerFactory factory = getWebServerFactory(); //注意这个方法getSelfInitializer() this.webServer = factory.getWebServer(getSelfInitializer()); getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer)); getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer)); }
private void selfInitialize(ServletContext servletContext) throws ServletException { prepareWebApplicationContext(servletContext); registerApplicationScope(servletContext); WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext); //获取所有的ServletContextInitializerBean并调用onStartup方法 for (ServletContextInitializer beans : getServletContextInitializerBeans()) { beans.onStartup(servletContext); } }
看下如何获取ServletContextInitializerBean
protected Collection<ServletContextInitializer> getServletContextInitializerBeans() { return new ServletContextInitializerBeans(getBeanFactory()); }
public ServletContextInitializerBeans(ListableBeanFactory beanFactory, Class<? extends ServletContextInitializer>... initializerTypes) { this.initializers = new LinkedMultiValueMap<>(); this.initializerTypes = (initializerTypes.length != 0) ? Arrays.asList(initializerTypes) : Collections.singletonList(ServletContextInitializer.class); //从bean工场中获取所有的ServletContextInitializerBeans addServletContextInitializerBeans(beanFactory); addAdaptableBeans(beanFactory); List<ServletContextInitializer> sortedInitializers = this.initializers.values().stream() .flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE)) .collect(Collectors.toList()); this.sortedList = Collections.unmodifiableList(sortedInitializers); logMappings(this.initializers); }
到此完整的分析了DispatcherServlet是如何注册到Tomcat容器中的。
总结:DispatcherServlet的创建于注册过程可分为5个步骤:
1.通过自动配置类,引入DispatcherServlet
2.把DispatcherServlet封装为ServletRegistrationBean,用于自动向ServletWebServer中注册
3.在tomcat创建阶段,把SelfInitializer作为ServletContextInitializer注册到TomcatStarter中
4.把tomcatStarter作为ServletContainerInitializer注册到tomcat中。
5.在启动tomcatstart时,调用servletContainerInitializer的onStartup方法