SPRING 四月 30, 2020

Servlet 注册到了哪?

文章字数 4.1k 阅读约需 4 mins. 阅读次数

还在给每个请求加前缀避免模块间接口冲突呢? 中内容,我们可以通过 ServletRegistrationBean 注册多个 DispatcherServlet,那么 Servlet 被注册到哪了呢?

简单的回答:Servlet 容器。

没毛病!但马达马达大内!注册到了 Servlet 容器里的哪?存在什么结构里?

让我们以 Tomcat 容器为例,刨根问底。

addRegistration

ServletRegistrationBean 中,有一个 addRegistration 方法,将具体的 Servlet 添加到了 ServletContext 中。

@Override
protected ServletRegistration.Dynamic addRegistration(String description, ServletContext servletContext) {
  String name = getServletName();
  return servletContext.addServlet(name, this.servlet);
}

addServlet

Servlet 容器负责提供 ServletContext 接口的实现。
在 Tomcat 中,ServletContext 的实现类为 org.apache.catalina.core.ApplicationContext

其私有的 addServlet 方法,将注册的 Servlet 放入了 Wrapper 中

wrapper.setServlet(servlet);

org.apache.catalina.Wrapper 会被作为 child 加入到 StandardContext 中。

addChild

StandardContext 的 addChild 方法,会调用基类 ContainerBase 的同名方法,进而调用 ContainerBase#addChildInternal,完成注册工作。

synchronized(children) {
    if (children.get(child.getName()) != null)
        throw new IllegalArgumentException(
                sm.getString("containerBase.child.notUnique", child.getName()));
    child.setParent(this);  // May throw IAE
    children.put(child.getName(), child);
}

结论

Servlet 实例被包装至 StandardWrapper,注册到了其父容器 StandardContext 从基类 ContainerBase 继承的一个 HashMap 里。

/**
 * The child Containers belonging to this Container, keyed by name.
 */
protected final HashMap<String, Container> children = new HashMap<>();

引申内容

在 Tomcat Catalina 中,Container 负责执行收到的请求,并基于请求返回响应。

Container 又扩展出四个接口

  1. Engine:代表整个 Catalina servlet 引擎,一般是包括一个或多个子容器,即 Host 或 Context 的实现,或其他自定义组。
  2. Host:表示一个有拥有数个 Context 的虚拟主机。
  3. Context:表示一个 ServletContext,包含一个或多个支持 Servlet 的 Wrapper。
  4. Wrapper:表示一个独立的 Servlet。

Container

0%