Servlet
Sun公司制订的一种用来扩展Web服务器功能的组件规范。当浏览器将请求发送给Web服务器(比如:apcahe的web server),Web服务器会向Servlet容器发送请求,Servlet容器负责解析请求数据包。
ServletContext
容器在启动时,会为每一个应用创建唯一的一个符合ServletContext接口要求的对象(Servlet上下文),该对象一直存在,只有非容器关闭时对象被销毁。
// GenericServlet抽象类,实际上调用ServletConfig的getServletContext方法
GenericServlet.getServletContext();
HttpSession.getServletContext();
ServletConfig.getServletContext();
FilterConfig.getServletContext();
作用:
- 绑定数据:
setAttribute 、 removeAttribute 、 getAttribute 、 Request 、 Session 、 ServletContext
都提供绑定数据相关的三个方法。如果都满足使用条件,应该优先使用生命周期短的,生命周期升序排列:Request<Session<ServletContext
。
- Request对象上绑定的数据只有同一个请求所涉及的各个Web组件可以共享,例如:一个Servlet将数据绑定到Request,然后转发到一个jsp。请求先交给过滤器来处理,然后调用Servlet。
- Session对象上绑定的数据是用一个会话所涉及的各个Web组件可以共享。
- ServletContext对象绑定的数据是公开的,谁都可以访问,而且随时可访问
- 访问全局的初始化参数:即使用
<context-param>
配置的初始化参数,调用String getInitParameter(String paramName)
方法,可以被同一个应用中的所有的Servlet、Filter共享。 - 依据逻辑路径path获得实际部署时的物理路径
Application
- 作用:用于保存应用程序中的公有数据,实现多客户之间的数据共享。
- 生命周期:从Web服务器启动,直到Web服务器关闭。
- 作用范围:application对象是一个应用程序级的对象,它作用于当前Web应用程序,也即作用于当前网站,所有访问当前网站的客户都共享一个application对象。
- 基类:javax.servlet.ServletContext类。
Cookie
一种客户端的状态管理技术。当浏览器访问服务器的时候,服务器可以将少量的数据以set-cookie消息头的方式发送给浏览器,浏览器会将这些数据保存下来。当浏览器再次访问服务器时,会将之前保存的这些数据以cookie消息头的方式发送给服务器。有几个cookie,就有几个set-cookie消息头。
- 创建:
// name:cookie的名称。value:cookie的值
Cookie c = new Cookie(String name, String value);
- 添加Cookie:
response.addCookie(c);
- 查询Cookie
Cookie[] request.getCookies();//如果没有任何的cookie,则返回null;
String cookie.getName();
String cookie.getValue();
- 编码:cookie的值或者名称只允许合法的ASCII码字符串,如果是中文,需要将中文转换成ASCII码字符串。
String URLEncoder.encode(String str, String code);
String URLDecoder.decode(String str, String code);
- Cookie生存时间:默认情况下,浏览器会将cookie保存在内存里,只要浏览器不关闭,cookie会一直存在。
启动浏览器后,操作系统会为浏览器开辟一块内存空间:
①浏览器访问服务器。
②服务器生成消息头setCookie发回给浏览器。
③浏览器将服务器生成的消息头保存到内存区域。
④当浏览器关闭,系统回收为浏览器分配的内存,cookie也相应消失。
设置生存时间:使用cookie.setMaxAge(int seconds)
方法。
①单位是秒。
②当seconds>0时,浏览器会将cookie保存在硬盘上,当cookie保存的时间超过seconds,则cookie会被浏览器删除。
③当seconds<0时,缺省值(浏览器会将cookie保存在内存里)。
④当seconds=0时,删除cookie。所以Cookie中无删除方法,设置为0即可。而修改,则为覆盖,用相同的name。 - Cookie路径问题:浏览器在向服务器上的某个地址发请求时,会比较请求地址与cookie的路径是否匹配,只有匹配的cookie才会发送。
①默认路径:值等于创建该cookie的组件的路径,比如:/web06_Cookie/
②匹配规则:只有当访问的地址是cookie的路径或着是其子路径时,浏览器才会将这个cookie进行发送。 - Cookie限制/缺点
- cookie可以被用户禁止。
- 因为cookie保存在浏览器端,所以cookie不安全。对于一些敏感的数据,需要加密处理。
- cookie只能够保存少量的数据(大约是4K左右)。
- cookie的个数也有限制(浏览器只能够保存大约300个左右的cookie,另外对于某个服务器也有cookie个数的限制,大约是20个)。
- cookie只能够保存字符串,对象、集合、数组都不能保存。
session
会话,服务器端的状态管理技术。
当浏览器访问服务器时,服务器会创建一个session对象(该对象有一个唯一的id号,称之为sessionId)。接下来,服务器在默认情况下,会使用set-cookie消息头将这个sessionId发送浏览器,浏览器会将这个sessionId保存下来(内存中,因为指定生存时间)。当浏览器再次访问服务器时,会将sessionId使用cookie消息头发送给服务器,服务器依据这个sessionId就可以找到之前创建的session对象。用户与服务器之间的多次交互叫一次会话。
创建:
-
HttpSession s=request.getSession(boolean flag);//HttpSession是一个接口,返回一个符合要求的对象(工厂)
当flag=true时:服务器会先检查请求当中是否有sessionId,没有则创建。有sessionId,则查找,找到则返回session对象。根据sessionId找不到,则服务器会创建一个新的session对象。flag默认为true。
当flag=false时:服务器会先检查请求当中是否有sessionId,没有则返回null。有sessionId则查找,找到则返回session对象。找不到则返回null。
session超时:
- 服务器会将空闲时间过长的session对象删除。大部分服务器默认的session超时限制是30分钟。
- 修改超时限制:
setMaxInactiveInterval(int seconds);
或在web.xml
中修改
<session-config>
<session-timeout>30</session-timeout>
</session-config>
立即删除session:session.invalidate();
。实际是清空session对象的内容,然后可以给其他人继续使用该session对象
优点
- session比较安全(相对于cookie,将所有状态都写在服务器端)
- session能够保存的数据类型更加丰富(cookie只能保存字符串)
- session能够保存的数据更大(cookie只能保存大约4K左右的数据),session理论上无限制
- session没有被禁止的问题,不需要url重写(cookie会被用户禁止)
缺点
- session会将数据放在服务器端,对服务器的资源的占用比较大,而cookie会将数据保存在浏览器端,对服务器资源的占用没有。
- session默认情况下,会将sessionId以cookie的方式发送给浏览器,浏览器会将session保存到内存中,如果浏览器关闭,浏览器发请求时就没有sessionId,服务器端的session对象就找不到。可用 spring session来管理。
用户禁止cookie后,如何继续使用session?
- 如果用户禁止cookie,服务器仍然会将sessionId以cookie的方式发送给浏览器,但浏览器不再保存这个cookie(sessionId)
- 如果想要继续使用session,需要采取其他方式来实现sessionId的跟踪,如url重写来实现sessionId的跟踪
url重写:浏览器在访问服务器上的某个地址时,不能够直接写这个组件(Servlet/JSP)的地址,而应该使用服务器生成的包含有sessionId的地址。
-
response.encodeURL(String utl);//encodeURL方法用在链接地址、表单提交地址
-
response.encodeRedirectURL(String url);//用于重定向
- 转发不用考虑!是服务器内部,不是浏览器访问服务器
Cookie、Session和Application比较
- 作用范围不同:
session对象是用户级的对象,而application对象是应用程序级的对象。
一个用户一个session对象,每个用户的session对象不同,在用户所访问网站的多个页面之间共享同一个session对象。
一个Web应用程序一个application对象,每个Web应用程序的application对象不同,但一个Web应用程序的多个用户之间共享同一个application对象。
在同一个网站下:
每个用户的session对象不同
所用用户的application对象相同
在不同网站下:
每个用户的session对象不同
每个用户的application对象不同 - 生命周期不同:
session对象:用户首次访问网站创建,用户离开该网站 (不一定要关闭浏览器) 消亡。
application对象:启动Web服务器创建,关闭Web服务器销毁。
Servlet和Filter区别
整个流程:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。
Filter作用:
- Filter可以进行对特定的url请求和相应做预处理和后处理。
- 在HttpServletRequest到达Servlet之前,拦截客户的HttpServletRequest。
- 根据需要检查HttpServletRequest,也可以修改HttpServletRequest头和数据。
- 在HttpServletResponse到达客户端之前,拦截HttpServletResponse。
- 根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据。
实际上Filter和Servlet极其相似,区别只是Filter不能直接对用户生成响应。实际上Filter里doFilter()方法里的代码就是从多个Servlet的service()方法里抽取的通用代码,通过使用Filter可以实现更好的复用。
Filter和Servlet的生命周期
Filter在web服务器启动时初始化
如果某个Servlet配置了 1 ,该Servlet也是在Tomcat(Servlet容器)启动时初始化。
如果Servlet没有配置1 ,该Servlet不会在Tomcat启动时初始化,而是在请求到来时初始化。
每次请求, Request都会被初始化,响应请求后,请求被销毁。
Servlet初始化后,将不会随着请求的结束而注销。
关闭Tomcat时,Servlet、Filter依次被注销。
过滤器、监听器
参考Java web之拦截器Interceptor、过滤器Filter以及监听器Listener
HandlerInterceptor接口。
转发和重定向的区别
重定向:服务器发送一个302状态码及一个Location消息头(值是一个地址,称为重定向地址),通知浏览器立即向重定向地址发请求。response.sendRedirect(String url)
特点:
- 重定向的地址是任意的,前提要存在否则报404
- 重定向之后,浏览器地址栏的地址会变成重定向地址
请求转发:一个Web组件(Servlet/JSP)将未完成的处理通过容器转交给另外一个Web组件继续完成。常见的情况是:一个Servlet将数据处理完毕之后,转交给一个JSP去展现。
步骤:
- 绑定数据到request:request里有个HashMap。
request.setAttribute(String name,Object obj);
- 获得一个转发器:url:要转发给哪一个Web组件。
RequestDispatcher rd=request.getRequsetDispatcher(String url);
- 转发:
rd.forward(request,response);//JSP和Servlet会共享相同的请求和响应对象
- 在转发的目的地,可以使用request.getAttribute方法获得绑定的数据,然后进行处理。【注意:转发之前,先清空response对象中缓存的数据;不能调用out.close()或着out.flush只能同时处理一个响应】
特点:
- 转发的目的地只能够是同一个应用内部的某个组件的地址
- 转发之后,浏览器地址栏的地址不变
- 转发所涉及的各个Web组件可以共享同一个request对象和response对象
区别
- 转发的目的地只能是同一个应用内部某个组件的地址,而重定向的目的地是任意的。
- 转发之后,浏览器地址栏的地址不变,而重定向会变。
- 转发所涉及的各个Web组件可以共享request对象,而重定向不可以。
- 转发是一件事情未做完,而重定向是一件事情已经做完。
Servlet生命周期
四个阶段:
- 实例化:指的是容器调用Servlet的构造器,创建Servlet对象。时机:
情况1:容器收到请求之后才创建Servlet对象。在默认情况下,容器只会为Servlet创建唯一的一个实例(多线程,有安全问题。每次请求创建一个线程,由线程去调用方法)。
情况2:容器事先(容器启动时)将某些Servlet(需配置load-on-startup
参数)对象创建好。load-on-startup参数值必须是>=0的整数,越小,优先级越高(即先被实例化)。参数加在web.xml配置文件里的某个<servlet>
标签里,如<load-on-startup>1</load-on-startup>
- 初始化:指的是容器在创建好Servlet对象之后,会立即调用Servlet对象的init方法。
- 就绪:指是Servlet对象可以接受调用了,容器收到请求之后,会调用Servlet对象的service方法来处理,且可以被执行多次。
- 销毁:销毁指的是Servlet容器在销毁Servlet对象之前,会调用destroy方法,且只会执行一次。
Servlet到底是单例还是多例
如果一个Servlet没有被部署在分布式的环境中,一般web.xml中声明的一个Servlet只对应一个实例。
而如果一个Servlet实现SingleThreadModel接口,就会被初始化多个实例。
在web.xml中声明几次,即使同一个Servlet,如果声明多次,也会生成多个实例。
Servlet容器资源路径处理
- Servlet容器会先假设访问的是一个Servlet,会依据应用名(appname)找到应用所在的文件夹,然后找到web.xml文件。
- 匹配
<url-pattern>
①精确匹配(完全匹配):“/”、大小写、名字完全一样。
②通配符匹配:使用 “” 来匹配任意长度的字符串,比如:<url-pattern>/</url-pattern>
③后缀匹配:使用“.”开头,后接任意的字符串,比如:<url-pattern>.do</url-pattern>
- 如果都不匹配,则容器的是一个静态资源文件(如html文件),然后容器会查找该文件,如果找到则返回,否则会返回404认为访问
context-param和init-param
web.xml里面可定义两种参数:
- application范围内的参数,存放在servletcontext中,在web.xml中配置如下:
<context-param>
<param-name>context/param</param-name>
<param-value>available during application</param-value>
</context-param>
- servlet范围内的参数,只能在servlet的init()方法中取得,在web.xml中配置如下:
<servlet>
<servlet-name>MainServlet</servlet-name>
<servlet-class>com.awesome.controller.MainServlet</servlet-class>
<init-param>
<param-name>param1</param-name>
<param-value>available in servlet init()</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
在servlet中可以通过代码分别取用:
public class MainServlet extends HttpServlet {
public MainServlet() {
super();
}
public void init() throws ServletException {
System.out.println("servlet参数" + this.getInitParameter("param1"));
System.out.println("servletContext参数" + getServletContext().getInitParameter("context/param"));
}
}
第一种参数在servlet里面可以通过getServletContext().getInitParameter("context/param")
得到;
第二种参数只能在servlet的init()方法中通过this.getInitParameter("param1")
取得;
参考
Servlet到底是单例还是多例?Tomcat系统架构与设计模式