servlet规范

Servlet规范

一。Servlet规范介绍:
1.servlet规范来自于JAVAEE规范中的一种
2.作用:
1)在Servlet规范中,【指定】动态资源文件开发步骤
2)在Servlet规范中,指定Http服务器【调用】动态资源文件规则(Servlet接口实现类)
3)在Servlet规范中,指定Http服务器【管理】动态资源文件实例对象规则

二。Servlet接口实现类:
1.【Servlet接口】来自于Servlet规范下一个接口,这个接口存在于Http服务器提供的jar包中
2.Tomcat服务器下lib文件有一个servlet-api.jar存放Servlet接口(javax.servlet.Servlet接口)
3.Servlet规范中认为,Http服务器能调用的【动态资源文件】必须是一个Servlet接口实现类
例子:

    class Student{
     //不是动态资源文件,Tomcat无权调用
    }
    class Teacher implements Servlet{
     //合法动态资源文件,Tomcat有权利调用
     Servlet obj = new Teacher();
     obj.doGet()
    }

三。Servlet接口实现类开发步骤
第一步:创建一个Java类继承于HttpServlet父类,使之成为一个Servlet接口实现类
第二步:重写HttpServlet父类两个方法。doGet或者doPost
get 浏览器------》oneServlet.doGet()
post 浏览器------》oneServlet.doPost()
第三步:将Servlet接口实现类信息【注册】到Tomcat服务器
【网站】—>【web】—》【WEB-INF】—>web.xml

    <!--将Servlet接口实现类类路径地址交给Tomcat-->
    <servlet>
        <servlet-name>mm</servlet-name> <!--声明一个变量存储servlet接口实现类类路径-->
        <servlet-class>com.bjpowernode.controller.OneServlet</servlet-class><!--声明servlet接口实现类类路径-->
    </servlet>
    Tomcat  String mm = "com.bjpowernode.controller.OneServlet"
    <!--为了降低用户访问Servlet接口实现类难度,需要设置简短请求别名-->
    <servlet-mapping> 
        <servlet-name>mm</servlet-name>
        <url-pattern>/one</url-pattern> <!--设置简短请求别名,别名在书写时必须以"/"为开头-->
    </servlet-mapping>
如果现在浏览器向Tomcat索要OneServlet时地址
http://localhost:8080/myWeb/one

三。Servlet对象生命周期:
1.网站中所有的Servlet接口实现类的实例对象,只能由Http服务器负责创建。
开发人员不能手动创建Servlet接口实现类的实例对象
2.在默认的情况下,Http服务器接收到对于【当前Servlet接口实现类】第一次请求时,自动创建这个Servlet接口实现类的实例对象,
在手动配置情况下,要求Http服务器在【启动时】自动创建某个Servlet接口实现类的实例对象

	<servlet>
	     <servlet-name>mm</servlet-name> <!--声明一个变量存储servlet接口实现类类路径-->
	     <servlet-class>com.bjpowernode.controller.OneServlet</servlet-class>
	     <load-on-startup>30<load-on-startup><!--填写一个大于0的整数即可-->
	</servlet>

说明:在中添加的作用是,标记是否在Web服务器(这里是Tomcat)
启动时会创建这个 Servlet 实例,即是否在 Web 服务器启动时调用执行该 Servlet 的 init()方法,而不是在真正访问时才创建。
它的值必须是一个整数。
当值大于等于 0 时,表示容器在启动时就加载并初始化这个 servlet,数值越小,该 Servlet
的优先级就越高,其被创建的也就越早;
当值小于 0 或者没有指定时,则表示该 Servlet 在真正被使用时才会去创建。
当值相同时,容器会自己选择创建顺序。

3.在Http服务器运行期间,一个Servlet接口实现类只能被创建出一个实例对象
4.在Http服务器关闭时刻,自动将网站中所有的Servlet对象进行销毁

互联网通信流程图
互联网通信流程图

四。HttpServletResponse接口
1.介绍:
1)【HttpServletResponse接口】来自于Servlet规范中,在Tomcat中存在servlet-api.jar
2)HttpServletResponse接口实现类由Http服务器负责提供
3)HttpServletResponse接口负责将doGet/doPost方法执行结果写入到【响应体】交给浏览器
4)开发人员习惯于将HttpServletResponse接口修饰的对象称为【响应对象】
2.主要功能:
1) 将执行结果以二进制形式写入到【响应体】
2) 设置响应头中[content-type]属性值,从而控制浏览器使用对应编译器将响应体二进制数据编译为【文字,图片,视频,命令】
3) 设置响应头中【location】属性,将一个请求地址赋值给location。从而控制浏览器向指定服务器发送请求

