框架(如Spring)如何在没有web.xml的情况下配置Servlet容器?
How do frameworks (like Spring) configure the Servlet container without web.xml?
(我已经知道答案了,但是因为我经常发现自己要重新寻找答案,所以我post在这里作为我自己和其他人的文档。这是encouraged 在 Whosebug 上。)
背景介绍
许多 Servlet 开发人员阅读了这本书 "Head First Serlet & JSP" 以获得他们的 "Certified Web Component Developer Exam" 或者只是为了学习 Servlet。但是这本书自 2009 年以来就没有更新过,而且只涵盖了 Servlet 2.4。从那以后很多事情改变了。目前最新版本是4.0。
发生变化的事情之一是 servlet 网络应用程序的启动过程,这可能会让人不清楚启动过程中发生了什么以及网络应用程序是如何初始化的。
问题
在 Servlet 2.4 及更低版本中,web.xml 用于完全配置 Web 应用程序。但是更高版本似乎有其他方式来配置 Web 应用程序,无需触及 web.xml 且无需注释。例如,作为 .jar 文件提供的 Web 框架能够以某种方式挂接到 Servlet 容器并添加 url 映射。
这个机制是如何运作的?
简介
在 Servlet 2.4(2003 年 11 月)中,servlet 容器(例如 Tomcat 和 Jetty)通过查找文件 WEB-INF/web.xml
(部署描述符)。文件 web.xml 包含对 servlet、过滤器和侦听器的引用,以及它们相关的 url 模式和参数。使用 web.xml servlet 容器确切地知道在哪里可以找到所有东西以及如何配置它们。
自 Servlet 3.0(2009 年 12 月)起,web.xml 是可选的,您也可以改用注释或编程配置。
注释使用起来更简单。它们位于 javax.servlet.annotation package, and allow you to annotate a servlet with @WebServlet, a filter with @WebFilter, and a listener with @WebListener。然后 servler 容器将自动查找并检测这些 classes。然而,注释确实提供了比 web.xml 和程序化配置更少的配置功能。
本文进一步关注如何配置编程配置以及它如何启动 Spring MVC。它比注解稍微复杂一点,但确实能让您和框架设计者更好地控制启动过程。
如果您想使用 Servlet 版本 3.0 之前的 Web 框架,您必须向 web.xml 添加一个 servlet 或过滤器并从那里配置框架。完成此初始化后,您可以开始编写 Web 框架已知的 classes(通常是 non-Servlet classes)来创建 Web 应用程序。
从Servlet 3.0开始,系统是模块化的。这允许框架和库设计者初始化 servlet 容器,而无需通过 web.xml 配置框架。您可以立即开始编写特定于 Web 框架的 classes 来创建 Web 应用程序,而无需接触 Servlet classes。
(也可以在 Servlet 3.0 中创建自己的 web.xml 并仍然让框架进行框架的初始化,而无需在 web.xml 中定义它。)
框架或库如何自动挂接到 Servlet 容器?
启动时,Servlet 容器首先查找位于 WEB-INF/web.xml
的部署描述符。如果此文件的 metadata-complete
属性设置为 false,或者根本未定义,容器还将搜索带注释的 classes,例如 @WebServlet.
除了查找 web.xml 和带注释的 classes 之外,自 Servlet 3.0 起,容器还将查找位于 [=15] 中的 .jar 文件中的 META-INF/web-fragment.xml
文件=] 目录.
文件 web-fragment.xml 是一个 web 片段,它是
(引自 Java Servlet Specification)
a logical partitioning of the web application in such a way that the
frameworks being used within the web application can define all the
artifacts without asking developers to edit or add information in the
web.xml. It can include almost all the same elements that the web.xml
descriptor uses. However the top level element for the descriptor MUST
be web-fragment and the corresponding descriptor file MUST be called
web-fragment.xml. The ordering related elements also differ between
the web-fragment.xml and web.xml
web-fragment.xml 的内容与 web.xml 类似,但具有 web-fragment
根元素而不是 web-app
元素:
<web-fragment xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
https://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd"
version="3.0">
<filter>
<filter-name>FrameworkFilter</filter-name>
<filter-class>framework.FrameworkFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FrameworkFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-fragment>
加载单个 web.xml 和多个 web-fragment.xml 文件的确切顺序可以使用 <absolute-ordering>
和 <ordering>
配置。
除了 Web 片段之外,还有一种划分 Web 应用程序的编程方法:通过编写接口 javax.servlet.ServletContainerInitializer
. ServletContainerInitializer gives access to the ServletContext
的实现,其中包含以编程方式添加 servlet、过滤器和侦听器的方法。
要使用 ServletContainerInitializer
,必须在位于 META-INF/services/javax.servlet.ServletContainerInitializer
的文件中指定它。此文件的内容必须是实现的完全限定路径 class.
这对 Spring MVC 如何工作?
尽管 Spring MVC 确实包含一个 web-fragment.xml
, it doesn't define any servlets, filters or listeners. Spring uses the META-INF/services/javax.servlet.ServletContainerInitializer
file to refer to its own ServletContainerInitializer implementation class, which is the class SpringServletContainerInitializer
。
SpringServletContainerInitializer 是一个 ServletContainerInitializer,所以它在启动时接收一个 ServletContext。 SpringServletContainerInitializer 的目标是将 servletContext 传递给开发人员更友好的 WebApplicationInitializer
, so that you can add servlets, such as Springs DispatcherServlet
, which is a front-controller that directs incoming requests to other controllers. (See spring-framework-reference 关于如何将 DispatcherServlet 配置为 Spring。)
Spring MVC 没有提供 WebApplicationInitializer 的具体实现,只有一些抽象的 classes,所以你可以控制启动过程。在 Spring Boot 的情况下,提供了一个具体的实现:SpringApplicationWebApplicationInitializer
以减少样板代码的数量。
更多信息
关于Servlet容器启动过程具体如何工作的详细描述,可以在官方Java Servlet Specification中找到。有关 Spring MVC 的更多信息可以在 Spring 框架参考 .
中找到
(我已经知道答案了,但是因为我经常发现自己要重新寻找答案,所以我post在这里作为我自己和其他人的文档。这是encouraged 在 Whosebug 上。)
背景介绍
许多 Servlet 开发人员阅读了这本书 "Head First Serlet & JSP" 以获得他们的 "Certified Web Component Developer Exam" 或者只是为了学习 Servlet。但是这本书自 2009 年以来就没有更新过,而且只涵盖了 Servlet 2.4。从那以后很多事情改变了。目前最新版本是4.0。 发生变化的事情之一是 servlet 网络应用程序的启动过程,这可能会让人不清楚启动过程中发生了什么以及网络应用程序是如何初始化的。
问题
在 Servlet 2.4 及更低版本中,web.xml 用于完全配置 Web 应用程序。但是更高版本似乎有其他方式来配置 Web 应用程序,无需触及 web.xml 且无需注释。例如,作为 .jar 文件提供的 Web 框架能够以某种方式挂接到 Servlet 容器并添加 url 映射。
这个机制是如何运作的?
简介
在 Servlet 2.4(2003 年 11 月)中,servlet 容器(例如 Tomcat 和 Jetty)通过查找文件 WEB-INF/web.xml
(部署描述符)。文件 web.xml 包含对 servlet、过滤器和侦听器的引用,以及它们相关的 url 模式和参数。使用 web.xml servlet 容器确切地知道在哪里可以找到所有东西以及如何配置它们。
自 Servlet 3.0(2009 年 12 月)起,web.xml 是可选的,您也可以改用注释或编程配置。
注释使用起来更简单。它们位于 javax.servlet.annotation package, and allow you to annotate a servlet with @WebServlet, a filter with @WebFilter, and a listener with @WebListener。然后 servler 容器将自动查找并检测这些 classes。然而,注释确实提供了比 web.xml 和程序化配置更少的配置功能。
本文进一步关注如何配置编程配置以及它如何启动 Spring MVC。它比注解稍微复杂一点,但确实能让您和框架设计者更好地控制启动过程。
如果您想使用 Servlet 版本 3.0 之前的 Web 框架,您必须向 web.xml 添加一个 servlet 或过滤器并从那里配置框架。完成此初始化后,您可以开始编写 Web 框架已知的 classes(通常是 non-Servlet classes)来创建 Web 应用程序。
从Servlet 3.0开始,系统是模块化的。这允许框架和库设计者初始化 servlet 容器,而无需通过 web.xml 配置框架。您可以立即开始编写特定于 Web 框架的 classes 来创建 Web 应用程序,而无需接触 Servlet classes。 (也可以在 Servlet 3.0 中创建自己的 web.xml 并仍然让框架进行框架的初始化,而无需在 web.xml 中定义它。)
框架或库如何自动挂接到 Servlet 容器?
启动时,Servlet 容器首先查找位于 WEB-INF/web.xml
的部署描述符。如果此文件的 metadata-complete
属性设置为 false,或者根本未定义,容器还将搜索带注释的 classes,例如 @WebServlet.
除了查找 web.xml 和带注释的 classes 之外,自 Servlet 3.0 起,容器还将查找位于 [=15] 中的 .jar 文件中的 META-INF/web-fragment.xml
文件=] 目录.
文件 web-fragment.xml 是一个 web 片段,它是 (引自 Java Servlet Specification)
a logical partitioning of the web application in such a way that the frameworks being used within the web application can define all the artifacts without asking developers to edit or add information in the web.xml. It can include almost all the same elements that the web.xml descriptor uses. However the top level element for the descriptor MUST be web-fragment and the corresponding descriptor file MUST be called web-fragment.xml. The ordering related elements also differ between the web-fragment.xml and web.xml
web-fragment.xml 的内容与 web.xml 类似,但具有 web-fragment
根元素而不是 web-app
元素:
<web-fragment xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
https://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd"
version="3.0">
<filter>
<filter-name>FrameworkFilter</filter-name>
<filter-class>framework.FrameworkFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FrameworkFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-fragment>
加载单个 web.xml 和多个 web-fragment.xml 文件的确切顺序可以使用 <absolute-ordering>
和 <ordering>
配置。
除了 Web 片段之外,还有一种划分 Web 应用程序的编程方法:通过编写接口 javax.servlet.ServletContainerInitializer
. ServletContainerInitializer gives access to the ServletContext
的实现,其中包含以编程方式添加 servlet、过滤器和侦听器的方法。
要使用 ServletContainerInitializer
,必须在位于 META-INF/services/javax.servlet.ServletContainerInitializer
的文件中指定它。此文件的内容必须是实现的完全限定路径 class.
这对 Spring MVC 如何工作?
尽管 Spring MVC 确实包含一个 web-fragment.xml
, it doesn't define any servlets, filters or listeners. Spring uses the META-INF/services/javax.servlet.ServletContainerInitializer
file to refer to its own ServletContainerInitializer implementation class, which is the class SpringServletContainerInitializer
。
SpringServletContainerInitializer 是一个 ServletContainerInitializer,所以它在启动时接收一个 ServletContext。 SpringServletContainerInitializer 的目标是将 servletContext 传递给开发人员更友好的 WebApplicationInitializer
, so that you can add servlets, such as Springs DispatcherServlet
, which is a front-controller that directs incoming requests to other controllers. (See spring-framework-reference 关于如何将 DispatcherServlet 配置为 Spring。)
Spring MVC 没有提供 WebApplicationInitializer 的具体实现,只有一些抽象的 classes,所以你可以控制启动过程。在 Spring Boot 的情况下,提供了一个具体的实现:SpringApplicationWebApplicationInitializer
以减少样板代码的数量。
更多信息
关于Servlet容器启动过程具体如何工作的详细描述,可以在官方Java Servlet Specification中找到。有关 Spring MVC 的更多信息可以在 Spring 框架参考 .
中找到