springboot整合mvc DispatcherServlet注册tomcat代码分析

根据自动装配原理:会初始化该类

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方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值