五。HttpServletRequest接口
1.介绍:
1)【HttpServletRequest接口】来自于Servlet规范中,在Tomcat中存在servlet-api.jar
2)HttpServletRequest接口实现类由Http服务器负责提供
3)HttpServletRequest接口负责在doGet/doPost方法运行时读取Http请求协议包中信息
4)开发人员习惯于将HttpServletRequest接口修饰的对象称为【请求对象】
2.作用:
1)可以读取Http请求协议包中【请求行】信息
2)可以读取保存在Http请求协议包中【请求头】或则【请求体】中请求参数信息
3)可以代替浏览器向Http服务器申请资源文件调用

六。请求对象和响应对象生命周期
1.在Http服务器接收到浏览器发送的【Http请求协议包】之后,
自动为当前的【Http请求协议包】生成一个【请求对象】和一个【响应对象】
2.在Http服务器调用doGet/doPost方法时,负责将【请求对象】和【响应对象】
作为实参传递到方法,确保doGet/doPost正确执行
3.在Http服务器准备推送Http响应协议包之前,负责将本次请求关联的【请求对象】和【响应对象】销毁
***【请求对象】和【响应对象】生命周期贯穿一次请求的处理过程中
*** 【请求对象】和【响应对象】相当于用户在服务端的代言人

七。欢迎资源文件
1.前提:用户可以记住网站名,但是不会记住网站资源文件名
2.默认欢迎资源文件:
用户发送了一个针对某个网站的【默认请求】时,此时由Http服务器自动从当前网站返回的资源文件
正常请求: http://localhost:8080/myWeb/index.html
默认请求: http://localhost:8080/myWeb/
3.Tomcat对于默认欢迎资源文件定位规则
1)规则位置:Tomcat安装位置/conf/web.xml
2)规则命令:

	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>

4.设置当前网站的默认欢迎资源文件规则
1)规则位置: 【网站/web/WEB-INF/web.xml】
2)规则命令:

	 <welcome-file-list>
		<welcome-file>login.html</welcome-file>
	</welcome-file-list>
3)网站设置自定义默认文件定位规则,此时Tomcat自带定位规则将失效

八。Http状态码
1.介绍:
1)由三位数字组成的一个符号。
2)Http服务器在推送响应包之前,根据本次请求处理情况,将Http状态码写入到响应包中【状态行】上
3)如果Http服务器针对本次请求,返回了对应的资源文件。通过Http状态码通知浏览器应该如何处理这个结果
如果Http服务器针对本次请求,无法返回对应的资源文件。通过Http状态码向浏览器解释不能提供服务的原因
2.分类:
1)组成:100—599,分为5个大类
2)1XX:最有特征 100; 通知浏览器本次返回的资源文件并不是一个独立的资源文件,
需要浏览器在接收响应包之后,继续向Http服务器所要依赖的其他资源文件
3) 2XX:最有特征200,通知浏览器本次返回的资源文件是一个完整独立资源文件,
浏览器在接收到之后不需要索要其他关联文件
4)3xx:最有特征302,通知浏览器本次返回的不是一个资源文件内容而是一个资源文件地址,
需要浏览器根据这个地址自动发起请求来索要这个资源文件,
通过response.sendRedirect(“资源文件地址”)写入到响应头中的location中。【重定向】
而这个行为导致Tomcat将302状态码写入到状态行
5)4XX:最有特征404,通知浏览器,由于在服务端没有定位到被访问的资源文件,因此无法提供帮助
最有特征405,通知浏览器,在服务端已经定位到被访问的资源文件(Servlet),
但是这个Servlet对于浏览器采用的请求方式不能处理
6)5xx:最有特征500,通知浏览器,在服务端已经定位到被访问的资源文件(Servlet),
这个Servlet可以接收浏览器采用请求方式,但是Servlet在处理请求期间,由于Java异常导致处理失败。
1、首先转发是服务器的操作,而重定向是客户端的操作。
2、转发:当客户端向服务器请求访问A资源,服务器将其转发到B这,返回B资源;
重定向:当客户端向服务器访问A资源时,服务器返回一个302代码和一个URL给客户端,客户端见到302,立马就向服务器给的URL进行访问。
3、转发只有一次请求而重定向有两次请求,转发只能在站内转发,重定向可以随意定向。

