Servlet学习笔记(一)之Servlet原理、初始化、生命周期、结构体系

Servlet是用java语言编写的应用到Web服务器端的扩展技术,与java对象的区别是,Servlet对象主要封装了对HTTP请求的处理,并且它的运行需要Servlet容器的支持(以下会介绍原因,也可以看之前的一篇介绍Servlet容器的博客,(http://blog.csdn.net/megustas_jjc/article/details/52923132)),在JavaWeb中,Servlet主要用于处理各种业务逻辑,并且还可以输出HTML代码来显示指定页面。
Servlet 用来 动态web资源 开发:
静态web资源 : 固定数据文件
动态web资源 : 通过程序动态生成数据文件

Servlet技术基于Request-Response编程模型 ,HTTP协议也是基于请求响应 模型 ,新航道托福因此 Servlet技术 用来 开发基于HTTP web 应用程序 。

接触 JavaEE API ------ 程序 接口 和 已经实现接口 类的 使用 (JavaEE ---- Java Platform, Enterprise Edition 缩写 )

建立一个简单servlet的步骤:
1、创建web project
2、编写 class 继承 HttpServlet
3、在web.xml 配置 Servlet程序 虚拟访问路径 (用户在浏览器上通过这个路径 访问编写Servlet程序 )
4、覆盖doGet或者doPost方法 进行输出
其中,Servlet程序在编写和运行时,需要javaee 类库 (API支持),例如在学习javase List 需要 import java.util.List 需要 jre/lib/rt.jar,对于eclipse需要自行导入jar包,先要找到文件所在的路径,如下。
C:Tomcat 5.0commonlibservlet-api.jar。 然后在eclipse里面 Project ->Properties,在左边找到Java Builder Path,单击,在右边找到Libraries,然后Add External Jars,找到C:Tomcat 5.0commonlibservlet-api.jar。完毕,接着可以使用 import javax.servlet.*

Servlet运行原理分析
编写Servlet程序没有 main函数(意味着不能独立执行,需要tomcat) ---- tomcat调用Servlet程序执行

这里写图片描述

1、用户在客户端发起url请求 : http://localhost/day05/hello 。
2、web.xml /hello 映射 HelloServlet程序。
3、用户提交请求时,get方式提交执行HelloServlet的doGet方法,post方式提交执行 HelloServlet的doPost 方法 。

手动编写Servlet运行(servlet在运行时需要依赖外界的jar包)
手动编写Servlet运行(servlet在运行时需要依赖外界的jar包)
1、在webapps 新建 day05test目录 — 虚拟应用
2、在day05test 新建 WEB-INF/classes
3、将编写Servlet的java源码文件 放入 classes ,在 WEB-INF 配置web.xml (进行虚拟路径配置)
4、编译Servlet的 java程序
javac -classpath E:apache-tomcat-6.0.14libservlet-api.jar HelloServlet.java // 通过 -classpath 指定 Servlet需要jar 包
生成Servlet package结构
javac -d . -classpath E:apache-tomcat-6.0.14libservlet-api.jar HelloServlet.java

Servlet生命周期与初始化

(1)Servlet生命周期
(2)init(ServletConfig config) 初始化
(3)service(ServletRequest req, ServletResponse res) 提供服务方法
(4)destroy() 销毁


原理:
1、tomcat服务器启动时,没有创建Servlet对象
2、第一次访问时,tomcat构造Servlet对象,调用 init,执行service
3、从第二次以后访问 tomcat 不会从新创建Servlet对象,也不会调用init ---- 每一次访问都会调用service
4、当服务器重启或正常关闭时 调用destroy (正常关闭 shutdown.bat)

这里写图片描述

servlet生命周期小结:

  • 针对客户端多次Servlet请求,通常情况下**,服务器只会创建一个Servlet实例对象**,雅思初级也就是说Servlet实例对象一旦创建,它就会驻留在内存中,为后续的其他请求服务,直至web容器退出,servlet实例对象才会销毁。
  • 在整个Servlet生命周期内,Servlet的init方法只被调用一次。而对一个Servlet的每次访问请求导致Servlet引擎调用一次servlet的service方法,对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service方法再根据请求方式分别调用doXXX方法。

因此,Servlet对象是tomcat创建的,每次请求调用Servlet中service方法,tomcat服务器会在每次调用Servlet的service方法时,为该方法创建Request对象和Response对象(在 JavaEE API 中没有Request和Response实现类(HttpServlet是包装类,因此不能产生Servlet对象) ----- 实现类由Servlet服务器提供的,tomcat提供实现类 weblogic 提供实现类 ) 。

service方法 和 HttpServlet doGet/doPost 关系区别
在HttpServlet代码实现中,根据请求方式不同 调用相应doXXX方法 get方式请求 — doGet post方式 — doPost (必须阅读HttpServlet源代码 )

其中可以通过对Servlet进行配置,使其启动时进行初始化,而不是之前的调用时进行初始化,其实现可以通过< load-on-startup>(< load-on-startup > 参数可以是一个数字 0-9 代表服务器加载优先级 0 最高 ,例如:在tomcat启动时,想通过Servlet加载一些框架配置文件 配置随服务器启动 )


Servlet结构体系
这里写图片描述

GenericServlet和HttpServlet都是Servlet接口的两个默认实现类,GenericServlet对Servlet接口及ServletConfig接口提供了部分实现,但是并没有对Http请求处理进行实现,这一操作由其子类HttpServlet进行实现,其为Http请求中的POST、GET等类型提供了具体的操作方法,所以通常情况下,编写的Servlet对象都是继承与HttpServlet。因此,编写Servlet 不需要覆盖service方法,只需要覆盖doGet和doPost 方法;Servlet初始化时覆盖init() ,无需覆盖init(config),因为init(Config) 调用了init()。并且,当doGet方法与doPost方法逻辑相同时,可以互相调用,简化编程,例如:


一般Servlet只初始化一次(只有一个实例)。对于更多的客户端请求,Server创建新的请求和响应对象,仍然激活此Servlet的service()方法,将这两个对象作为参数传递给该方法。如此重复以上的循环,但无需再调用init()方法(Web容器收到请求后,Web容器会产生一个新的线程来调用Servlet的service(),service()方法检查HTTP请求类型(GET、POST、PUT、DELETE等),雅思辅导班然后相应调用doGet()、doPost()、doPut()、doDelete()等方法,即用多个线程去执行各个请求)。

原因:

出于性能的考虑:特别的对于门户网站而言,每一个Servlet在每一秒内的并发访问量都可以是成千上万的。在一个面向模块化开发的现在,常常一个点击操作就被定义为一个Servlet的实现,而如果Servlet的每一次被访问,都创建一个新的实例的话,服务器的可用资源消耗量将是一个相当重要的问题。
退一步,一般Servlet的访问是很快的,每一个实例被快速的创建,又被快速的回收,GC的回收速度也跟不上,频繁的内存操作也将可能带来次生的问题。

所以,Servlet的“单一实例化”是一个很重要的策略。

问题描述:
写一个Servlet对象,使用不同的浏览器浏览时,刷新,会出现数据安全问题。由于servlet对象只有一个,其中的属性很容易称为servlet方法执行的临界资源,尽可能不要在Servlet中定义成员变量
解决方法:
在servlet中添加同步代码块


最近在复习web相关的内容,将遇到的问题通过网上一些文章和参考用书进行了一个整理,整理为如下内容:
首先我们先来看如下的一个例子,现在假设有两个jsp页面,jsp1与jsp2:

jsp1页面

jsp2页面:

会发现无法显示test,因为在jsp2页面中找不到test,那么原因是什么呢?

其实那就要从request的生命周期或者是说作用范围说起了,setAttribute()用来在同一个request周期中保存变量使用。

比如servlet调用后,引出JSP页面,这是一个request周期。如果在Jsp页面需要servlet中的一些 处理结构,就从request.getAttribute中获取。
而sendRedirect()方法是通过浏览器重定向的,所以第二个JSP页面中获得的request并非是前一个页面的request(两次请求生成了前后两个不同的 request对象了)。而此时使用RequestDispatcher接口的forward()方法则能够得到request中的对象了,这是因为后者并不是使用客户端浏览器进行重定向的,从函数的名字就可以看出,RequestDispatcher.forward()就是从服务器端进行任务转发。

sendRedirect()是请求从定向,和超连接是一个意思,比如你在A页面中写一个request.setAtribute,sendRedirect到B页面,就是说服务器从A页面中给你一个response,然后你的浏览器再去request到B页面,由于有两次request和response,是不能在B页面取到request.setAtribute里的值,能从地址栏看到url的改变。

request.getRequestDispatcher().forward(request,response)是请求分发器,比如你在A页面中写一个request.setAtribute,request.getRequestDispatcher().forward(request,response)到B页面,那就是说服务器给你的response是B页面的,并且只有一次request和response,所以是能在B页面取到request.setAtribute里的值,地址栏的url仍然是A页面的。

所以通常情况下,setAttribute()方法都和RequestDispatcher.forward()都在一起使用,具体用法示例:

request.setAttribute()和request.getAttribute()配对使用,作用域是请求和被请求页面之间。雅思机经request.setAttribute()是只在此action的下一个forward需要使用的时候使用;request.getAttribute()表示从request范围取得设置的属性,必须要先setAttribute设置属性,才能通过getAttribute来取得,设置与取得的为Object对象类型。其实表单控件中的Object的 name与value是存放在一个哈希表中的,所以在这里给出Object的name会到哈希表中找出对应它的value。setAttribute()的参数是String和Object。

sendRedirect不能传递request对象。使用request.setAttribute时不能使redirect而是forward。即是将请求转发而不是重定向。

request.getParameter()表示接收参数,参数为页面提交的参数。包括:表单提交的参数、URL重写(就是xxx?id=1中的id)传的参数等,因此这个并没有设置参数的方法(没有setParameter()),而且接收参数返回的不是Object,而是String类型。

(1)request.getParameter()取得是通过容器的实现来取得通过类似post,get等方式传入的数据,request.setAttribute()和getAttribute()只是在web容器内部流转,仅仅是请求处理阶段
(2)request.getParameter()方法传递的数据,会从Web客户端传到Web服务器端,代表HTTP请求数据。request.getParameter()方法返回String类型的数据。
request.setAttribute()和getAttribute()方法传递的数据只会存在于Web容器内部
还有一点就是,HttpServletRequest类有setAttribute()方法,而没有setParameter()方法。
拿一个例子来说一下吧,假如两个WEB页面间为链接关系时,就是说要从1.jsp链接到2.jsp时,出国留学中介被链接的是2.jsp可以通过getParameter()方法来获得请求参数.

假如1.jsp里有

请输入用户姓名:

的话在2.jsp中通过request.getParameter(“username”)方法来获得请求参数username:
<% String username=request.getParameter(“username”); %>


但是如果两个WEB间为转发关系时,转发目的WEB可以用getAttribute()方法来和转发源WEB共享request范围内的数据,也还是说一个例子吧。
有1.jsp和2.jsp
1.jsp希望向2.jsp传递当前的用户名字,如何传递这一数据呢?先在1.jsp中调用如下setAttribute()方法:

在2.jsp中通过getAttribute()方法获得用户名字:
<% String username=(String)request.getAttribute(“username”); %>

不同页面间传值使用request.setAttribute(position, nameOfObj)时,只会从a.jsp到b.jsp一次传递,之后这个request 就会失去它的作用范围,再传就要再设一个 request.setAttribute()。而使用session.setAttribute()会在一个过程中始终保有这个值。
session.setAttribute()和session.getAttribute()配对使用,作用域是整个会话期间,在所有的页面都使用这些数据的时候使用。详细的session相关内容可以参考http://blog.csdn.net/megustas_jjc/article/details/53443012。

原文地址:https://www.cnblogs.com/zhangyanran/p/10082076.html