Servlet基础知识

Servlet

Sun公司制订的一种用来扩展Web服务器功能的组件规范。当浏览器将请求发送给Web服务器(比如:apcahe的web server),Web服务器会向Servlet容器发送请求,Servlet容器负责解析请求数据包。

ServletContext

容器在启动时,会为每一个应用创建唯一的一个符合ServletContext接口要求的对象(Servlet上下文),该对象一直存在,只有非容器关闭时对象被销毁。

// GenericServlet抽象类,实际上调用ServletConfig的getServletContext方法
GenericServlet.getServletContext();
HttpSession.getServletContext();
ServletConfig.getServletContext();
FilterConfig.getServletContext();

作用:

  1. 绑定数据:setAttribute 、 removeAttribute 、 getAttribute 、 Request 、 Session 、 ServletContext都提供绑定数据相关的三个方法。如果都满足使用条件,应该优先使用生命周期短的,生命周期升序排列:Request<Session<ServletContext
    • Request对象上绑定的数据只有同一个请求所涉及的各个Web组件可以共享,例如:一个Servlet将数据绑定到Request,然后转发到一个jsp。请求先交给过滤器来处理,然后调用Servlet。
    • Session对象上绑定的数据是用一个会话所涉及的各个Web组件可以共享。
    • ServletContext对象绑定的数据是公开的,谁都可以访问,而且随时可访问
  2. 访问全局的初始化参数:即使用<context-param>配置的初始化参数,调用String getInitParameter(String paramName)方法,可以被同一个应用中的所有的Servlet、Filter共享。
  3. 依据逻辑路径path获得实际部署时的物理路径

Application

  1. 作用:用于保存应用程序中的公有数据,实现多客户之间的数据共享。
  2. 生命周期:从Web服务器启动,直到Web服务器关闭。
  3. 作用范围:application对象是一个应用程序级的对象,它作用于当前Web应用程序,也即作用于当前网站,所有访问当前网站的客户都共享一个application对象。
  4. 基类:javax.servlet.ServletContext类。

Cookie

一种客户端的状态管理技术。当浏览器访问服务器的时候,服务器可以将少量的数据以set-cookie消息头的方式发送给浏览器,浏览器会将这些数据保存下来。当浏览器再次访问服务器时,会将之前保存的这些数据以cookie消息头的方式发送给服务器。有几个cookie,就有几个set-cookie消息头。

  1. 创建:
// name:cookie的名称。value:cookie的值
Cookie c = new Cookie(String name, String value);
  1. 添加Cookie:response.addCookie(c);
  2. 查询Cookie
Cookie[] request.getCookies();//如果没有任何的cookie,则返回null;
String cookie.getName();
String cookie.getValue();
  1. 编码:cookie的值或者名称只允许合法的ASCII码字符串,如果是中文,需要将中文转换成ASCII码字符串。
String URLEncoder.encode(String str, String code);
String URLDecoder.decode(String str, String code);
  1. Cookie生存时间:默认情况下,浏览器会将cookie保存在内存里,只要浏览器不关闭,cookie会一直存在。
    启动浏览器后,操作系统会为浏览器开辟一块内存空间:
    ①浏览器访问服务器。
    ②服务器生成消息头setCookie发回给浏览器。
    ③浏览器将服务器生成的消息头保存到内存区域。
    ④当浏览器关闭,系统回收为浏览器分配的内存,cookie也相应消失。
    设置生存时间:使用cookie.setMaxAge(int seconds)方法。
    ①单位是秒。
    ②当seconds>0时,浏览器会将cookie保存在硬盘上,当cookie保存的时间超过seconds,则cookie会被浏览器删除。
    ③当seconds<0时,缺省值(浏览器会将cookie保存在内存里)。
    ④当seconds=0时,删除cookie。所以Cookie中无删除方法,设置为0即可。而修改,则为覆盖,用相同的name。
  2. Cookie路径问题:浏览器在向服务器上的某个地址发请求时,会比较请求地址与cookie的路径是否匹配,只有匹配的cookie才会发送。
    ①默认路径:值等于创建该cookie的组件的路径,比如:/web06_Cookie/
    ②匹配规则:只有当访问的地址是cookie的路径或着是其子路径时,浏览器才会将这个cookie进行发送。
  3. Cookie限制/缺点
    1. cookie可以被用户禁止。
    2. 因为cookie保存在浏览器端,所以cookie不安全。对于一些敏感的数据,需要加密处理。
    3. cookie只能够保存少量的数据(大约是4K左右)。
    4. cookie的个数也有限制(浏览器只能够保存大约300个左右的cookie,另外对于某个服务器也有cookie个数的限制,大约是20个)。
    5. cookie只能够保存字符串,对象、集合、数组都不能保存。