九。多个Servlet之间调用规则:
1.前提条件:某些来自于浏览器发送请求,往往需要服务端中多个Servlet协同处理。
但是浏览器一次只能访问一个Servlet,导致用户需要手动通过浏览器发起多次请求才能得到服务。
这样增加用户获得服务难度,导致用户放弃访问当前网站【98k,AKM】。
2.提高用户使用感受规则:无论本次请求涉及到多少个Servlet,用户只需要【手动】通知浏览器发起一次请求即可。
3.多个Servlet之间调用规则:
1)重定向解决方案
2)请求转发解决方案

十。重定向解决方案:
1.工作原理: 用户第一次通过【手动方式】通知浏览器访问OneServlet。
OneServlet工作完毕后,将TwoServlet地址写入到响应头【location】属性中,导致Tomcat将302状态码写入到状态行。
在浏览器接收到响应包之后,会读取到302状态。此时浏览器自动根据响应头中location属性地址发起第二次请求,访问TwoServlet去完成请求中剩余任务。
2.实现命令:response.sendRedirect(“请求地址”),将地址写入到响应包中的响应头location属性中
3.特征:
1)请求地址:既可以把当前网站内部的资源文件地址发送给浏览器 (/网站名/资源文件名),也可以把其他网站资源文件地址发送给浏览器(http://ip地址:端口号/网站名/资源文件名)。
2)请求次数:浏览器至少发送两次请求,但是只有第一次请求是用户手动发送。后续请求都是浏览器自动发送的。
3)请求方式:重定向解决方案中,通过【地址栏】通知浏览器发起下一次请求,
因此通过重定向解决方案调用的资源文件接收的请求方式一定是【GET】。
4.缺点:重定向解决方案需要在浏览器与服务器之间进行多次往返,大量时间消耗在往返次数上,增加用户等待服务时间。

十一。请求转发解决方案:
1.原理:用户第一次通过手动方式要求浏览器访问OneServlet。
OneServlet工作完毕后,通过当前的请求对象代替浏览器向Tomcat发送请求,申请调用TwoServlet。
Tomcat在接收到这个请求之后,自动调用TwoServlet来完成剩余任务。
2.实现命令:【请求对象代替浏览器】向Tomcat发送请求
//1.通过当前请求对象生成资源文件申请报告对象
RequestDispatcher report = request.getRequestDispatcher(“/资源文件名”);一定要以"/“为开头
//2.将报告对象发送给Tomcat
report.forward(当前请求对象,当前响应对象)
3.优点:1)无论本次请求涉及到多少个Servlet,用户只需要手动通过浏览器发送一次请求。
2)Servlet之间调用发生在服务端计算机上,节省服务端与浏览器之间往返次数,增加处理服务速度。
4.特征:1)请求次数,在请求转发过程中,浏览器只发送一次请求。
2)请求地址,只能向Tomcat服务器申请调用【当前网站】下资源文件地址。
request.getRequestDispathcer(”/资源文件名") 不要写网站名
3)请求方式,在请求转发过程中,浏览器只发送一个了个Http请求协议包。
参与本次请求的所有Servlet共享同一个请求协议包,
因此这些Servlet接收的请求方式与浏览器发送的请求方式保持一致。

十二。多个Servlet之间数据共享实现方案:
1.数据共享:OneServlet工作完毕后,将产生数据交给TwoServlet来使用
2.Servlet规范中提供四种数据共享方案
1.ServletContext接口
2.Cookie类
3.HttpSession接口
4.HttpServletRequest接口

十三。【ServletContext接口】:
1.介绍:1)来自于Servlet规范中一个接口。在Tomcat中存在servlet-api.jar,在Tomcat中负责提供这个接口实现类
2)如果两个Servlet来自于【同一个网站】。彼此之间通过网站的ServletContext实例对象实现数据共享
3)开发人员习惯于将ServletContext对象称为【全局作用域对象】
2.工作原理:每一个网站都存在一个全局作用域对象。这个全局作用域对象【相当于】一个Map。
在这个网站中OneServlet可以将一个数据存入到全局作用域对象,
当前网站中其他Servlet此时都可以从全局作用域对象得到这个数据进行使用
3.全局作用域对象生命周期:
1)在Http服务器启动过程中,自动为当前网站在内存中创建一个全局作用域对象。
2)在Http服务器运行期间时,一个网站只有一个全局作用域对象。
3)在Http服务器运行期间,全局作用域对象一直处于存活状态。
4)在Http服务器准备关闭时,负责将当前网站中全局作用域对象进行销毁处理
**全局作用域对象生命周期贯穿网站整个运行期间
4.命令实现:【同一个网站】OneServlet将数据共享给TwoServlet

