轻量级Java EE企业应用开发实战
上QQ阅读APP看书,第一时间看更新

3.5 Servlet上下文

Servlet上下文定义了Servlet运行在Web应用的视图,定义在ServletContext接口中。容器供应商负责提供Servlet容器的ServletContext接口的实现。Servlet可以使用ServletContext对象记录事件,获取URL引用的资源,存取当前上下文的其他Servlet可以访问的属性。

ServletContext是Web服务器中已知路径的根。例如,Servlet上下文可以从https://waylau.com/catalog找出,“/catalog”请求路径称为上下文路径,所有以它开头的请求都会被路由到与ServletContext相关联的Web应用。

3.5.1 ServletContext接口作用域

每一个部署到容器的Web应用都有一个ServletContext接口的实例与之关联。在容器分布在多台虚拟机的情况下,每个JVM的每个Web应用将有一个ServletContext实例。

如果容器内的Servlet没有部署到Web应用中,就隐含地作为“默认”Web应用的一部分,并有一个默认的ServletContext。在分布式的容器中,默认的ServletContext是非分布式的且仅存在于一个JVM中。

3.5.2 初始化参数

以下ServletContext接口方法允许Servlet访问由应用开发人员在Web应用的部署描述符中指定的上下文初始化参数:

  • getInitParameter
  • getInitParameterNames

应用开发人员使用初始化参数来表达配置信息。代表性的例子是一个网络管理员的E-Mail地址,或保存关键数据的系统名称。

3.5.3 配置方法

下面的方法从Servlet 3.0开始添加到ServletContext,以便启用编程方式定义Servlet、Filter和它们映射到的URL模式。这些方法只能从ServletContextListener实现的contexInitialized方法或者ServletContainerInitializer实现的onStartup方法进行的应用初始化过程中调用。除了添加Servlet和Filter外,也可以查找关联到Servlet或Filter的一个Registration对象实例,或者到Servlet或Filter的所有Registration对象的Map。

如果ServletContext传到了ServletContextListener的contextInitialized方法,但该ServletContextListener既没有在web.xml或web-fragment.xml中声明,又没有使用@WebListener注解,那么在ServletContext中定义的用于Servlet、Filter和Listener的编程式配置的所有方法必须抛出nsupportedOperationException。

1.编程式添加和配置Servlet

编程式添加Servlet到上下文对框架开发者是很有用的。例如,框架可以使用这个方法声明一个控制器Servlet。这个方法将返回一个ServletRegistration或ServletRegistration.Dynamic对象,允许我们进一步配置如init-params、url-mapping等Servlet的其他参数。

下面描述常用的添加和配置Servlet的方法。

  • addServlet(String servletName, String className):该方法允许应用以编程方式声明一个Servlet。它添加给定的Servlet名称和类名称到Servlet上下文。
  • addServlet(String servletName, Servlet servlet):该方法允许应用以编程方式声明一个Servlet。它添加给定的名称和Servlet实例的Servlet到Servlet上下文。
  • addServlet(String servletName, Class <? extends Servlet> servletClass):该方法允许应用以编程方式声明一个Servlet。它添加给定的名称和Servlet类的一个实例的Servlet到Servlet上下文。
  • T createServlet(Class clazz):该方法实例化一个给定的Servlet类,该方法必须支持适用于Servlet的除了@WebServlet的所有注解。返回的Servlet实例通过调用上面定义的addServlet(String, Servlet)注册到ServletContext之前,可以进行进一步的定制。
  • ServletRegistration getServletRegistration(String servletName):该方法返回与指定名字的Servlet相关的ServletRegistration,或者如果没有该名字的ServletRegistration,就返回null。如果ServletContext传到了ServletContextListener的contextInitialized方法,但该ServletContextListener既没有在web.xml或web-fragment.xml中声明,又没有使用javax.servlet. annotation.WebListener注解,就必须抛出UnsupportedOperationException。
  • Map getServletRegistrations():该方法返回ServletRegistration对象的Map,由名称作为键并对应着注册到ServletContext的所有Servlet。如果没有Servlet注册到ServletContext,就返回一个空的Map。返回的Map包括所有声明和注解的Servlet对应的ServletRegistration对象,也包括那些使用addServlet方法添加的所有Servlet对应的ServletRegistration对象。返回的Map的任何改变都不影响ServletContext。如果ServletContext传到了ServletContextListener的contextInitialized方法,但该ServletContextListener既没有在web.xml或web-fragment.xml中声明,又没有使用javax.servlet.annotation.WebListener注解,就必须抛出UnsupportedOperationException。