session

会话,服务器端的状态管理技术。
当浏览器访问服务器时,服务器会创建一个session对象(该对象有一个唯一的id号,称之为sessionId)。接下来,服务器在默认情况下,会使用set-cookie消息头将这个sessionId发送浏览器,浏览器会将这个sessionId保存下来(内存中,因为指定生存时间)。当浏览器再次访问服务器时,会将sessionId使用cookie消息头发送给服务器,服务器依据这个sessionId就可以找到之前创建的session对象。用户与服务器之间的多次交互叫一次会话。

创建:

  1. HttpSession s=request.getSession(boolean flag);//HttpSession是一个接口,返回一个符合要求的对象(工厂)
    当flag=true时:服务器会先检查请求当中是否有sessionId,没有则创建。有sessionId,则查找,找到则返回session对象。根据sessionId找不到,则服务器会创建一个新的session对象。flag默认为true。
    当flag=false时:服务器会先检查请求当中是否有sessionId,没有则返回null。有sessionId则查找,找到则返回session对象。找不到则返回null。

session超时:

  1. 服务器会将空闲时间过长的session对象删除。大部分服务器默认的session超时限制是30分钟。
  2. 修改超时限制:setMaxInactiveInterval(int seconds);或在web.xml中修改
<session-config>
	<session-timeout>30</session-timeout>
</session-config>

立即删除session:session.invalidate();。实际是清空session对象的内容,然后可以给其他人继续使用该session对象

优点

  1. session比较安全(相对于cookie,将所有状态都写在服务器端)
  2. session能够保存的数据类型更加丰富(cookie只能保存字符串)
  3. session能够保存的数据更大(cookie只能保存大约4K左右的数据),session理论上无限制
  4. session没有被禁止的问题,不需要url重写(cookie会被用户禁止)

缺点

  1. session会将数据放在服务器端,对服务器的资源的占用比较大,而cookie会将数据保存在浏览器端,对服务器资源的占用没有。
  2. session默认情况下,会将sessionId以cookie的方式发送给浏览器,浏览器会将session保存到内存中,如果浏览器关闭,浏览器发请求时就没有sessionId,服务器端的session对象就找不到。可用 spring session来管理。

用户禁止cookie后,如何继续使用session?

  1. 如果用户禁止cookie,服务器仍然会将sessionId以cookie的方式发送给浏览器,但浏览器不再保存这个cookie(sessionId)
  2. 如果想要继续使用session,需要采取其他方式来实现sessionId的跟踪,如url重写来实现sessionId的跟踪

url重写:浏览器在访问服务器上的某个地址时,不能够直接写这个组件(Servlet/JSP)的地址,而应该使用服务器生成的包含有sessionId的地址。

  1. response.encodeURL(String utl);//encodeURL方法用在链接地址、表单提交地址
  2. response.encodeRedirectURL(String url);//用于重定向
  3. 转发不用考虑!是服务器内部,不是浏览器访问服务器

Cookie、Session和Application比较

  1. 作用范围不同:
    session对象是用户级的对象,而application对象是应用程序级的对象。
    一个用户一个session对象,每个用户的session对象不同,在用户所访问网站的多个页面之间共享同一个session对象。
    一个Web应用程序一个application对象,每个Web应用程序的application对象不同,但一个Web应用程序的多个用户之间共享同一个application对象。
    在同一个网站下:
    每个用户的session对象不同
    所用用户的application对象相同
    在不同网站下:
    每个用户的session对象不同
    每个用户的application对象不同
  2. 生命周期不同:
    session对象:用户首次访问网站创建,用户离开该网站 (不一定要关闭浏览器) 消亡。
    application对象:启动Web服务器创建,关闭Web服务器销毁。

Servlet和Filter区别