OneServlet{
   public void doGet(HttpServletRequest request,HttpServletResponse response){
	//1.通过【请求对象】向Tomcat索要当前网站中【全局作用域对象】
	ServletContext application = request.getServletContext();
    //2.将数据添加到全局作用域对象作为【共享数据】
	application.setAttribute("key1",数据);
   }
}

TwoServlet{
  public void doGet(HttpServletRequest request,HttpServletResponse response){
	//1.通过【请求对象】向Tomcat索要当前网站中【全局作用域对象】
	ServletContext application = request.getServletContext();
	//2.从全局作用域对象得到指定关键字对应数据
    Object 数据 =  application.getAttribute("key1");
  }
}

十四。Cookie
1.介绍:
1)Cookie来自于Servlet规范中一个工具类,存在于Tomcat提供servlet-api.jar中。
2)如果两个Servlet来自于同一个网站,并且为同一个浏览器/用户提供服务,此时借助于Cookie对象进行数据共享。
3) Cookie存放当前用户的私人数据,在共享数据过程中提高服务质量
4) 在现实生活场景中,Cookie相当于用户在服务端得到【会员卡】
2.原理:用户通过浏览器第一次向MyWeb网站发送请求申请OneServlet。
OneServlet在运行期间创建一个Cookie存储与当前用户相关数据,
OneServlet工作完毕后,【将Cookie写入到响应头】交还给当前浏览器。
浏览器收到响应响应包之后,将cookie存储在浏览器的缓存,
一段时间之后,用户通过【同一个浏览器】再次向【myWeb网站】发送请求申请TwoServlet时。【浏览器需要无条件的将myWeb网站之前推送过来的Cookie,写入到请求头】发送过去,此时TwoServlet在运行时,就可以通过读取请求头中cookie中信息,得到OneServlet提供的共享数据
3.实现命令: 同一个网站 OneServlet 与 TwoServlet 借助于Cookie实现数据共享

OneServlet{
    public void doGet(HttpServletRequest request,HttpServletResponse resp){
		//1.创建一个cookie对象,保存共享数据(当前用户数据)
	    Cookie card = new Cookie("key1","abc");
	    Cookie card1= new Cookie("key2","efg");
	    ****cookie相当于一个map,一个cookie中只能存放一个键值对
	    ****这个键值对的key与value只能是String,键值对中key不能是中文
	    //2.【发卡】将cookie写入到响应头,交给浏览器
	    resp.addCookie(card);
	    resp.addCookie(card1);
    }
}

浏览器 <–收到响应包-- 状态行【200】
响应头【cookie: key1=abc; key2=eft】
空白行【】
响应体【处理结果】
浏览器向myWeb网站发送请求访问TwoServlet -->请求包
请求行【url:/myWeb/two method:get】
【请求参数[get] Cookie:key1=abc;key2=efg】
空白行【】
请求体【请求参数[POST]】

TwoServlet{		 
   public void doGet(HttpServletRequest request,HttpServletResponse resp){
	//1.调用请求对象从请求头得到浏览器返回的Cookie
    Cookie  cookieArray[] = request.getCookies();
    //2.循环遍历数据得到每一个cookie的key 与 value
	  for(Cookie card:cookieArray){
	      String key = card.getName(); 读取key  "key1"
		  Strign value = card.getValue(); 读取value "abc"
		  提供较好的服务。。。。。。。。
	  }
   }
}	

4.Cookie销毁时机:
1.在默认情况下,Cookie对象存放在浏览器的缓存中。【因此只要浏览器关闭,Cookie对象就被销毁掉】。
2.在手动设置情况下,可以要求浏览器将接收的Cookie存放在客户端计算机上硬盘上,
同时需要指定Cookie在硬盘上存活时间。
在存活时间范围内,关闭浏览器关闭客户端计算机,关闭服务器,都不会导致Cookie被销毁。
在存活时间到达时,Cookie自动从硬盘上被删除
cookie.setMaxAge(60); //cookie在硬盘上存活1分钟

十五。HttpSession 接口:
1.介绍:1)【HttpSession接口】来自于Servlet规范下一个接口。存在于Tomcat中servlet-api.jar中,
其实现类由Http服务器提供,Tomcat提供实现类存在于servlet-api.jar。
2)如果两个Servlet来自于同一个网站,并且为同一个浏览器/用户提供服务,
此时借助于HttpSession对象进行数据共享。
3)开发人员习惯于将HttpSession接口修饰对象称为【会话作用域对象】
2.HttpSession 与 Cookie 区别:【面试题】
1)存储位置: 一个在天上,一个在地下
Cookie:存放在客户端计算机(浏览器内存/硬盘)
HttpSession:存放在服务端计算机内存
2)数据类型:
Cookie对象存储共享数据类型只能是String
HttpSession对象可以存储任意类型的共享数据Object
3) 数据数量:
一个Cookie对象只能存储一个共享数据
HttpSession使用map集合存储共享数据,所以可以存储任意数量共享数据
4)参照物:
Cookie相当于客户在服务端【会员卡】
HttpSession相当于客户在服务端【私人保险柜】
3.命令实现:同一个网站(myWeb)下OneServlet将数据传递给TwoServlet