2.编程式添加和配置Filter

  • addFilter(String filterName, String className):该方法允许应用以编程方式声明一个Filter。它添加以给定的Filter名称和类名称的Filter到Web应用。
  • addFilter(String filterName, Filter filter):该方法允许应用以编程方式声明一个Filter。它添加以给定的Filter名称和Filter实例到Web应用。
  • addFilter(String filterName, Class <? extends Filter> filterClass):该方法允许应用以编程方式声明一个Filter。它添加以给定的Filter名称和Filter类到Web应用。
  • T createFilter(Class clazz):该方法实例化一个给定的Filter。
  • FilterRegistration getFilterRegistration(String filterName):该方法返回与指定名字的Filter相关的FilterRegistration,或者如果没有该名字的FilterRegistration,就返回null。如果ServletContext传到了ServletContextListener的contextInitialized方法,但该ServletContextListener既没有在web.xml或web-fragment.xml中声明,又没有使用javax.servlet.annotation.WebListener注解,就必须抛出UnsupportedOperationException。
  • Map getFilterRegistrations():该方法返回FilterRegistration对象的Map,由名称作为键并对应着注册到ServletContext的所有Filter。如果没有Filter注册到ServletContext,就返回一个空的Map。返回的Map包括所有声明和注解的Filter对应的FilterRegistration对象,也包括那些使用addFilter方法添加的所有Servlet对应的ServletRegistration对象。返回的Map的任何改变都不影响ServletContext。如果ServletContext传到了ServletContextListener的contextInitialized方法,但该ServletContextListener既没有在web.xml或web-fragment.xml中声明,又没有使用javax.servlet.annotation.WebListener注解,就必须抛出UnsupportedOperationException。

3.编程式添加和配置Listener

  • void addListener(String className):往ServletContext添加指定类名的监听器。ServletContext将使用由与应用关联的classloader加载该监听器的类。监听器必须实现一个或多个如下接口:

 javax.servlet.ServletContextAttributeListener

 javax.servlet.ServletRequestListener

 javax.servlet.ServletRequestAttributeListener

 javax.servlet.http.HttpSessionListener

 javax.servlet.http.HttpSessionAttributeListener

 javax.servlet.http.HttpSessionIdListener

  • void addListener(T t):往ServletContext添加一个给定的监听器。给定的监听器实例必须实现一个或多个如下接口:

 javax.servlet.ServletContextAttributeListener

 javax.servlet.ServletRequestListener

 javax.servlet.ServletRequestAttributeListener

 javax.servlet.http.HttpSessionListener

 javax.servlet.http.HttpSessionAttributeListener

 javax.servlet.http.HttpSessionIdListener

  • void addListener(Class <? extends EventListener> listenerClass):往ServletContext添加指定类名的监听器。给定的监听器类必须实现一个或多个如下接口:

 javax.servlet.ServletContextAttributeListener

 javax.servlet.ServletRequestListener

 javax.servlet.ServletRequestAttributeListener

 javax.servlet.http.HttpSessionListener

 javax.servlet.http.HttpSessionAttributeListener

 javax.servlet.http.HttpSessionIdListener

  • void createListener(Class clazz):该方法实例化给定的EventListener类。指定的EventListener类必须实现至少一个如下接口:

 javax.servlet.ServletContextAttributeListener

 javax.servlet.ServletRequestListener

 javax.servlet.ServletRequestAttributeListener

 javax.servlet.http.HttpSessionListener

 javax.servlet.http.HttpSessionAttributeListener

 javax.servlet.http.HttpSessionIdListener

3.5.4 上下文属性

Servlet可以通过名字将对象属性绑定到上下文。同一个Web应用内的其他任何Servlet都可以使用绑定到上下文的任意属性。以下ServletContext接口中的方法允许访问此功能:

  • setAttribute
  • getAttribute
  • getAttributeNames
  • removeAttribute

在JVM中创建的上下文属性是本地的,这可以防止从一个分布式容器的共享内存存储中获取ServletContext属性。当需要在运行在分布式环境的Servlet之间共享信息时,该信息应该被放到会话中,或存储到数据库,或设置到Enterprise JavaBeans(企业级JavaBean)组件。

3.5.5 资源

ServletContext接口提供了直接访问Web应用中仅是静态内容层次结构的文件的方法,包括HTML、GIF和JPEG文件等:

  • getResource
  • getResourceAsStream

getResource和getResourceAsStream方法需要一个以“/”开头的String作为参数,给定的资源路径是相对于上下文的根,或者相对于Web应用的WEB-INF/lib目录下的JAR文件中的META-INF/resources目录。这两个方法首先根据请求的资源查找Web应用上下文的根,然后查找所有WEB-INF/lib目录下的JAR文件。查找WEB-INF/lib目录下JAR文件的顺序是不确定的。这种层次结构的文件可以存在于服务器的文件系统、Web应用的归档文件、远程服务器或其他位置。

需要注意的是,这两个方法不能用于获取动态内容。例如,在支持JSP的容器中,如getResource("/index.jsp")形式的方法调用将返回JSP源码而不是处理后的输出。