问题:Web容器(例如Tomcat)是怎么来执行jsp文件的?

首先它会将放在webapps目录下的jsp文件(这里以hello.jsp为例)翻译成hello_jsp.java文件并编译为hello_jsp.class(注意:生成的文件名都是小写字母),存放在Tomcat安装目录\work\Catalina\localhost\webDemo\org\apache\jsp路径下,打开.java源文件,你会看到hello_jsp类继承了httpJspBase类。而HttpJspBase类又是HttpServlet的子类,所以hello_jsp类也就间接实现了Servlet接口,也就是说Web容器把jsp文件转换成了一个servlet类了

然后Web容器根据配置文件(web.xml)和客户端(浏览器)的请求URL来确定使用哪一个servlet类.接下来调用这个servlet类的service()方法。在hello_jsp.java中看不到这个service()方法,并不代表它没有这个方法,只代表它没有重写这个方法。(除了重写之外,从父类继承的方法在其子类中,都是隐藏的,所以你看不到。)那么如果想看看在这个类中从其父类继承得到的方法长什么样?很简单!找到有这个方法的父类,查看方法的源码即可。那么如果需要调用这个类的service()方法怎么办?放心,No problem呀,它会去寻找所有父类里有这个方法的父类,然后再执行这个父类的方法体(在这里我们把这个机制或者行为笑称为“儿子继承的东西没找到,咱不怕,去找老子”),在这里说明一下:在子类中调用继承的方法,这个方法就是子类的方法,即SubClass.method(),只不过执行的方法体内容和其父类中的方法体内容一模一样而已。那么接着咱们就来说说这个父类HttpJspBase,在它的源码中,你会看到两个方法,第一个方法_japService(),被其子类hello_jsp类重写了。另外一个方法,源码如下

public void service(HttpServletRequest quest,HttpServletResponse response) throws ServletException,IOException{
  _jspService(request,response);
}

这个父类中的servce()方法,子类hello_jsp继承得到的service方法也就是它。看到没有,多么简单的一个方法呀!上面提过了Web容器在确定使用哪一个sevlet类后,接着要干嘛?当然就是调用这个servlet的service()方法了,开始执行它的方法体,方法体中也没啥复杂的事情,就是调用本类中的_japService()方法,也就是hello_jsp类中的重写父类的_jspService()。

咱们接着看这个重写的_jspService()的方法体,里面有若干个out.write();这个方法的实参不就是jsp文件的HTML内容吗?哦,所以才有我们在浏览器上看到的输出内容。

所以在父类里定义的service()方法的作用我觉得很大:它把我们原始的继承Serlet接口并重写其service()方法的习惯转变为了继承HttpJspBase类并重写其_jspService()方法。这是一种技术上的改进和分支吧,也就造就了JSP技术的发展吧。与之类似的是HttpServlet类,它也间接实现了Servlet接口,重写了service()方法,特别是它继承了元老级的GenericServlet(这个类可是直接实现Servlet接口的第一代类呀,可谓是亲生的嫡长子呀!它提供了很多方法,可以说是一个重大改革,也为HttpServlet铺好了路,关于它以后有空再讲)。那么我们来看看Httpservlet类实现的service()方法吧

 public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException { HttpServletRequest request;
HttpServletResponse response; try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException("non-HTTP request or response");
}
service(request, response);
}