OneServlet{
    public void doGet(HttpServletRequest request,HttpServletResponse response){
		//1.调用请求对象向Tomcat索要当前用户在服务端的私人储物柜
	     HttpSession   session = request.getSession();
        //2.将数据添加到用户私人储物柜
	    session.setAttribute("key1",共享数据);
    }
}

浏览器访问/myWeb中TwoServlet

TwoServlet{		      
	public void doGet(HttpServletRequest request,HttpServletResponse response){
		//1.调用请求对象向Tomcat索要当前用户在服务端的私人储物柜
		HttpSession   session = request.getSession();
		//2.从会话作用域对象得到OneServlet提供的共享数据
		Object 共享数据 = session.getAttribute("key1");
	}
}

4.Http服务器如何将用户与HttpSession关联起来?【cookie!】Session技术在底层是基于Cookie技术实现的。
问题:服务器是如何实现一个session为一个用户浏览器服务的?换个说法:为什么服务器能够为不同的用户浏览器提供不同session?

HTTP协议是无状态的,Session不能依据HTTP连接来判断是否为同一个用户。于是乎:服务器向用户浏览器发送了一个名为JESSIONID的Cookie,它的值是Session的id值。其实Session依据Cookie来识别是否是同一个用户。

简单来说:Session 之所以可以识别不同的用户,依靠的就是Cookie。
Session技术在底层是基于Cookie技术实现的

5.getSession() 与 getSession(false)
1)getSession(): 如果当前用户在服务端已经拥有了自己的私人储物柜。
用户身份合法,要求tomcat将这个私人储物柜进行返回
如果当前用户在服务端尚未拥有自己的私人储物柜,要求tocmat为当前用户创建一个全新的私人储物柜
2)getSession(false):如果当前用户在服务端已经拥有了自己的私人储物柜。
用户身份不确定或者不合法,要求tomcat将这个私人储物柜进行返回
如果当前用户在服务端尚未拥有自己的私人储物柜,此时Tomcat将返回null
返回一个新的、返回一个null。
6.HttpSession生命周期:
0、在用户第一次访问jsp、servlet等程序时才会创建Session,session存储在服务器端,Session对象保存在内存里,为了防止内存溢出,服务器会把长时间没有活跃的Session从内存中删除,这个时间也就是Session的超时时间。。只访问html、image等静态资源并不会创建,可调用request.getSession(true)强制生成Session。
1.用户与HttpSession关联时使用的Cookie只能存放在浏览器缓存中。
2.在浏览器关闭时(Cookie对象就被销毁掉),意味着用户与他的HttpSession关系被切断。
3.由于Tomcat无法检测浏览器何时关闭,因此在浏览器关闭时并不会导致Tomcat将浏览器关联的HttpSession进行销毁
4.为了解决这个问题,Tomcat为每一个HttpSession对象设置【空闲时间】,
这个空闲时间默认【30分钟】,如果当前HttpSession对象空闲时间达到30分钟,
此时Tomcat认为用户已经放弃了自己的HttpSession,此时Tomcat就会销毁掉这个HttpSession
7.HttpSession空闲时间手动设置
在当前网站/web/WEB-INF/web.xml

	<session-config>
	       <session-timeout>5</session-timeout> <!--当前网站中每一个session最大空闲时间5分钟-->
	</session-config>

session和cokkie的生命周期不同之处

十六。HttpServletRequest 接口实现数据共享
1.介绍:1) 在同一个网站中,如果两个Servlet之间通过【请求转发】方式进行调用,彼此之间【共享】同一个请求协议包。而一个请求协议包只对应一个请求对象,因此servlet之间共享同一个请求对象,此时可以利用这个请求对象在两个Servlet之间实现数据共享
2) 在请求对象实现Servlet之间数据共享功能时,开发人员将请求对象称为【请求作用域对象】,
2.命令实现:OneServlet通过请求转发申请调用TwoServlet时,需要给TwoServlet提供共享数据

