点点滴滴啊

导航

 

前言

​ 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);
            }
        }
    }

    // 根据不同的类型进去区分 Servlet\Filter\EventListener\ServletContextInitializer,并添加进 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();
    }
}
posted on 2021-02-28 18:20  丶点滴  阅读(478)  评论(0编辑  收藏  举报