javaweb|Java Web基础知识之Servlet容器初始化(无web.xml)

在之前典型的Java Web程序中,部署描述符web.xml是必不可少的,在这里我们需要配置各种组件,包括ServletFilterListener等,如果使用过SpringMVC的话,应该会对在web.xml中配置org.springframework.web.servlet.DispatcherServlet十分熟悉。但是对于所有的配置文件都有的一个通病就是只有在程序部署的时候,一些配置项问题才能被发现,而不能在程序编译开发阶段就发现。所以如果通过编程的方法来设置配置项则是一个最好的选择,我们完全可以抛弃web.xml这个部署描述符,而是换用从Servlet 3.0中提出的一个接口javax.servlet.ServletContainerInitializer来完成Servlet容器的初始化,该接口的作用是当Web应用启动时,通知一些实现类来执行一些要求的ServletFilterListener等的编程注册。
一、接口说明 ServletContainerInitializer接口细节:

  • 其中只有一个方法onStartup(...) ,在执行任何ServletContext监听器之前,由Servlet容器调用这个方法,该方法的主要作用是注册Web对象;
  • 实现ServletContainerInitializer的类必须使用@HandleTypes注解进行标注,以便声明onStartup(...)可以处理这个类的实例,所有该类、包括它的子类都会被传递给其中的Set> c字段,如果没有这个注解,或者在该注解中使用的类不存在或没有相应的子类,则会传递给该参数一个null值;
  • 这个接口被设计在jar文件中使用,而无法直接在war包中直接使用,而是通过在jar中完成定义,然后将jar包作为Java Web的依赖包,该接口的实现类会通过Java的SPI的注册查询机制被发现;
  • 如果要使用这个类,需要一个元数据文件来说明如何定位该接口的实现类,该文本文件在META-INF/services文件夹下,这个文本文件的名称为javax.servlet.ServletContainerInitializer ,其中的内容是该接口的实现类的全限定名;
    ?
二、编程实现 1、构建jar依赖包
首先搭建依赖包工程,这里使用Maven管理工程,依赖项只需要一个,如下:
javax.servlet javax.servlet-api 3.1.0 provided

  • 1
Maven项目目录如下:
javaweb|Java Web基础知识之Servlet容器初始化(无web.xml)
文章图片

  • 其中ServletContainerInitializer的实现类为com.demo.CustomServletContainerInitializer,为了在jar中加入META-INF/services文件夹,只需要将该文件夹直接放到maven的资源文件夹resources下即可,在打包的时候就会在jar中实现该文件夹,并包括之前的文件;
  • 可以看出META-INF/services文件夹中的文本文件名为javax.servlet.ServletContainerInitializer ,其中的内容为com.demo.CustomServletContainerInitializer ,为该接口的实现类;
  • CustomServletContainerInitializer 中的实现如下:
    @HandlesTypes({HttpServlet.class}) public class CustomServletContainerInitializer implements ServletContainerInitializer {public void onStartup(Set> c, ServletContext ctx) throws ServletException { for(Class clazz: c){ System.out.println(clazz.getName()); } } }

    • 1
    该实现类在Java Web应用启动时,会调用该方法,传递HttpServlet类以及其子类。
2、构建Java Web程序
Java Web程序的工程目录如下:
javaweb|Java Web基础知识之Servlet容器初始化(无web.xml)
文章图片

  • 在工程中必须有webapp这个目录,如果没有则会导致异常java.lang.IllegalArgumentException: Document base ... src\main\webapp does not exist or is not a readable directory
  • 这里我们定义一个ServletTestServlet ,通过使用注解@javax.servlet.annotation.WebServlet 来标识这个Servlet ,代码如下:
    @WebServlet(urlPatterns = "/testServlet", name = "testServlet") public class TestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Writer writer = resp.getWriter(); writer.write("do get"); }@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Writer writer = resp.getWriter(); writer.write("do post"); } }

    • 1
    这个注解是在应用启动的时候被容器处理,并且都对应的servlet也可以通过相应的URL来访问;
在程序启动的过程中,会发现传递进来很多的servlet子类和Filter的实现类,如下:
javaweb|Java Web基础知识之Servlet容器初始化(无web.xml)
文章图片

【javaweb|Java Web基础知识之Servlet容器初始化(无web.xml)】其中也包括我们自定义的一个TestServlet

    推荐阅读