OneServlet{			 
	public void doGet(HttpServletRequest req,HttpServletResponse response){
		//1.将数据添加到【请求作用域对象】中attribute属性
		req.setAttribute("key1",数据); //数据类型可以任意类型Object
		//2.向Tomcat申请调用TwoServlet
		req.getRequestDispatcher("/two").forward(req,response)
    }
}
TwoServlet{
	public void doGet(HttpServletRequest req,HttpServletResponse response){                      
	    //从当前请求对象得到OneServlet写入到共享数据
	    Object 数据 = req.getAttribute("key1");
    }
}

十七。Servlet规范扩展----监听器接口
1.介绍:1)一组来自于Servlet规范下接口,共有8个接口。在Tomcat存在servlet-api.jar包
2)监听器接口需要由【开发人员】亲自实现,Http服务器提供jar包并没有对应的实现类
3)监听器接口用于监控【作用域对象生命周期变化时刻】以及【作用域对象共享数据变化时刻】
2.作用域对象:
1)在Servlet规范中,认为在服务端内存中可以在某些条件下,为两个Servlet之间提供数据共享方案的对象,被称为【作用域对象】
2)Servlet规范下作用域对象:
ServletContext: 全局作用域对象
HttpSession : 会话作用域对象
HttpServletRequest:请求作用域对象
3.监听器接口实现类开发规范:三步
1)根据监听的实际情况,选择对应监听器接口进行实现
2)重写监听器接口声明【监听事件处理方法】
3)在web.xml文件将监听器接口实现类注册到Http服务器
4.ServletContextListener接口:
1)作用:通过这个接口合法的检测全局作用域对象被初始化时刻以及被销毁时刻
2)监听事件处理方法:
public void contextInitlized():在全局作用域对象被Http服务器初始化被调用
public void contextDestory():在全局作用域对象被Http服务器销毁时候触发调用
5.ServletContextAttributeListener接口:
1)作用:通过这个接口合法的检测全局作用域对象共享数据变化时刻
2)监听事件处理方法:
public void contextAdd():在全局作用域对象添加共享数据
public void contextReplaced():在全局作用域对象更新共享数据
public void contextRemove():在全局作用域对象删除共享数据
6.全局作用域对象共享数据变化时刻
ServletContext application = request.getServletContext();
application.setAttribute(“key1”,100); //新增共享数据
application.setAttribute(“key1”,200); //更新共享数据
application.removeAttribute(“key1”); //删除共享数据

拓展:用户添加时connection的创建和销毁浪费时间,那么在tomcat服务器启动时会为当前网站创建全局作用域对象,
然后通过ContecxtServletListernr接口监听全局作用域对象,创建一批connection通道并放到全局作用域对象中保存。
注意主要重载很多方法。

十八:Servlet规范扩展----Filter接口(过滤器接口)
过滤器执行流程

1.介绍:
1)来自于Servlet规范下接口,在Tomcat中存在于servlet-api.jar包
2)Filter接口实现类由【开发人员】负责提供,Http服务器不负责提供
3)执行地位在Servlet之前,客户端发送请求时,在Http服务器调用资源文件之前,会先经过Filter,对Http服务器进行过滤,再到达目标Servlet。响应时,会根据执行流程再次反向执行Filter
2.具体作用:
1)拦截Http服务器,帮助Http服务器检测当前请求合法性
2)拦截Http服务器,对当前请求进行增强操作
比如servlet很多时,post方式发送请求需要设置很多req.setCharacterEnconding(“utf-8”)
这个时候就可以使用拦截器,设置完毕后把拦截的请求对象返还给tomcat。
tomcat在调用servlet时,就会把对象传到dopost方法中
3.Filter接口实现类开发步骤:三步
1)创建一个Java类实现Filter接口
2)重写Filter接口中doFilter方法
3)web.xml将过滤器接口实现类注册到Http服务器
4.Filter拦截地址格式
1)命令格式:


<filter>
		<!--  名称-->
	<filter-name>ThrowanexceptionS</filter-name>
		<!--  过滤类全称-->
	<filter-class>S.M.fileter.MyFilter</filter-class>
</filter>

<!-- 映射路径配置-->
<filter-mapping>
		<!--  名称-->
	<filter-name>oneFilter</filter-name>
		<!--  过滤器的url匹配规则和Servlet类-->
	<url-pattern>拦截地址</url-pattern>
</filter-mapping>
2)命令作用:
	拦截地址通知Tomcat在调用何种资源文件之前需要调用OneFilter过滤进行拦截
