Servlet是基于Java技术的web组件,容器托管的,用于生成动态内容。Servlet容器是web server或application server 的一部分,提供基于请求/响应发送模型的网络服务,解码基于 MIME 的请求,并且格式化基于 MIME 的响应。 Servlet 容器也包含了管理 Servlet 生命周期。
Servlet有三大组件,Filter过滤器、Listener监听器、Servlet,以及ServletContext上下文。
Servlet3.1需支持Http/1.0、Http/1.1、及RFC2612缓存机制,所谓缓存即可能在将客户端请求交给 Servlet 处理之前修改它们,也可能在将 Servlet 生成的响应发送给客户端之前修改它们,或者可能根据 RFC2616 规范直接对请求作出响应而不交给 Servlet 进行处理。
Servlet容器即可以运行在Web服务器的同一个进程中,也可以运行在不同进程中,甚至可以运行在不同主机的进程中。
Servlet3.0支持以下几个主要特性:
Servlet接口是 Java Servlet API 的核心抽象。所有Servlet 类必须直接或间接的实现该接口,或者更通常做法是通过继承一个实现了该接口的类从而复用许多共性功能。
HttpServlet抽象子类在 Servlet 接口基础之上添加了些协议相关的方法。其service方法支持“有条件的GET请求”,即如果没有修订,则直接返回304,不调用GET方法,使用客户端缓存。
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
}
注意:在非分布式环境中,Servlet实例在容器中一般是单例的,即Servlet默认是线程不安全的,需要开发人员处理多线程问题。但如果实现了SingleThreadModel接口(作用是保证一个特定 servlet实例的service方法在一个时刻仅能被一个线程执行),则允许在存在多个实例,一般而言看容器如何实现,比如可以使用syncronize进行同步,或采用servlet实例池,该接口在servlet2.4中被废弃,不建议使用。
Servlet容器负责加载和实例化Servlet。加载和实例化可以发生容器启动时,或者延迟初始化直到容器决定有请求需要处理时。使用的是普通Java类加载机制,可以从本地文件系统,也可以从网络获取。
Servlet在请求处理时实例化或在部署时立即实例化。在后一种情况,以它们的load-on-startup元素表示的顺序实例化。
初始化一般用户获取一些代价高昂的资源,比如JDBC,或者执行一些一次性动作。初始化方法为init(ServletConfig config),其中config是每一个servlet实例都会有一个独立的对象,用于获取当前部署描述文件web.xml中配置的信息,如servlet名字、初始化参数、ServletContext对象,如下所示:
<servlet>
<servlet-name>xxxservlet-name>
<servlet-class>xxxservlet-class>
<init-param>
<param-name>xxxparam-name>
<param-value>xxxparam-value>
init-param>
//用于支持文件上传
<multipart-config>multipart-config>
servlet>
初始化过程中可能抛出UnavailableException异常,而这个异常是说servlet目前暂时无法初始化,需要等待其他资源就绪,请等一段时间再初始化。
//seconds表示等待时间,<=0表示无法预知时间
UnavailableException(String msg, int seconds)
会接收ServletRequest,响应ServletResponse,在Http协议中默认是HttpServletRequest和HttpServletResponse。
注意:
如果抛出UnavailableException表示的是一个永久性不可用,则servlet容器,需要将该servlet从容器中移除,并调用destroy方法。之后会返回一个 SC_NOT_FOUND (404) 响应。
如果 UnavailableException 表示的是一个临时性的不可用,容器可以选择在临时不可用的这段时间内路由任何请求到Servlet。所以在这段时间内被容器拒绝的请求,都会返回一个 SC_SERVICE_UNAVAILABLE (503)响应状态码,且同时会返回一个 Retry-After 头指示此 Servlet 什么时候可用。
容器可以选择忽略永久性和临时性不可用的区别,并把UnavailableExceptions 视为永久性的,从而 Servlet 抛出UnavailableException 后需要把它从服务中移除。
使用HttpServletRequest.upgrade和HttpUpgradeHandler实现HTTP/1.1协议升级,如升级到Websocket等等.
Client可以在header中发送Upgrade字段,并指定其需要的其他协议,比如HTTP/2.0,此时服务器如果支持需返回101编码,并包含Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11响应。
在Servlet3.0中,可以调用HttpServletRequest.upgrade(HttpUpgradeHandler)方法,进行升级响应过程,即返回101.
一次简单的WebSocket握手的过程:
当Web应用程序调用new WebSocket(url)接口时,Browser就开始了与地址为url的WebServer建立握手连接的过程。
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key:dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat,superchat
Sec-WebSocket-Version: 13
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept:s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
参考:
http://www.cnblogs.com/wooer/p/5588993.html websocket简介
从Servlet3.0开始,具备异步请求响应编程模型。即servlet实例所在线程可以不用等待response写返回,而直接释放serlvet线程,因为有些response有比较大的开销,可能会消耗过大的时间,造成线程阻塞,比如等待JDBC连接,等待网络请求等。
注意:默认情况下不支持JSP的servlet,如果需要使用,请在servlet异步执行线程中,调用ctx.dispatch(“xxxx.jsp”)。
子线程处理完成后,可以调用complete方法直接返回,或者调用dispatch方法(DispatcherType.ASYNC,不同于 RequestDispatcher.forward(ServletRequest, ServletResponse) 分派,响应的缓冲区和头信息将不会重置),转发到其他的servlet中继续处理,如下所示:
// REQUEST dispatch to /url/A
AsyncContext ac = request.startAsync();
...
ac.dispatch(); // ASYNC dispatch to /url/A
// REQUEST to /url/A
// FORWARD dispatch to /url/B
request.getRequestDispatcher("/url/B").forward(request,response);
// Start async operation from within the target of the FORWARD
// dispatch
ac = request.startAsync();
...
ac.dispatch(); // ASYNC dispatch to /url/A
// REQUEST to /url/A
// FORWARD dispatch to /url/B
request.getRequestDispatcher("/url/B").forward(request,response);
// Start async operation from within the target of the FORWARD
// dispatch
ac = request.startAsync(request,response);
...
ac.dispatch(); // ASYNC dispatch to /url/B
如何启用子线程?
有两种方法:
private ExecutorService executorService = Executors.newFixedThreadPool(10);
AsyncContext ctx=request.startAsync();
ctx.setTimeout(30*1000);
executorService.submit(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
try {
//do something
ctx.complete();//提交写响应
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
final AsyncContext ctx=request.startAsync();
ctx.setTimeout(30*1000);
ctx.start(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
try {
//do something
ctx.complete();//提交写响应
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
在Servlet3.0中需要对servlet和filter分别都使用@WebServlet和@WebFilter注解,并标识asyncSupported=true,默认是false。从一个同步 Servlet 分派到另一个异步 Servlet 是非法的,一个servlet要么同步要么异步,不能两者兼有。
只有servlet成功初始化实例后,才会调用该方法。
如下示例所示,常见的default servlet配置方式,一般用于配置静态资源(static resource)或文件目录列表服务(listings),与dispatch servlet进行区分,如下配置需要注意两点:
<servlet>
<servlet-name>dispatcherservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>/WEB-INF/dispatcher-servlet.xmlparam-value>
init-param>
<load-on-startup>2load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>dispatcherservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>/assets/*url-pattern>
<url-pattern>/tables/*url-pattern>
servlet-mapping>
官方文献说明:
The default servlet is the servlet which serves static resources as well as serves the directory listings (if directory listings are enabled).
默认情况下default servlet配置在$CATALINA_BASE/conf/web.xml文件中,且默认情况下是随webapp一起启动,并默认开启listings服务,debug模式处于关闭状态。通常建议把listings服务关闭,因为会消耗比较大资源。如果需要替换默认配置,你可以自己覆写一个default servlet,或者使用 localXsltFile or globalXsltFile 。
<servlet>
<servlet-name>defaultservlet-name>
<servlet-class>
org.apache.catalina.servlets.DefaultServlet
servlet-class>
<init-param>
<param-name>debugparam-name>
<param-value>0param-value>
init-param>
<init-param>
<param-name>listingsparam-name>
<param-value>trueparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
...
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<servlet>
<servlet-name>defaultservlet-name>
<servlet-class>
org.eclipse.jetty.servlet.DefaultServlet
servlet-class>
<init-param>
<param-name>acceptRangesparam-name>
<param-value>trueparam-value>
init-param>
<init-param>
<param-name>dirAllowedparam-name>
<param-value>trueparam-value>
init-param>
<init-param>
<param-name>gzipparam-name>
<param-value>trueparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
如果不想使用servlet的default servlet技术,那在spring 3.0.4及以后版本中提供了mvc:resources标签,可以达到一样的效果。
参考:
http://tomcat.apache.org/tomcat-6.0-doc/default-servlet.html Apache Tomcat 6.0 Default Servlet Reference
http://blog.csdn.net/zdhcumt/article/details/6867264 DefaultServlet
http://blog.csdn.net/u012814506/article/details/45095419 servlet必知细节(三)– DefaultServlet
http://blog.csdn.net/wxwzy738/article/details/19072909 web.xml中出现default是什么意思?
/org/eclipse/jetty/servlet/DefaultServlet.java”>http://www.boyunjian.com/javasrc/net.sf.ehcache/ehcache/2.8.1//org/eclipse/jetty/servlet/DefaultServlet.java DefaultServlet源码
在Servlet3.0之前,web.xml定义的监听器顺序是以随机顺序执行的,现在是以配置顺序调用初始化,并以相反顺序进行销毁。
在 servlet2.5 中 metadata-complete 仅影响部署时的注解扫描。然而,在 servlet 3.0 和后来版本中,在运行时,metadata-complete 将影响扫描指定部署信息的所有注解和 web-fragments。web-fragments是在servlet3.0才有xml。
如果ServletContext传到了ServletContainerInitializer的onStartup方法,则给定名字的类可以实现ServletContextListener,否则只能实现其他。
监听器分类:
参考:
http://blog.csdn.net/luccs624061082/article/details/41644899 Servlet 3.0之装配来自web.xml,web-fragment.xml和注解的描述符
路径请求参数优先于POST中的Body请求参数,例如:如果请求由查询字符串 a =hello 和 POST 数据 a=goodbye&a=world 组成,得到的参数集合顺序将是=(hello,goodbye,world)。
POST请求参数,其类型必须是application/x-www-form-urlencoded。
Servlet3.0配置文件上传,需满足以下条件:
Part 类代表从 multipart/form-data 格式的 POST 请求中接收到的一个部分或表单项。 每个 part 都可通过 Part.getInputStream 方法访问头部,相关的内容类型和内容。
只有一个属性值可与一个属性名称相关联。以前缀 java.和 javax.开头的属性名称是本规范的保留定义。同样地, 以前缀 sun.和 com.sun.,oracle 和 com.oracle 开头的属性名是 Oracle Corporation 的保留定义。建议属性集中所有属性的命名与 Java 编程语言的规范 1 为包命名建议的反向域名约定一致。
requestURI = contextPath + servletPath + pathInfo
示例:
配置如下
Context Path | /catalog |
---|---|
Servlet Mapping | Pattern: /lawn/* Servlet: LawnServlet |
Servlet Mapping | Pattern: /garden/* Servlet: GardenServlet |
Servlet Mapping | Pattern: *.jsp Servlet: JSPServlet |
解析如下
请求路径 | 路径元素 |
---|---|
/catalog/lawn/index.html | ContextPath: /catalog ServletPath: /lawn PathInfo: /index.html |
/catalog/garden/implements/ | ContextPath: /catalog ServletPath: /garden PathInfo: /implements/ |
/catalog/help/feedback.jsp | ContextPath: /catalog ServletPath: /help/feedback.jsp PathInfo: null |
仅仅针对于异步Servlet和Upgrade升级处理有效,如果在非前所述两者中调用ServletInputStream.setReadListener或ServletOutputStream.setWriteListener方法时将抛出 IllegalStateException。
HttpOnly cookie 暗示客户端它们不会暴露给客户端脚本代码(它没有被过滤掉,除非客户端知道如何查找此属性)。HttpOnly属性对大小写不敏感.
Set-Cookie: USER=123; expires=Wednesday, 09-Nov-99 23:12:40 GMT; HttpOnly
参考:
http://desert3.iteye.com/blog/869080 HttpOnly介绍以及防止XSS攻击时的作用
如果客户端没有指定编码字符集,则servlet必须默认使用“ISO-8859-1”,而且调用getCharacterEncoding将会返回null。
开发人员可以通过调用setCharacterEncoding(String enc)方法来覆盖由容器提供的字符编码。必须在解析任何 post 数据或从请求读取任何输入之前调用此方法。此方法一旦调用,将不会影响已经读取的数据的编码。
容器一般会重用request对象,以节省创建开销。
它只能把信息写到response对象的ServletOutputStream或Writer中,或提交在最后写保留在response缓冲区中的内容,或通过显式地调用ServletResponse接口的flushBuffer方法。它不能设置响应头部信息或调用任何影响响应头部信息的方法,HttpServletRequest.getSession()和HttpServletRequest.getSession(boolean)方法除外。include后,request的以下参数可以通过request.getAttribute访问。
javax.servlet.include.request_uri
javax.servlet.include.context_path
javax.servlet.include.servlet_path
javax.servlet.include.path_info
javax.servlet.include.query_string
// AsyncContext 的 dispatch
javax.servlet.async.request_uri
javax.servlet.async.context_path
javax.servlet.async.servlet_path
javax.servlet.async.path_info
javax.servlet.async.query_string
forward转发后,request的以下参数可以通过request.getAttribute访问。
javax.servlet.forward.request_uri
javax.servlet.forward.context_path
javax.servlet.forward.servlet_path
javax.servlet.forward.path_info
javax.servlet.forward.query_string
定义了servlet在web应用中的视图。可以用来记录事件,获取资源和配置属性等。对应于ContextPath,即应用的根路径,也称为上下文路径。每个web应用都有一个与之对应的ServletContext。
可以使用getInitParameter和getInitParameterNames获取应用部署描述符文件中的配置初始化信息。
从Servlet3.0开始,可以使用注解和web分片技术,实现web服务可插性支持(使用JAR Services API ServiceLoader.load(Class)),解决webapp划分模块问题,即各独立web模块可以不用再在一个总的web.xml中注册相关信息,只需要在各自独立的模块中配置即可。
注意:该对象支持在运行时动态部署 Servlet、过滤器、监听器,以及为 Servlet 和过滤器增加 URL 映射等。但只能在webapp启动在初始化时进行完成注册,且不能动态销毁,在运行时为了安全原因,无法完成注册。这些方法只能从 ServletContextListener实现的contexInitialized方法或者ServletContainerInitializer实现的onStartup方法进行的应用初始化过程中调用。
Initializer使用方式需满足几点:
是web应用的一个逻辑分区,代表web.xml的部分或全部,即可以将web.xml应用部署描述文件进行拆分放置到不同的jar包中,然后在web.xml中指定加载顺序,碎片文件的名字必须是web-fragment.xml,并放置在jar包的META-INF目录中,比如spring-web项目
META-INF/web-fragment.xml
<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 http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd"
version="3.0" metadata-complete="true">
<name>spring_webname>
<distributable/>
web-fragment>
web.xml
<absolute-ordering>
<name>some_web_fragmentname>
<name>spring_webname>
<others/>//规定在顺序中没有命名的其他资源加载,最多一个
absolute-ordering>
注意:
指定当前的部署描述文件是否是完全的,true-表示完全,false-表示不完全,需要从其他地方获取,默认是false不完全。
<web-app 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
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0" metadata-complete="true">
web-app>
参考:
https://www.ibm.com/developerworks/cn/java/j-lo-servlet30/ Servlet 3.0 新特性详解
此处的可插拔指的是war应用可以在不停止服务器(例如tomcat)的情况下部署。
为一个 Web 应用增加一个 Servlet 配置有如下三种方式 ( 过滤器、监听器与 Servlet 三者的配置都是等价的,故在此以 Servlet 配置为例进行讲述,过滤器和监听器具有与之非常类似的特性 ):
<web-fragment
xmlns=http://java.sun.com/xml/ns/javaee
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd"
metadata-complete="true">
<servlet>
<servlet-name>fragmentservlet-name>
<servlet-class>footmark.servlet.FragmentServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>fragmentservlet-name>
<url-pattern>/fragmenturl-pattern>
servlet-mapping>
web-fragment>
web-fragment.xml 包含了两个可选的顶层标签,\
<web-fragment...>
<name>FragmentAname>
<ordering>
<after>
<name>FragmentBname>
<name>FragmentCname>
after>
<before>
<others/>
before>
ordering>
...
web-fragment>
参考:
http://www.xdemo.org/web-fragment-module-springmvc/ Web-fragment高度模块化Java项目(集成SpringMVC)
https://blogs.oracle.com/swchan/entry/servlet_3_0_web_fragment Servlet 3.0 web-fragment.xml
Servlet可以共享ServletContext上下文属性,即通过setAttribute、getAttribute、getAttributeNames、removeAttribute获取设置属性。
在 JVM 中创建的上下文属性是本地的,这可以防止从一个分布式容器的共享内存存储中获取 ServletContext属性。当需要在运行在分布式环境的 Servlet 之间共享信息时,该信息应该被放到:
需要以“/“作为输入参数的开头,意思是相对于上下文的根路径,调用时,首先会查找根路径,其次会查看WEB-INF/lib中的jar包中的META-INFO/resource目录,jar包的扫描顺序是不定的。可以用于扫描文件系统、jar/war等归档文件、远程服务器资源等。
该方法将返回Web应用中的完整资源列表。在Web应用程序层次结构
中的/index.html文件,或在WEB-INF/lib目录下的JAR文件中的META-INF/resources目录下包括的index.html文件,可以满足从/catalog/index.html送达的请求,优先使用根目录中的文件。
注意:除静态资源、Jsp文件外,WEB-INF的内容不允许直接供给客户端访问,只能通过使用servlet代码调用ServletContext的getResource和getResourceAsStream方法来访问,并可使用RequestDispatcher调用公开这些内容。
安全模型不适用与使用RequestDispatch调用静态资源或forward、include资源到servlet的情况。有两种安全使用方式:
javax.security.Principal用于表示一个实体,例如个人、企业或登录ID。
如果没有用户通过身份认证,getRemoteUser方法返回null,isUserInRole方法总返回false,getUserPrincipal方法总返回null。
@ServletSecurity 注解不应用到 ServletRegistration 使用 ServletContext 接口的 addServlet(String, Servlet)方法创建的 url-pattern,除非该 Servlet 是由 ServletContext 接口的 createServlet 方法构建的。
Servlet3.0允许使用@SecurityServlet配置或web.xml中指定servlet的安全模型,包括角色,访问控制和认证要求。
@WebServlet("/account")
@ServletSecurity(
//指定所有其他方法可以被属于角色R1的用户调用。
value=@HttpConstraint(rolesAllowed = {"R1"}),
httpMethodConstraints={
@HttpMethodConstraint(value="GET", rolesAllowed="R2"),
@HttpMethodConstraint(value="POST", rolesAllowed={"R3", "R4"})
}
)
public class AccountServlet extends javax.servlet.http.HttpServlet {
//. . .
}
<security-constraint>
<web-resource-collection>
<url-pattern>/account/*url-pattern>
<http-method>GEThttp-method>
web-resource-collection>
<auth-constraint>
<role-name>managerrole-name>
auth-constraint>
<user-data-constraint>
<transport-guarantee>INTEGRITYtransport-guarantee>
user-data-constraint>
//用于拒绝对未覆盖的HTTP方法请求拒绝, 请求返回一个403(SC_FORBIDDEN)状态码
<deny-uncovered-http-methods/>
security-constraint>
方法级别安全性
@RolesAllowed("R2")
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
//. . .
}
@RolesAllowed,@DenyAll或@PermitAll中只能有一个在目标指定。而@TransportProtected注释可能出现的组合@RolesAllowed 或@PermitAll注解。
参考:
https://my.oschina.net/u/2315511/blog/381810 Servlet的Web Fragments和安全性
规范并没有规定必须使用缓存输出流,但一般情况下是会实现的,而且ServletResponse有方法设置缓存大小。
仅仅针对于异步Servlet和Upgrade升级处理有效,如果在非前所述两者中调用ServletInputStream.setReadListener或ServletOutputStream.setWriteListener方法时将抛出 IllegalStateException。
当且仅当ServletOutputStream的isReady方法返回false,容器随后将调用onWritePossible方法,之后再调用isReady返回true。
ServletOutputstream写会成功,则isReady返回true,否则返回false(意思是已经准备好写东西了,请触发写事件给监听器)。
一般不用来产生响应或类似于Servlet一样的响应,常用于包装请求或相应,用于修订或调整到资源的请求,修订或调整从资源的响应,覆盖行为执行过滤任务。匹配请求的过滤器链的顺序是它们在web.xml中声明的顺序。
容器必须确保它为过滤器列表中的每一个都实例化了一个适当类的过滤器,并调用其init(FilterConfig config)方法。FilterConfig包含有init参数,也有servletContext引用。
注意:
<filter-mapping>
<filter-name>Logging Filterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<filter-mapping>
<filter-name>Image Filterfilter-name>
<servlet-name>ImageServletservlet-name>
filter-mapping>
注意:
<filter-mapping>
<filter-name>Image Filterfilter-name>
<servlet-name>ImageServletservlet-name>
<dispatcher>FORWARDdispatcher>
<dispatcher>REQUESTdispatcher>//直接请求
<dispatcher>ASYNCdispatcher>//异步请求
filter-mapping>
与每个会话相关联是一个包含唯一标识符的字符串,也被称为会话 ID。会话 ID 的值能通过调用javax.servlet.http.HttpSession.getId() 获 取 , 且能在创建后通过调用javax.servlet.http.HttpServletRequest.changeSessionId()改变。
HttpSession对象,绝不能在容器上下文之间中共享,只能限定应用上下文,即单个容器上下文之内有效。并为了安全,容器需要给定默认的超时时间,或用户使用setMaxInactiveInterval设置超时时间。这些方法的超时时间以秒为单位。根据定义,如果超时时间设置为 0 或更小的值,会话将永不过期
<session-config>
<cookie-config>
<comment>sessioncomment>
<domain>xxxxdomain>
<http-only>truehttp-only>
//seconds 默认 -1
<max-age>100max-age>
//JSESSIONID default
<name>JSESSIONIDname>
<path>/path>
<secure>truesecure>
cookie-config>
//分钟,0或-1表示不过期
<session-timeout>1session-timeout>
<tracking-mode>COOKIEtracking-mode>
<tracking-mode>URLtracking-mode>
<tracking-mode>SSLtracking-mode>
session-config>
所有会话跟踪Cookie的名字都是JSESSIONID。容器也允许自定义名字。所有servlet容器必须提供能够配置容器是否标记会话跟踪 cookie为HttpOnly
待续
URL 重写是会话跟踪的最低标准,即在Cookie在客户端不支持时,需要采用将会话ID写入URL的方式,例如:
http://www.myserver.com/catalog/index.html;jsessionid=1234
URL 重写在日志、书签、 referer header、缓存的 HTML、 URL 工具条中暴露会话标识。在支持 cookie 或 SSL会话的情况下,不应该使用 URL 重写作为会话跟踪机制。
可以在HttpSession对象上绑定servlet之间共享的属性对象。属性的添加和删除,可以通过实现HttpSessionBindingListener获得通知,其有两个方法:valueBound和valueUnbound。
activated活化(从硬盘到内存)和passivated钝化(从内存到硬盘)。容器需要支持会话迁移存储对象机制,且附加会话属性时,属性对象应实现Serializable接口。容器必须在迁移会话时通知实现了 HttpSessionActivationListener的所有会话属性。它们必须在序列化会话之前通知钝化监听器,在反序列化之后通知激活监听器。可用于持久化或者从一个VM迁移到另一个VM。
例如:在用户访问的时候,假如服务器突然关闭了,这个时候,用户的session就不存在了,假如是购物网站,也就相当于,用户好不容易选好的物品,刚刚添加到购物车,结果,因为服务器的突然关闭一下,什么都没了,这样很不好,于是我们就需要实现会话的持久化。可以让我们在重新启动服务器之后用户的session还在服务器中存在!
public class Person implements Serializable, HttpSessionActivationListener {
private String name;
public Person(String name) {
super();
this.name = name;
}
@Override
public void sessionWillPassivate(HttpSessionEvent se) {
System.out.println(this + "保存到硬盘了...");
}
@Override
public void sessionDidActivate(HttpSessionEvent se) {
System.out.println(this + "从硬盘读取并活化了...");
}
@Override
public String toString() {
return "Perosn [name=" + name + "]---"+super.toString();
}
}
写分布式应用的开发人员应该意识到容器可能运行在多个 Java 虚拟机中,开发人员不能依赖静态变量存储应用状态。他们应该用企业Bean或数据库存储这种状态。
参考:
http://blog.csdn.net/qq_26525215/article/details/52262566 JavaWeb-会话的持久化:HttpSessionActivationListener
http://memorynotfound.com/httpsessionactivationlistener-example-use-case/ Httpsessionactivationlistener Example Use Case
注解必须在WEB-INF/classes或者WEB-INF/lib下的jar包中,才能被处理。如果要启用注解,请在web.xml中确保metadata-complete为false,常用注解如下图所示:
xml配置优先级高于注解。
用于定义servlet组件,其中必须指定的是urlPatterns或value,两者不能同时使用,可以指定多个url,例如urlPatterns={“/foo”, “/bar”}。没有指定name时,默认采用全限定类名(例如com.acme.Foo)。如果同一个 Servlet 类以不同的名字声明在部署描述符中,必须实例化一个新的Servlet实例。注意使用该注解的前提是必须继承HttpServlet。
可以使用@WebInitParam配置ServletConfig参数。
\false\如果指定了该参数,则不允许使用rul,即该servlet无效。
用于定义filter过滤器组件,如果没有指定name,则默认采用全限定类名(例如com.acme.Foo)。注解的urlPatterns属性,servletNames属性或value属性必须被指定,同时使用value和urlPatterns是非法的。注意使用该注解的前提是必须实现javax.servlet.Filter接口。
可以使用@WebInitParam配置FilterConfig参数。
用于定义listener监听器组件,获取web应用上下文中的操作事件。注意该注解的前提是必须实现以下的监听器接口。
该注解主要是为了辅助 Servlet 3.0 中 HttpServletRequest 提供的对上传文件的支持。该注解标注在 Servlet 上面,以表示该 Servlet 希望处理的请求的 MIME 类型是 multipart/form-data。另外,它还提供了若干属性用于简化对上传文件的处理
属性名 | 类型 | 是否可选 | 描述 |
---|---|---|---|
fileSizeThreshold | int | 是 | 当数据量大于该值时,内容将被写入文件。 |
location | String | 是 | 存放生成的文件地址。 和\的\元素被解析为一个绝对路径且默认为 javax.servlet.context.tempdir。 如果指定了相对地址,它将是相对于tempdir位置。 绝对路径与相对地址的测试必须使用java.io.File.isAbsolute。 |
maxFileSize | long | 是 | 允许上传的文件最大值。默认值为 -1,表示没有限制。 |
maxRequestSize | long | 是 | 针对该 multipart/form-data 请求的最大数量,默认值为 -1, |
待定
\用于指定GUI图标,支持GIF, JPEG, PNG例如:
<icon>
<small-icon>employee-service-icon16x16.jpgsmall-icon>
<large-icon>employee-service-icon32x32.jpglarge-icon>
icon>
用于指定jsp资源控制信息,包括是否开启el表达式、jsp文件编码等。
<jsp-config>
<jsp-property-group>
<url-pattern>url-pattern>
<el-ignored>trueel-ignored>
jsp-property-group>
jsp-config>
资源注入配置,用于引用外部资源(an external resource),可以包括一个可选描述、资源控制器、验证类型、是否可共享(Shareable or Unshareable)、注入对象等。主要的作用是将容器中需要用到的资源或组件与应用服务器定义的资源或组件关联。作用等同于在类上使用资源引用注解@Resource,@Resources,@EJB,@EJBs,@WebServiceRef,@WebServiceRefs,@PersistenceContext,@PersistenceContexts,@PersistenceUnit,@PersistenceUnits
<resource-ref>
//is the name of a component dependency and is relative to java:comp/env/jdbc/EmployeeAppDB
<res-ref-name>jdbc/EmployeeAppDBres-ref-name>
<res-type>javax.sql.DataSourceres-type>
<res-auth>Containerres-auth>
<res-sharing-scope>Shareableres-sharing-scope>
<injection-target>//可以多个
<injection-target-class>com.acme.ServletAinjection-target-class>
<injection-target-name>dsinjection-target-name>
injection-target>
resource-ref>
等同于
public class ServletA{
@Resource(name="jdbc/EmployeeAppDB")
private DataSource ds;
}
等同于
public class ServletA{
{
InitialContext ic=new InitialContext();
DataSource ds=(DataSource)ic.lookup("java:comp/env/jdbc/EmployeeAppDB");
}
}
优先级为annotation < standard.xml < sun-*.xml。
其实只要在serlvet中可以使用Spring容器,就没必要用这种方式。
参考:
http://www.bubuko.com/infodetail-452903.html EJB和Web容器中的资源或组件是如何查找的?
欢迎文件的局部URI有序列表,默认的根路径对于的欢迎页面,如果第一个没有找到,则找第二个,依次类推。当一个对应到WAR文件中一个目录条目的请求URI没有映射到一个Web组件时,允许部署者为容器用于添加URI指定局部URI有序列表。这种请求被认为是有效的局部请求。
<welcome-file-list>
<welcome-file>index.jspwelcome-file>
<welcome-file>second.jspwelcome-file>
welcome-file-list>
如果请求host:port/webapp/directory/,该条目无法映射到servlet或jsp,则会默认添加host:port/webapp/directory/index.jsp返回给客户端。
错误页面机制,可以通过reponse code,也可以使用exception,这种语法允许当servlet或过滤器调用response的sendError方法,发送4xx和5xx状态的响应(2xx与3xx无效),这样错误机制才可能会被调用,或如果servlet产生一个异常或错误传播给容器时,由容器返回资源配置。
容器抛出的异常包括三种:
例如:
<error-page>
<error-code>500error-code>
<location>/error.jsplocation>
error-page>
<error-page>
<exception-type>java.lang.NullExceptionexception-type>
<location>/error.jsplocation>
error-page>
注意:error-code与exception-type必须唯一。如果抛出的异常并没有定义exception-type,则会被包装成ServletException再次寻找。如果还是没有处理,则会抛出500.
参考:
http://blog.csdn.net/dclove/article/details/11727073 在web.xml中配置error-page
指定该站台是否可分布式处理,如果web.xml中出现这个元素,则代表站台在开发时已经被设计为能在多个JSP Container 之间分散执行.
\
ServletContainerInitializer和编程式注册特性可以在Servlet和JSP容器之间提供一个清晰的职责分离,通过由Servlet 容器只负责解析web.xml和web-fragment.xml资源,而解析标签库描述符( TLD)资源委托给JSP容器。
JSP也是一种Servlet,JSP容器是Servlet子容器,是内嵌到一个 Servlet3.0 兼容的 Servlet 容器中,可以提供它自己的ServletContainerInitializer 实现,搜索传递到它的 onStartup 方法的 ServletContext 参数寻找任何 TLD 资源,扫描这些资源寻找 Listener 声明,并向 ServletContext 注册相关的 Listener。
ServletContext.getJspConfigDescriptor 方法得到应用的 web.xml和web-fragment.xml 部署描述符中的任何 jsp-config 相关的配置
URL会剔除掉上下文路径和参数,匹配时会区分大小写,并且一旦匹配到一个不会再进行更多尝试。匹配步骤如下: