转载: Servlet规范
Servlet上下文
4.1 ServletContext接口介绍
ServletContext(Servlet上下文)接口定义了servlet运行在的Web应用的视图。容器供应商负责提供Servlet容器的ServletContext接口的实现。Servlet可以使用ServletContext对象记录事件,获取URL引用的资源,存取当前上下文的其他Servlet可以访问的属性。
ServletContext是Web服务器中已知路径的根。例如,Servlet上下文可以从http://www.mycorp.com/catalog找出,/catalog请求路径称为上下文路径,所有以它开头的请求都会被路由到与ServletContext 相关联的Web应用。
4.2 ServletContext接口作用范围
每一个部署到容器的Web应用都有一个Servlet接口的实例与之关联。在容器分布在多台虚拟机的情况下,每个JVM的每个Web应用将有一个ServletContext实例。
如果容器内的Servlet没有部署到Web应用中,则隐含的作为”默认”Web应用的一部分,并有一个默认的ServletContext。在分布式的容器中,默认的ServletContext是非分布式的且仅存在于一个JVM中。
4.3 初始化参数
如下ServletContext接口方法允许Servlet访问由应用开发人员在Web应用中的部署描述符中指定的上下文初始化参数:
■getInitParameter
■getInitParameterNames
应用开发人员使用初始化参数来表达配置信息。代表性的例子是一个Webmaster的e-mail地址,或保存关键数据的系统名称。
4.4 配置方法
下面的方法从Servlet3.0开始添加到ServletContext,以便启用编程方式定义Servlet、Filter和它们映射到的url模式(url pattern)。这些方法只能从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的编程式配置的所有方法必须抛出UnsupportedOperationException。
4.4.1 编程式添加和配置Servlet
编程式添加Servlet到上下文对框架开发者是很有用的。例如,框架可以使用这个方法声明一个控制器Servlet。这个方法将返回一个ServletRegistration或ServletRegistration.Dynamic对象,允许我们进一步配置如init-params,url-mapping等Servlet的其他参数。下面描述了该方法的三个重载版本。
4.4.1.1addServlet(String servletName, String className)
该方法允许应用以编程方式声明一个Servlet。它添加以给定的名称和class名称的Servlet到servlet上下文。
4.4.1.2addServlet(String servletName, Servlet servlet)
该方法允许应用以编程方式声明一个Servlet。它添加以给定的名称和Servlet实例的Servlet到servlet上下文。
4.4.1.3addServlet(String servletName, Class <? extends Servlet> servletClass)
该方法允许应用以编程方式声明一个Servlet。它添加以给定的名称和Servlet类的一个实例的Servlet到servlet上下文。
4.4.1.4<T extends Servlet> T createServlet(Class<T> clazz)
该方法实例化一个给定的Servletclass,该方法必须支持适用于Servlet的除了@WebServlet的所有注解。
返回的Servlet实例通过调用上边定义的addServlet(String,Servlet)注册到ServletContext之前,可以进行进一步的定制。
4.4.1.5ServletRegistration getServletRegistration(String servletName)
该方法返回与指定名字的Servlet相关的ServletRegistration,或者如果没有该名字的ServletRegistration则返回null。如果ServletContext传到了ServletContextListener的contextInitialized方法,但该ServletContextListener即没有在web.xml或web-fragment.xml中声明也没有使用javax.servlet.annotation.WebListener注解,则必须抛出UnsupportedOperationException。
4.4.1.6Map<String, ? extends ServletRegistration> 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。
4.4.2 编程式添加和配置Filter
4.4.2.1addFilter(String filterName, String className)
该方法允许应用以编程方式声明一个Filter。它添加以给定的名称和class名称的Filter到web应用。
4.4.2.2addFilter(String filterName, Filter filter)
该方法允许应用以编程方式声明一个Filter。它添加以给定的名称和filter实例的Filter到web应用。
4.4.2.3addFilter(String filterName, Class <? extends Filter> filterClass)
该方法允许应用以编程方式声明一个Filter。它添加以给定的名称和filter类的一个实例的Filter到web应用。
4.4.2.4<T extends Filter> T createFilter(Class<T> clazz)
该方法实例化一个给定的Filterclass,该方法必须支持适用于Filter的所有注解。
返回的Filter实例通过调用上边定义的addServlet(String, Filter)注册到ServletContext之前,可以进行进一步的定制。给定的Filter类必须定义一个用于实例化的空参构造器。
4.4.2.5FilterRegistration getFilterRegistration(String filterName)
该方法返回与指定名字的Filter相关的FilterRegistration,或者如果没有该名字的FilterRegistration则返回null。如果ServletContext传到了ServletContextListener的contextInitialized方法,但该ServletContextListener即没有在web.xml或web-fragment.xml中声明也没有使用javax.servlet.annotation.WebListener注解,则必须抛出UnsupportedOperationException。
4.4.2.6Map<String, ? extends FilterRegistration> 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。
4.4.3编程式添加和配置Listener
4.4.3.1void addListener(String className)
往ServletContext添加指定class名称的监听器。ServletContext将使用由与应用关联的classloader装载加载该给定名称的class,且它们必须实现一个或多个以下接口:
■javax.servlet.ServletContextAttributeListener
■javax.servlet.ServletRequestListener
■javax.servlet.ServletRequestAttributeListener
■javax.servlet.http.HttpSessionListener
■javax.servlet.http.HttpSessionAttributeListener
如果ServletContext传到了ServletContainerInitializer的onStartup方法,则给定名字的类可以实现除上面列出的接口之外的javax.servlet.ServletContextListener。作为该方法调用的一部分,容器必须装载指定类名的class,以确保其实现了所需的接口之一。如果给定名字的类实现了一个监听器接口,则其调用顺序和声明顺序是一样的,换句话说,如果它实现了javax.servlet.ServletRequestListener 或 javax.servlet.http.HttpSessionListener,那么新的监听器将被添加到该接口的有序监听器列表的末尾。
4.4.3.2<T extends EventListener> void addListener(T t)
往ServletContext添加一个给定的监听器。给定的监听器实例必须实现是一个或多个如下接口:
■javax.servlet.ServletContextAttributeListener
■javax.servlet.ServletRequestListener
■javax.servlet.ServletRequestAttributeListener
■javax.servlet.http.HttpSessionListener
■javax.servlet.http.HttpSessionAttributeListener
如果ServletContext传到了ServletContainerInitializer的onStartup方法,则给定的监听器实例可以实现除上面列出的接口之外的javax.servlet.ServletContextListener。如果给定的监听器实例实现了一个监听器接口,则其调用顺序和声明顺序是一样的,换句话说,如果它实现了javax.servlet.ServletRequestListener 或 javax.servlet.http.HttpSessionListener,那么新的监听器将被添加到该接口的有序监听器列表的末尾。
4.4.3.3void addListener(Class <? extends EventListener> listenerClass)
往ServletContext添加指定class类型的监听器。给定的监听器类必须实现是一个或多个如下接口:
■javax.servlet.ServletContextAttributeListener
■javax.servlet.ServletRequestListener
■javax.servlet.ServletRequestAttributeListener
■ javax.servlet.http.HttpSessionListener
■javax.servlet.http.HttpSessionAttributeListener
如果ServletContext传到了ServletContainerInitializer的onStartup方法,则给定的监听器类可以实现除上面列出的接口之外的javax.servlet.ServletContextListener。如果给定的监听器类实现了一个监听器接口,则其调用顺序和声明顺序是一样的,换句话说,如果它实现了javax.servlet.ServletRequestListener 或 javax.servlet.http.HttpSessionListener,那么新的监听器将被添加到该接口的有序监听器列表的末尾。
4.4.3.4<T extends EventListener> void createListener(Class<T> clazz)
该方法实例化给定的EventListener类。指定的EventListener类必须实现至少一个如下接口:
■javax.servlet.ServletContextAttributeListener
■javax.servlet.ServletRequestListener
■javax.servlet.ServletRequestAttributeListener
■javax.servlet.http.HttpSessionListener
■javax.servlet.http.HttpSessionAttributeListener
该方法必须支持该规范定义的适用于如上接口的所有注解。返回的EventListener实例可以在通过调用addListener(T t)注册到ServletContext之前进行进一步的定制。给定的EventListener必须定义一个用于实例化的空参构造器。
4.4.3.5用于编程式添加Servlet、Filter和Listener的注解处理需求
当时有编程式API添加Servlet或创建Servlet时,apart from the addServlet thattakes an instance,下面的注解必须被内省
When using the programmatic API to add aservlet or create a servlet, apart from the addServlet that takes an instance,the following annotations must be introspected in the class in question and themetadata defined in it MUST be used unless it is overridden by calls to the APIin the ServletRegistration.Dynamic /
ServletRegistration.
@ServletSecurity, @RunAs, @DeclareRoles,@MultipartConfig.
Filter和Listener不需要内省注解。
除了那些使用带有一个实例的方法添加的组件,在编程式添加或创建的所有组件(Servlet,Filter和Listener)上的资源注入,只有当组件是一个Managed Bean时才被支持。Managed Bean的更多细节请参考JavaEE6部分和JSR299中定义的Managed Bean规范。
4.5 上下文属性
Servlet可以使用指定的名字将对象属性绑定到上下文。同一个Web应用内的其他任何Servlet都可以使用绑定到上下文的任意属性。以下Servlet接口中的方法允许访问此功能:
■ setAttribute
■ getAttribute
■getAttributeNames
■removeAttribute
4.5.1分布式容器中的上下文属性
在JVM中创建的上下文属性是本地的,这可以防止从一个分布式容器的共享内存存储中获取ServletContext属性。当需要在运行在分布式环境的Servlet之间共享信息时,该信息应该被放到session(请看第7章,”会话”),或存储到数据库,或者设置到企业级JavaBean组件(Enterprise JavaBeans™)。
4.6 资源
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应用的归档文件,远程服务器,或在其他位置。
这两个方法不能用于获取动态内容。例如,在支持JavaServer Pages™规范(JavaServer Pages™ 规范可以在http://java.sun.com/products/jsp找到)的容器中,如getResource(“/index.jsp”)形式的方法调用将返回JSP源码而不是处理后的输出。请看第9章,“分派请求”获取更多关于动态内容的信息。
可以使用getResourcePaths(Stringpath)方法访问Web应用中的资源的完整列表。该方法的语义的全部细节可以从本规范的API文档中找到。
4.7 多主机和Servlet上下文
Web服务器可以支持多个逻辑主机共享一个服务器IP地址。有时,这种能力被称为“虚拟主机”。这种情况下,每一个逻辑主机必须有它自己的上下文或一组上下文。Servlet上下文不会在虚拟主机之间共享。
4.8 Reload注意事项
尽管容器供应商不需要实现类的重新加载(reload)模式以便易于开发,但是任何此类的实现必须确保所有servlet及它们使用的类(Servlet使用的系统类异常可能使用的是一个不同的class loader)在一个单独的class loader范围内被加载。为了保证应用像开发人员预期的那样工作,该要求是必须的。作为一个开发辅助,容器应支持到session绑定到的监听器的完整通知语义以用于当class重新加载时session终结的监控。
之前几代的容器创建新的class loader来加载servlet,且与用于加载在servlet上下文中使用的其他Servlet或类的class loader是完全不同的。这可能导致servlet上下文中的对象引用指向意想不到的类或对象,并引起意想不到的行为。为了防止因创建新的class loader所引起的问题,该要求是必须的。
4.8.1 临时工作目录
每一个servlet上下文都需要一个临时的存储目录。Servlet容器必须为每一个servlet上下文提供一个私有的临时目录,并将通过javax.servlet.context.tempdir上下文属性使其可用,关联该属性的对象必须是java.io.File类型。该要求公认为在多个servlet引擎实现中提供一个通用的便利。当servlet容器重启时,它不需要去保持临时目录中的内容,但必须确保一个servlet上下文的临时目录中的内容对运行在同一个servlet容器的其他Web应用的上下文不可见。