• DispatcherServlet 注册流程


    前言

    ​ spring web 主要是要是通过 DispatcherServlet 来对请求进行分发,现在来看看他注册到 web 容器中的过程。

    版本号

    spring-boot:2.3.5
    
    注册DispatcherServlet

    ​ 在servlet 3的环境下,可以使用代码进行注册,与配置在 web.xml 中一样。主要查看在spring boot 下如何 将 DispatcherServlet 添加进ServletContext 中的代码。

    spring 提供了 ServletContextInitializer 来支持操作 ServletContext,以达到注册 Servlet、过滤器、监听器、初始参数设置等操作。

    @FunctionalInterface
    public interface ServletContextInitializer {
    
       /**
        * 使用初始化所需的所有Servlet,过滤器,监听器上下文参数和属性来配置给定的ServletContext。
        */
       void onStartup(ServletContext servletContext) throws ServletException;
    
    }
    

    ServletContextInitializer 的实现类 ServletRegistrationBean 提供了注册 Servlet的能力,而DispatcherServletRegistrationBean 实现了 ServletRegistrationBean来注册 DispatcherServlet

    // 
    public class ServletRegistrationBean<T extends Servlet> extends DynamicRegistrationBean<ServletRegistration.Dynamic> {
        @Override
        protected ServletRegistration.Dynamic addRegistration(String description, 
                                                              ServletContext servletContext) {
           String name = getServletName();
           return servletContext.addServlet(name, this.servlet);
        }
    }
    // 注册DispatcherServlet
    public class DispatcherServletRegistrationBean extends ServletRegistrationBean<DispatcherServlet>
    		implements DispatcherServletPath {
        	public DispatcherServletRegistrationBean(DispatcherServlet servlet, String path) {
    		super(servlet);
    		Assert.notNull(path, "Path must not be null");
    		this.path = path;
    		super.addUrlMappings(getServletUrlMapping());
    	}
    }    
    
    执行 ServletContextInitializer 的流程

    ​ spring boot中,启动程序准备好环境后将会进入刷新,在刷新流程中将会根据配置创建对应的web容器,如Tomcat、Jetty等,以创建tomcat 为例,在创建WebServer 中,判断使用的外部容器还是 springboot 提供的容器。

    1. 如果使用的事外部容器,则通过 BeanFactory 获取 ServletContextInitializer 实现类,并调用他的 onStartup 方法。
    2. 如果使用的是SpringBoot提供的tomcat容器,会去创建 tomcat,在创建后将启动 tomcat,执行 ServletContextInitializer的 onStartup 方法。
    //AbstractApplicationContext
    public void refresh() throws BeansException, IllegalStateException {
    	onRefresh(); // 初始化其他特殊的bean
    }
    
    
    //ServletWebServerApplicationContext
    public class ServletWebServerApplicationContext extends GenericWebApplicationContext
    		implements ConfigurableWebServerApplicationContext {
        
        @Override
    	protected void onRefresh() {
    		super.onRefresh();
    		try {
                // 这里是关键点,也就是创建webServer。
    			createWebServer();
    		}
    		catch (Throwable ex) {
    			throw new ApplicationContextException("Unable to start web server", ex);
    		}
    	}
        
        private void createWebServer() {
            // 获取当前WebServer
            WebServer webServer = this.webServer;
            // 获取Servlet上下文,如果使用外部 tomcat,则在第一次执行这个方法时,通过 SpringServletContainerInitializer 将ServletContext 传递进来,否则在创建webServer的时候进行创建。
            ServletContext servletContext = getServletContext();
            // 都为空,则说明还没有创建Web服务与 servlet 容器
            if (webServer == null && servletContext == null) {
                // 获取构造工厂
                ServletWebServerFactory factory = getWebServerFactory();
                //获取所有ServletContextInitializer类型的bean,以备webServer服务创建好之后调用
                this.webServer = factory.getWebServer(getSelfInitializer());
                // 注册web服务关闭时的处理器,进行收尾操作
                getBeanFactory().registerSingleton("webServerGracefulShutdown",
                                                   new WebServerGracefulShutdownLifecycle(this.webServer));
                getBeanFactory().registerSingleton("webServerStartStop",
                                                   new WebServerStartStopLifecycle(this, this.webServer));
            }
            // 使用外部tomcat会进入,调用 ServletContextInitializer
            else if (servletContext != null) {
                try {
                    getSelfInitializer().onStartup(servletContext);
                }
                catch (ServletException ex) {
                    throw new ApplicationContextException("Cannot initialize servlet context", ex);
                }
            }
            initPropertySources();
        }
    
    }
    

    获取 ServletContextInitializer 的代码

    // 返回匿名类,在匿名类中调用 selfInitialize 方法
    private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
       return this::selfInitialize;
    }
    
    // 在该方法中进行具体的注册操作
    private void selfInitialize(ServletContext servletContext) throws ServletException {
       // 。。。略
       // 主要关注这里,getServletContextInitializerBeans(),获取所有的ServletContextInitializerBean
       // 然后调用所有的 ServletContextInitializer#onStartup 方法向servletContext 中进行注册操作。
       for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
          beans.onStartup(servletContext);
       }
    }
     
    // 获取 ServletContextInitializer 实现类
    protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {
        return new ServletContextInitializerBeans(getBeanFactory());
    }
    
    // 自定义集合
    public class ServletContextInitializerBeans extends AbstractCollection<ServletContextInitializer>{
        
        @SafeVarargs
        public ServletContextInitializerBeans(ListableBeanFactory beanFactory,
                                              Class<? extends ServletContextInitializer>... initializerTypes) {
            this.initializers = new LinkedMultiValueMap<>();
            // 获取类型,默认使用 ServletContextInitializer
            this.initializerTypes = (initializerTypes.length != 0) ? Arrays.asList(initializerTypes)
                : Collections.singletonList(ServletContextInitializer.class);
            // 获取所有的 ServletContextInitializer ,并进行分类
            addServletContextInitializerBeans(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);
        }
    
        // 获取所有的 ServletContextInitializer ,并进行分类
        private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
    
            for (Class<? extends ServletContextInitializer> initializerType : this.initializerTypes) {
                for (Entry<String, ? extends ServletContextInitializer> initializerBean : 
                     // 获取所有的 ServletContextInitializer 实现类 bean
                     getOrderedBeansOfType(beanFactory,initializerType)) {
                    addServletContextInitializerBean(initializerBean.getKey(), initializerBean.getValue(), beanFactory);
                }
            }
        }
    
        // 根据不同的类型进去区分 ServletFilterEventListenerServletContextInitializer,并添加进 initializers 中
        private void addServletContextInitializerBean(String beanName, ServletContextInitializer initializer,
                                                      ListableBeanFactory beanFactory) {
            // servlet 
            if (initializer instanceof ServletRegistrationBean) {
                Servlet source = ((ServletRegistrationBean<?>) initializer).getServlet();
                addServletContextInitializerBean(Servlet.class, beanName, initializer, beanFactory, source);
            }
            // filter
            else if (initializer instanceof FilterRegistrationBean) {
                Filter source = ((FilterRegistrationBean<?>) initializer).getFilter();
                addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
            }
            // Filter
            else if (initializer instanceof DelegatingFilterProxyRegistrationBean) {
                String source = ((DelegatingFilterProxyRegistrationBean) initializer).getTargetBeanName();
                addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
            }
            // EventListener
            else if (initializer instanceof ServletListenerRegistrationBean) {
                EventListener source = ((ServletListenerRegistrationBean<?>) initializer).getListener();
                addServletContextInitializerBean(EventListener.class, beanName, initializer, beanFactory, source);
            }
            // ServletContextInitializer
            else {
                addServletContextInitializerBean(ServletContextInitializer.class, beanName, initializer, beanFactory,
                                                 initializer);
            }
        }
    
        /**
         *
         */
        private void addServletContextInitializerBean(Class<?> type, String beanName, 
                                                      ServletContextInitializer initializer,
                                                      ListableBeanFactory beanFactory, Object source) {
            this.initializers.add(type, initializer);
            if (source != null) {
                // Mark the underlying source as seen in case it wraps an existing bean
                this.seen.add(source);
            }
        }
    }
    

    创建 WebServer的代码( TomcatServletWebServerFactory ),并且调用 ServletContextInitializer#onStrat()

    @Override
    public WebServer getWebServer(ServletContextInitializer... initializers) {
       if (this.disableMBeanRegistry) {
          Registry.disableRegistry();
       }
       // 创建tomcat服务
       Tomcat tomcat = new Tomcat();
       // 。。。。略
        
       // 准备上下文
       prepareContext(tomcat.getHost(), initializers);
       // 创建并启动,在启动时将调用 ServletContextInitializer#onStrat() 方法
       return getTomcatWebServer(tomcat);
    }
    
    // 准备上下文
    protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
       //  创建 TomcatContext,虽然不是 ServletContext 类,但是可以转换成ServletContext
       TomcatEmbeddedContext context = new TomcatEmbeddedContext();
       if (documentRoot != null) {
          context.setResources(new LoaderHidingResourceRoot(context));
       }
       // 。。。。略
       // 合并
       ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
       // 关联上下文
       host.addChild(context);
       // 配置上下文
       configureContext(context, initializersToUse);
    }
    
    protected void configureContext(Context context, ServletContextInitializer[] initializers) {
        // 创建tomcat启动器
        TomcatStarter starter = new TomcatStarter(initializers);
        if (context instanceof TomcatEmbeddedContext) {
            TomcatEmbeddedContext embeddedContext = (TomcatEmbeddedContext) context;
            // 设置启动回调
            embeddedContext.setStarter(starter);
            embeddedContext.setFailCtxIfServletStartFails(true);
        }
        // 将 TomcatStart 与上下文关联,添加 ContainerInitializer
        // 然后由他来执行 ServletContextInitializer#onStartup
        context.addServletContainerInitializer(starter, NO_CLASSES);
    }
    
    // 创建 TomcatWebServer
    protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
        return new TomcatWebServer(tomcat, getPort() >= 0, getShutdown());
    }
    
    public class TomcatWebServer implements WebServer{
        // 构造器
        public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
            Assert.notNull(tomcat, "Tomcat Server must not be null");
            this.tomcat = tomcat;
            this.autoStart = autoStart;
            this.gracefulShutdown = (shutdown == Shutdown.GRACEFUL) ? new GracefulShutdown(tomcat) : null;
            initialize();
        }
    
        // 初始化:启动 tomcat
        private void initialize() throws WebServerException {
            // 。。。。略
            // Start the server to trigger initialization listeners
            this.tomcat.start();
        }
    }
    
  • 相关阅读:
    有关macOS隐藏文件的问题
    AcWing 2548. 大胖子走迷宫(BFS)
    AcWing 1224. 交换瓶子(交换最少次数使得数列有序)
    AcWing 1220. 生命之树(树形DP)
    AcWing 1215. 小朋友排队(树状数组)
    AcWing 1214. 波动数列(推柿子+DP)
    Python文件操作
    远程升级程序过程
    找某个Linux内核可能调用的文件
    linux platform简易的理解
  • 原文地址:https://www.cnblogs.com/diandiandidi/p/14459953.html
Copyright © 2020-2023  润新知