1.Servlet默认是线程不安全的,需要开发人员处理多线程问题。
通常Web容器对于并发请求将使用同一个servlet处理,并且在不同的线程中并发执行service方法。
2.doPut和doDelete方法允许Servlet开发人员让支持HTTP/1.1的客户端使用这些功能。HttpServlet中的doHead 方法可以认为是doGet方法的一个特殊形式,它仅返回由doGet 方法产生的header 信息。doOptions方法返回当前servlet支持的HTTP方法(译者注:通过Allow响应头返回支持的HTTP 操作,如GET、POST)。 doTrace方法返回的响应包含TRACE 请求的所有头信息。
3.HttpServlet 定义了用于支持有条件GET 操作的getLastModified 方法。所谓的有条件GET 操作是指客户端 通过GET请求获取资源时,当资源自第一次获取那个时间点发生更改后才再次发生数据,否则将使用客户端缓存的数据。在一些适当的场合,实现此方法可以更有效的利用网络资源,减少不必要的数据发送。
4.对于未托管在分布式环境中(默认)的servlet而言,servlet容器对于每一个Servlet声明必须且只能产生一个实例。不过,如果Servlet实现了SingleThreadModel接口,servlet容器可以选择实例化多个实例以便处理高负荷请求或者串行化请求到一个特定的实例。
如果Servlet以分布式方式进行部署,容器可以为每个虚拟机(JVM)的每个Servlet声明产生一个实例。但是,如果在分布式环境中servlet实现了SingleThreadModel接口,此时容器可以为每个容器的JVM实例化多个Servlet实例。
5.SingleThreadModel接口的作用是保证一个特定的servlet实例的service方法在一个时刻仅能被一个线程执行,一定要注意,此包装仅适用于每一个servlet实例,因此容器可以选择池化这些对象。有些对象可以在同一时刻被多个servlet实例访问,如HttpSession实例,可以在一个特定的时间对多个Servlet可用,包括哪些实现了SingleThreadModel接口的Servlet。
6.Servlet容器通过调用Servlet实例的init方法完成初始化,init方法定义在Servlet接口中,并且提供一个唯一的ServletConfig接口实现的对象作为参数,该对象每个Servlet实例一个。配置对象允许Servlet访问由Web应用配置信息提供的键值对的初始化参数。该配置对象也提供给Servlet去访问一个ServletContext对象,ServletContext描述了Servlet的运行时环境。
7.客户端请求由ServletRequest类型的request对象表示。Servlet封装响应并返回给请求的客户端,该响应由ServletResponse类型的response表示。这两个对象(request和response)是由容器通过参数传递到Servlet接口的service方法的。
在HTTP请求的场景下,容器提供的请求和响应对象具体类型分别是HttpServeltRequest和HttpServletResponse。需要注意的是,由Servlet容器初始化的某个Servlet实例在服务期间,可以在生命周期中不处理任何请求。
8.ServletException表示在处理请求过程中发生了错误,容器应该采取适当措施清理请求。
UnavailableException表示servlet不能处理请求,可能是临时的也可能是永久的。如果UnavailableException表示的是一个永久性的不可用,Servlet容器必须从服务中移除这个Servlet,调用它的destory方法,并释放Servlet实例。所有被容器拒绝的请求,都会返回一个SC_NOT_FOUND(404)响应。
如果UnavailableException表示的是一个临时性的不可用,容器可以选择在临时不可用的这段时间内路由任何请求到Servlet。所以在这段时间内被容器拒绝的请求,都会返回一个SC_SERVICE_UNAVAILABLE(503)响应状态码,且同时会返回一个Retry-After头指示此Servlet什么时候可用。容器可选择忽略永久性和临时性不可用的区别,并把UnavailableExceptions视为永久性的,从而Servlet抛出UnavailableException后需要把它从服务中移除。
9.Servelet3.0引入了异步处理请求的能力,是线程可以返回到容器,从而执行更多的任务。当开始移除处理请求时,另一个线程或回调可以或者产生响应,或者调用完成(complete)或者请求分派(dispatch),这样,它可以在容器上下文使用AsyncContext.dispatch方法运行。
从一个Servlet分派时,把asyncSupported=true设置为false是允许的。这种情况下,当servlet的service方法不支持异步退出时,响应将被提交,且容器负责调用AsyncContext的complete,以便所有感兴趣的AsyncListener得到触发通知。过滤器作为清理要完成的异步任务持有的资源的一种机制,也应该使用AsyncListener.onComplete触发的结果。
从一个同步Servlet分派到另一个异步Servlet是非法的。不过与改点不同的是当应用调用startAsync时将抛出IllegalStateException。这将允许servlet只能作为同步的或异步的Servlet。
10.AsyncContext该类表示在ServletRequest启动的异步操作执行上下文,AsyncContext由之前描述的ServletRequest.startAsync创建并初始化。
任何执行dispath方法期间可能抛出的错误或异常必须由容器捕获及处理:
(1)调用所有由AsyncContext创建的并注册到ServletRequest的AsyncListener实例的AsyncListener.onError(AsyncEvent)方法,可以通过AsyncEvent.getThrowable()获取到捕获的Throwable。
(2)如果没有监听器调用AsyncContext.complete或任何AsyncContext.dispatch方法,然后执行一个状态码为HttpServletResponse.SC_INTERNAL_SERVER_ERROR的出错分派,并且可以通过RequDispatcher.ERROR_EXCEPTION请求属性获取Throwable值。
(3)如果没有找到匹配的错误页面,或错误页面没有调用AsyncContext.complete()或任何AsyncContext.dispatch方法,则容器必须调用AsyncContext.complete。
在异步操作超时的情况下,容器必须按照如下步骤运行:
(1)当异步操作启动后调用注册到ServletRequest的所有AscyncListener实例的AsyncListener.onTimeout方法
(2)如果没有监听器调用AsyncContext.complete()或任何AsyncContext.dispatch方法,执行一个状态码为HttpServletResponse.SC_INTERNAL_SERVER_ERROR出错分派。
(3)如果没有找到匹配的错误页面,或者错误页面没有调用AsyncContext.complete()或者任何Asyn.dispath方法,则容器必须调用AsyncContext.complete()。
如果在AsyncListener中调用的方法抛出异常,将记录下来且将不影响任何其他AsyncListener的调用。
默认情况下是不支持JSP的异步处理,因为它是用于内容审查且异步处理可能在内容生成之前已经完成。这取决于如何处理这种情况。一旦完成了所有的异步活动,使用AsyncContext.dispatch分派到的JSP页面可以用来生成内容。
11.在HTTP/1.1,Upgrade通用头(general-header)允许客户端指定其支持和希望使用的其他通信协议。如果服务器找到合适的切换协议,那么新的协议将在之后的通信中使用。Servlet容器提供了HTTP升级机制。不过,Servlet容器本身不知道任何升级协议。协议处理封装在HttpUpgradeHandler协议处理器。在容器和HttpUpgradeHandler协议处理器之间通过字节流进行数据读取或写入。
当收到一个升级(upgrade)请求,servlet可以调用HttpServletRequest.upgrade方法启动升级处理。该方法实例化给定的HttpUpgradeHandler类,返回的HttpUpgradeHandler实例可以被进一步定制。应用准备和发送一个合适的响应到客户端。退出servlet service方法之后,servlet容器完成所有过滤器的处理并标记连接已交给HttpUpgradeHandler协议处理器处理。然后调用HttpUpgradeHandler协议处理器init方法,传入一个WebConnection以允许HttpUpgradeHandler协议处理器访问数据流。
Servlet过滤器仅处理初始的HTTP请求和响应,然后他们将不会再参与到后续的通信中。换句话说,一旦请求被升级,它们将不会被调用。
协议处理器(ProtocolHandler)可以使用非阻塞IO接收和发送消息。
当处理HTTP升级时,开发人员负责线程安全的访问ServletInputStream和ServletOutputStream。
当升级处理已经完成,将调用HttpUpgradeHandler.destory方法。
12.servlet的请求参数以字符串的形式作为请求的一部分从客户端发送servlet容器。当请求时一个HttpServletRequest对象,且符合下面“参数可用时”描述的条件时,容器从URI查询字符串和POST数据中填充参数。参数以一系列的名值对的形式保存。任何给定的参数和名称可存在多个参数值。
以下是在POST表单数据填充到参数集前必须满足的条件:
(1)该请求是一个HTTP或者HTTPS请求。
(2)HTTP请求的方法是POST
(3)内容类型是application/x-www-form-urlencoded.
(4)该servlet已经对request对象的任意getPararmeter方法进行了初始调用。
13.当数据以multipart/from-data的格式发送时,servlet容器支持文件上传
(1)servlet处理注解“@MultipartConfig”标注的请求。
(2)为了servlet处理请求,部署描述符包含了一个multipart-config元素。
如果servlet容器提供multipart/form-data格式数据的处理,可以同HttpServletRequset中的以下方法得到:
(1)public Collection<Part> getParts()
(2)public Part getPart(String name)
注:Part类代表从multipart/from-data格式的POST请求中接收到的一个部分或表单项。每个part都可通过Part.getInputStream方法访问头部,相关的内容类型和内容。
对于表单数据的Content-Disposition,即使没有文件名,也可使用part的名称通过HttpServletRequest的getParameter和getParameterValues方法得到part的字符串值。
如果servlet的容器不提供multi-part/form-data格式数据的处理,这些数据将可通过HttpServletRequest.getInputStream得到。
14.属性是与请求相关联的对象。属性可以由容器设置来表达信息,否则无法通过API标示,或者由servlet设置将信息传达给另一个servlet(通过RequestDispatcher)。属性通过ServletRequest接口中下面的方法来访问:
(1)getAttribute
(2)getAttributeNames
(3)setAttribute
只有一个属性值可与一个属性名称相关联。以前缀java.和javax.开头的属性名称是本规范的保留定义。同样地,以前缀sun.和com.sun.,oracle和com.oracle开头的属性名是Oracle Corporation的保留定义。
15.引导servlet服务请求的请求路径由许多重要部分组成。以下元素从请求URI路径得到,并通过request对象公开:
(1)Context Path:与ServletContext相关联的路径前缀是这个servlet的一部分。如果这个上下文是基于Web服务器的URL命名空间基础上的“默认”上下文,那么这个路径将是一个空字符串。否则,如果上下文不是基于服务器的命名空间,那么这个路径以"/" 字符开始,但不以"/" 字符结束。
(2)Servlet Path:路径部分直接与激活请求的映射对应。这个路径以"/"字符开头,如果请求与"/*"或“”模式匹配,在这种情况下,它是一个空字符串。
(3)PathInfo:请求路径的一部分,不属于Context Path或Servlet Path。如果没有额外的路径,它要么是null,要么是以"/"开头的字符串。
重要的是要注意,除了请求URI和路径部分的URL编码差异外,下面的等式永远为真:
reuqestURI=contextPath+servletPath+pathInfo。
16.在API中有两个方便的方法,允许开发者获得与某个特定的路径等级的文件系统路径。这些方法是:
(1)ServletContext.getRealPath
(2)HttpServletRequest.getPathTranslated
getRealPath方法需要一个字符串参数,并返回一个字符串形式的路径,这个路径对应一个在本地文件系统上的文件。getPathTranslated方法推断出请求的pathInfo的实际路径。
这些方法在servlet容器无法确定一个有效的文件路径的情况下,如Web应用程序从归档中,在不能访问本地的远程文件系统上,活在一个数据库中执行时,这些方法必须返回null。JAR文件中META-INF/resources目录下的资源,只有当调用getRealPath()方法时才认为容器已经从包含它的JAR文件中解压,在这种情况下,必须返回解压缩后的位置。
17.servlet容器的非阻塞IO允许开发人员在数据可用时读取数据或在数据可写时写数据。非阻塞IO仅对在Servlet和Filter中的异步请求处理和升级处理有效。否则,当调用ServletInputStream.setReadListener或ServletInputStream.setWriteListener方法时将抛出IllegalStateException。
一旦把监听器与给定的ServletInputStream关联起来,当数据可以读取,所有的数据都读取完或如果处理请求时发生错误,容器调用ReadListener的方法。注册一个ReadListener将启动非阻塞IO。在那时切换到传统的阻塞IO是非法的,且必须抛出IllegalStateException。在当前请求范围内,随后调用setReadListener是非法的且必须抛出IllegalStateException。