3)要求Tomcat在调用某一个具体文件之前,来调用OneFilter拦截
<url-pattern>/img/mm.jpg</url-pattern>
4)要求Tomcat在调用某一个文件夹下所有的资源文件之前,来调用OneFilter拦截
<url-pattern>/img/*</url-pattern>
5)要求Tomcat在调用任意文件夹下某种类型文件之前,来调用OneFilter拦截
<url-pattern>*.jpg</url-pattern>
6)要求Tomcat在调用网站中任意文件时,来调用OneFilter拦截
<url-pattern>/*</url-pattern>

过滤器链
客户端向服务器请求后,服务器调用Servlet之前回执行一组过滤器,这组过滤器就叫做过滤器链

每一个过滤器实现某个特定的功能,当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的【FilterChain对象】传递给此方法,在doFilter方法中,如果调用FilterChain对象中的doFilter方法,web服务器会检查FilterChain对象中是否还有filter。如果有调用第二个Filter,就继续执行第二个Filter。如果没有,就调用目标资源。
多个过滤器执行流程

1、拦截器是基于Java的反射机制的,而过滤器是基于函数回调
2、拦截器不依赖与servlet容器,而过滤器依赖与servlet容器
3、拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用
4、拦截器可以访问action上下文、值栈里的对象,而过滤器不能
5、在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次

拦截器: 依赖 WEB 框架,在 SrpingMvc 中就依赖 SpringMVC 框架。是属于面向切面变成的一种运用。
执行顺序
单个拦截器执行顺序
单个拦截器执行顺序

多个拦截器执行的顺序
多个拦截器的注册与执行

多个拦截器的执行顺序
当有多个拦截器时,形成拦截器链。拦截器链的执行顺序,与其注册顺序一致。需要再
次强调一点的是,当某一个拦截器的 preHandle()方法返回 true 并被执行到时,会向一个专门的方法栈中放入该拦截器的 afterCompletion()方法。

其他:
由于servlet采用的是单实例,也就是整个应用中只有一个实例对象,所以我们需要分析一下,这个唯一的实例对象中的类成员是否线程安全。

下面我们来看一个小案例:
首先我们定义一个用户名的成员变量,然后获取客户端发送过来的用户信息,最后再响应给客户端。
修改前的servlet
此时,我们在浏览器中传入aaa用户请求服务器,这个时候浏览器上理所当然的显示出了aaa用户的信息。
单线程没问题
我们在获取用户名和响应用户信息之间加一个线程睡眠,然后让两个不同的浏览器同时去访问服务器。
修改后的servlet
这个时候我们使用火狐浏览器去请求aaa,使用谷歌浏览器请求bbb,会发现谷歌浏览器请求的bbb依然显示的是bbb用户,而火狐浏览器请求的aaa也显示了bbb用户。
火狐浏览器

谷歌浏览器
结论:
一个浏览器代表了一个线程,多个浏览器代表多个线程。按理说我们期望应该是每个浏览器查看的都是自己的用户名,而现在我们看到的确是混乱的用户数据。因此我们可以认为servlet是线程不安全的!

解决方法
1、加锁
发生线程安全的代码加上一个锁
2、全局变量改为局部变量
全局变量改为局部变量
生命周期
Servlet 生命周期流程
Servlet 生命周期中 init 和 destroy 方法只会在 Servlet 实例创建和销毁时被调用【一次】,而 service 方法则会在每个请求到达时被调用一次。此外,Servlet 还可以实现其他生命周期方法,如 init(ServletConfig config)、getServletConfig() 等,以提供更加灵活的初始化和配置方式。

2、Spring 中一个 Controller 是一个Servlet 吗?
在 Spring 中,每个 Controller 类并不是一个 Servlet,而是通过 Servlet 映射器(HandlerMapping)和适配器(HandlerAdapter)来将 HTTP 请求映射到相应的方法进行处理。
具体来说,Spring MVC 框架使用了 DispatcherServlet 作为前置控制器,负责接收客户端的请求并将请求分发给相应的 Controller 进行处理。DispatcherServlet 会根据配置的 Servlet 映射器和适配器来选择合适的 Controller 类,并将请求转发给该类中的具体方法进行处理。在方法中,可以通过注解来定义请求参数、返回值和异常处理等信息,从而更加方便地实现业务逻辑的编写。
因此,虽然每个 Controller 类并不是一个 Servlet,但在 Spring MVC 框架中,它们可以像 Servlet 一样接收并处理 HTTP 请求。同时,Spring 还提供了很多方便的注解和工具类来简化 Controller 类的编写,使得开发者可以更加专注于业务逻辑的实现。

3、在 Spring 中有多少个 Servlet ?
在一个 Spring 应用程序中,通常会有一个或多个 Servlet。其中,最常见的是 DispatcherServlet,它是 Spring MVC 框架的核心组件之一,负责接收客户端请求并将请求分发给相应的 Controller 进行处理。

除了 DispatcherServlet,Spring 还提供了一些其他的 Servlet,包括:

ContextLoaderServlet:用于在 Web 应用程序启动时加载 Spring 配置文件,并将 ApplicationContext 对象存储在 ServletContext 中供其他组件使用。

FrameworkServlet:是 DispatcherServlet 的父类,用于处理与 Spring 框架相关的 Servlet 请求,如请求映射、视图解析等。

HttpPutFormContentFilter:用于处理 PUT 请求中的表单数据。

OpenEntityManagerInViewFilter:用于在 Web 请求结束时自动关闭 EntityManager,以避免因为长时间持有 EntityManager 导致的内存泄漏。

DelegatingFilterProxy:是一个通用的过滤器代理,可以将过滤器的实现委托给 Spring 容器中的任意一个 Bean 实例。

需要注意的是,除了 DispatcherServlet 外,其他的 Servlet 大多是一些辅助性的组件,用于解决一些特定的问题,如处理 PUT 请求中的表单数据、自动关闭 EntityManager 等。开发者在使用 Spring 框架时,一般只需要关注 DispatcherServlet 的配置和使用即可。

4、DispatcherServlet 的生命周期
DispatcherServlet 是 Spring MVC 框架中的一个核心组件,它作为前置控制器负责接收客户端请求并将请求分发给相应的 Controller 进行处理。它的生命周期可以分为以下几个阶段:

初始化阶段(Initialization):在容器启动时,Servlet 容器会自动创建 DispatcherServlet 实例并调用其 init() 方法进行初始化。在初始化阶段中,DispatcherServlet 会读取并解析配置文件(如 web.xml 或注解配置等),创建必要的组件对象(如 HandlerMapping、HandlerAdapter 等),并将它们存储在 ServletContext 中,以便于在后续的请求处理中使用。

请求处理阶段(Request Handling):当客户端发送请求时,Servlet 容器会将请求交给 DispatcherServlet 进行处理。在请求处理阶段中,DispatcherServlet 会根据配置的 HandlerMapping 找到匹配的 Controller,然后调用相应的 Controller 方法进行处理。在方法执行过程中,DispatcherServlet 会根据配置的 HandlerAdapter 对请求参数进行解析,将其转换为方法所需的类型,并将方法的执行结果封装为 ModelAndView 对象。最后,DispatcherServlet 会调用 ViewResolver 将 ModelAndView 对象转换为相应的视图,并将视图渲染后的结果返回给客户端。

销毁阶段(Destruction):当 Servlet 容器关闭时,会调用 DispatcherServlet 的 destroy() 方法进行销毁。在销毁阶段中,DispatcherServlet 会释放所有的资源(如 HandlerMapping、HandlerAdapter 等),并清除 ServletContext 中的相应对象。

需要注意的是,由于 DispatcherServlet 是一个单例对象,因此它的生命周期与整个应用程序的生命周期是一致的,即在应用程序启动时创建,在应用程序关闭时销毁。在处理请求时,DispatcherServlet 会创建一个新的线程来处理每个请求,因此它的请求处理阶段是并发的,可以处理多个请求同时到达的情况。

DispatcherServlet 异步处理请求的源码展示:
在 DispatcherServlet 中创建新的线程来处理请求的代码位于 doService() 方法中。以下是部分源码示例:

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 获取处理器
    HandlerExecutionChain mappedHandler = getHandler(request);
    // 获取处理器适配器
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    // 使用 Callable 封装请求和响应
    final ModelAndView exMv = ha.handle(request, response, mappedHandler.getHandler());
    // 创建新线程处理请求
    if (asyncManager.isConcurrentHandlingStarted()) {
        return;
    }
    // 判断是否支持异步处理
    if (exMv != null && exMv.isAsyncStarted()) {
        if (isAsyncDispatch(request)) {
            // 使用 Spring 的异步机制进行处理
            if (request.getAsyncContext().getTimeout() > 0) {
                asyncManager.setTaskTimeout(request.getAsyncContext().getTimeout());
            }
            asyncManager.startCallableProcessing(new DispatcherServletCallable(exMv), request, response, mappedHandler.getHandler());
            return;
        }
    }
    // 同步处理请求
    ha.handle(request, response, mappedHandler.getHandler());
}

可以看到,在 doService() 方法中,当判断可以使用异步处理时,DispatcherServlet 会使用 Spring 的异步机制进行处理,其中 asyncManager.startCallableProcessing() 方法会创建一个新的线程来处理请求。这样就实现了异步处理请求,提高了系统的吞吐量和响应速度。

  • 20
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值