HttpServletRequest和HttpServletResponse分别是ServletRequest和ServletResponse的子类,这样经过强转型,再最后调用自己的service方法,成功完成了接口方法到基类方法的转移了呀!还没有完,接下来才是HttpServlet的高明之处:看看他自己定义的那个service()的源码吧

    protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException { String method = req.getMethod(); 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;
try {
ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
} catch (IllegalArgumentException iae) {
// Invalid date header - proceed as if none was set
ifModifiedSince = -1;
}
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
// 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);
}
} } else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp); } else if (method.equals(METHOD_POST)) {
doPost(req, resp); } else if (method.equals(METHOD_PUT)) {
doPut(req, resp); } else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp); } else {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
// String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}

比较长,言而言之,就是这些个逻辑实现,将Web容器最先调用servlet类的service()方法转移到了调用servlet类的doGet(),doPOST()等方法上,因为看不到这些底层的实现代码,所以就让我们产生了HttpServlet的入口是doGet()方法的假象。当然这也带来了简化流程的好处:继承了HttpServlet类的子类只要重写doGet (),doPOST()等方法即可。

总结:jsp实质上还是servlet,是一种加强版的servlet技术吧

JSP的小心得的更多相关文章

  1. ASP.NET MVC Autofac依赖注入的一点小心得(包含特性注入)

    前言 IOC的重要性 大家都清楚..便利也都知道..新的ASP.NET Core也大量使用了这种手法.. 一直憋着没写ASP.NET Core的文章..还是怕误导大家.. 今天这篇也不是讲Core的 ...

  2. 下列哪个为JSP的小脚本的标签?(选择1项)

    下列哪个为JSP的小脚本的标签?(选择1项) A.<% %> B.<@ %> C.<%! %> D.<%– %> 解答:A

  3. Qt使用com组件的一点小心得(使用Qt自带的工具dumpcpp生成.h和.cpp文件)

    这几天工作中要用到Qt调用com组件,主要用到的类型有dll和ocx,使用他们的方法很简单:1.将com组件注册到系统中.2.使用Qt自带的工具dumpcpp将com组件生成cpp和头文件.3.然后就 ...

  4. 拼接Sql语句小心得

    在往数据库插入数据时,需要根据数据和数据库中的列信息进行拼接,在本篇文章中,输出小心得.使用语言为 python. 拼接原始列信息 比如待插入数据库列信息为 deptNo,dName, Locate, ...

  5. BUI Webapp用于项目中的一点小心得

    接触BUI也有一段时间,也用在了移动端的项目开发中,总的来说,该框架用起来也挺灵活的,控件可以自由定制,前提是自己能认真地学习该框架的api,因为api里面说的东西比较详细,如果没有仔细看的,可能有些 ...

  6. 用java编网页的学习流程,我的一些小心得(初学java到高深运用)

    (1)java基础:首先得会写int,String,for循环,数组,**等等(熟练各种基础的关键字,各种java自带的排序,随即等等算法)什么是封装,继承,多态,然后private,public,p ...

  7. RIME-使用小心得

    从4月份我才接触到RIME输入法,当时的感觉上相见恨晚的,现在感觉也不错,时至今日,想写点东西,也算是小感触吧. RIME称为中州韵输入法引擎,是开放源代码的输入法软件,其主页是http://rime ...

  8. 简单而又复杂的jsp(小知识)

    JSP中的page标签中的pageEncoding属性和contentType属性 pageEncoding的默认值为ISO-8859-1 contentType的默认属性为:text/html; c ...

  9. Unity仪表盘显示UGUI制作小心得

    最近在做设备仪表参数参数显示,由于模型摆放位置经常修改,加之要求不能在模型的下面添加东西,显示界面的位置也不得不跟着修改,一来二去就烦了,想了解决办法,现在总结如下: 1.仍然在模型下面新建Panel ...

随机推荐

  1. Bootstrap入门(第一天)

    一直都想认真的学习一下Bootstrap,但是由于种种原因,一直没有行动,虽然期间有使用过Bootstrap,但是都没有系统的学习过.最近工作室(学校老师的工作室)安排了一个前端任务让我跟进,主要是根 ...

  2. hdu 3265 矩形剪块面积并

    http://acm.hust.edu.cn/vjudge/problem/10769 给n张海报,在每张海报上剪掉一个矩形,求面积并 把剪块的海报分成四个矩形,就是普通的求面积并问题了 #inclu ...

  3. Django组件——forms组件

    一.校验字段功能 通过注册用户这个实例来学习校验字段功能. 1.模型:models.py from django.db import models # Create your models here. ...

  4. Grunt压缩图片和JS

    今天我们来说一下用Grunt来压缩图片和JS吧! 首先要安装插件: 这是压缩图片的; npm install --save-dev gulp-imagemin 这是压缩JS的: npm install ...

  5. Eclipse中搭建Android开发环境

    一.搭建Android开发环境 准备工作:下载Eclipse.JDK.Android SDK.ADT插件 下载地址:Eclipse:http://www.eclipse.org/downloads/ ...

  6. 菜鸟学习Spring——SpringMVC注解版控制层重定向到控制层

    一.概述. SpringMVC中界面请求Contorller1,Contorller1需要重定向到Contorller2中显示其他页面或者做一些业务逻辑,Spring中提供了这个功能利用"r ...

  7. sketchup 与 ArcGIS 10 的交互(转)

    来自:http://blog.csdn.net/kikitamoon/article/details/9036347 许多用户在 ArcGIS 9.2 时代习惯于使用 Sketchup 插件,但是,9 ...

  8. solidity语言5

    结构体 pragma solidity ^0.4.11; // 众筹合约 contract CrowdFunding { // 投资者 struct Funder { address addr; ui ...

  9. ZT C++关键字new学习

    http://blog.csdn.net/waken_ma/article/details/4007914 C++关键字new学习 很多新手对C++关键字new可能不是很了解吧,今天我一起来学习一下. ...

  10. Wi-Fi

    AP就是一个无线的交换机,提供无线信号发射接收的功能 Wi-Fi是一种可以将个人电脑.手持设备(如PDA.手机)等终端以无线方式互相连接的技术 两个不一样的东西,无法比较的 你说的应该是无线路由器和无 ...