整个流程:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。
Filter作用:

  1. Filter可以进行对特定的url请求和相应做预处理和后处理。
  2. 在HttpServletRequest到达Servlet之前,拦截客户的HttpServletRequest。
  3. 根据需要检查HttpServletRequest,也可以修改HttpServletRequest头和数据。
  4. 在HttpServletResponse到达客户端之前,拦截HttpServletResponse。
  5. 根据需要检查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)
特点:

  1. 重定向的地址是任意的,前提要存在否则报404
  2. 重定向之后,浏览器地址栏的地址会变成重定向地址

请求转发:一个Web组件(Servlet/JSP)将未完成的处理通过容器转交给另外一个Web组件继续完成。常见的情况是:一个Servlet将数据处理完毕之后,转交给一个JSP去展现。
步骤:

  1. 绑定数据到request:request里有个HashMap。request.setAttribute(String name,Object obj);
  2. 获得一个转发器:url:要转发给哪一个Web组件。RequestDispatcher rd=request.getRequsetDispatcher(String url);
  3. 转发:rd.forward(request,response);//JSP和Servlet会共享相同的请求和响应对象
  4. 在转发的目的地,可以使用request.getAttribute方法获得绑定的数据,然后进行处理。【注意:转发之前,先清空response对象中缓存的数据;不能调用out.close()或着out.flush只能同时处理一个响应】

特点:

  1. 转发的目的地只能够是同一个应用内部的某个组件的地址
  2. 转发之后,浏览器地址栏的地址不变
  3. 转发所涉及的各个Web组件可以共享同一个request对象和response对象

区别

  1. 转发的目的地只能是同一个应用内部某个组件的地址,而重定向的目的地是任意的。
  2. 转发之后,浏览器地址栏的地址不变,而重定向会变。
  3. 转发所涉及的各个Web组件可以共享request对象,而重定向不可以。
  4. 转发是一件事情未做完,而重定向是一件事情已经做完。

Servlet生命周期

四个阶段:

  1. 实例化:指的是容器调用Servlet的构造器,创建Servlet对象。时机:
    情况1:容器收到请求之后才创建Servlet对象。在默认情况下,容器只会为Servlet创建唯一的一个实例(多线程,有安全问题。每次请求创建一个线程,由线程去调用方法)。
    情况2:容器事先(容器启动时)将某些Servlet(需配置load-on-startup参数)对象创建好。load-on-startup参数值必须是>=0的整数,越小,优先级越高(即先被实例化)。参数加在web.xml配置文件里的某个<servlet>标签里,如<load-on-startup>1</load-on-startup>
  2. 初始化:指的是容器在创建好Servlet对象之后,会立即调用Servlet对象的init方法。
  3. 就绪:指是Servlet对象可以接受调用了,容器收到请求之后,会调用Servlet对象的service方法来处理,且可以被执行多次。
  4. 销毁:销毁指的是Servlet容器在销毁Servlet对象之前,会调用destroy方法,且只会执行一次。

Servlet到底是单例还是多例

如果一个Servlet没有被部署在分布式的环境中,一般web.xml中声明的一个Servlet只对应一个实例。
而如果一个Servlet实现SingleThreadModel接口,就会被初始化多个实例。
在web.xml中声明几次,即使同一个Servlet,如果声明多次,也会生成多个实例。

Servlet容器资源路径处理

  1. Servlet容器会先假设访问的是一个Servlet,会依据应用名(appname)找到应用所在的文件夹,然后找到web.xml文件。
  2. 匹配<url-pattern>
    ①精确匹配(完全匹配):“/”、大小写、名字完全一样。
    ②通配符匹配:使用 “” 来匹配任意长度的字符串,比如:<url-pattern>/</url-pattern>
    ③后缀匹配:使用“.”开头,后接任意的字符串,比如:<url-pattern>.do</url-pattern>
  3. 如果都不匹配,则容器的是一个静态资源文件(如html文件),然后容器会查找该文件,如果找到则返回,否则会返回404认为访问

context-param和init-param

web.xml里面可定义两种参数:

  1. application范围内的参数,存放在servletcontext中,在web.xml中配置如下:
<context-param>
	<param-name>context/param</param-name>
	<param-value>available during application</param-value>
</context-param>
  1. 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系统架构与设计模式

posted @ 2022-10-29 17:23  johnny233  阅读(14)  评论(0编辑  收藏  举报  来源