复习JSP的概念

JSP是Java Server Page的缩写,在传统的HTML页面中加入JSP标签和java的程序片段就构成了JSP。

JSP的基本语法:两种注释类型、三个脚本元素、三个元素指令、八个动作指令。

JSP的内置对象常用的有:Request、Response、Out、Session、cookie、Application等。

JSP中的局部变量和全局变量

在JSP基本语法博文中有个小例子counter.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head></head>
<body>
<%!int count = 0;
synchronized void setCount() {
count++;
};
%>
<h2>
欢迎阅读本文
<h2>
<br> 本文阅读次数:
<% setCount();
out.println(count);
%>
<br>
i=0,计算i++=
<%
int i = 0;
out.println(i++);
%> </body>
</html>

这个例子的目的是为了区分在<%! %>和<%%>中定义的变量:

<%! %>内的变量和方法是一个类内的变量和方法也就是页面的成员变量和成员方法,每当一个用户访问此页面,count会加一。

<% %>内的变量是一个方法的变量也就是局部变量,无论访问页面多少次,i++的值总是0。

我们看到两种变量的不同,但是并没理解为什么会造成这样的不同。下面就详细讲解。

JSP执行过程图解

第一次请求:

当服务器上的一个JSP页面被第一次请求执行时,服务器上的JSP引擎首先将JSP页面文件转译成一个.java文件,也就是servlet,并编译这个java文件生成.class的字节码文件,然后执行字节码文件响应客户端的请求。

再次请求:

JSP引擎将直接执行字节码文件来响应客户。

由JSP转译的servlet

我们可以查看由JSP转译成的servelt,由此来加深多JSP的理解。存放JSP转译成的servlt的目录如下:

apache-tomcat-7.0.59\work\Catalina\localhost\yourwebapp\org\apache\jsp 

这些servlet的名字都是以_jsp.java结尾。下面是counter_jsp.java的具体内容:

/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/7.0.59
* Generated at: 2015-08-07 05:13:13 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp; import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import java.util.*; public final class counter_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent { int count = 0;
synchronized void setCount() {
count++;
}; private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory(); private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants; private javax.el.ExpressionFactory _el_expressionfactory;
private org.apache.tomcat.InstanceManager _jsp_instancemanager; public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
} public void _jspInit() {
_el_expressionfactory = _jspxFactory.getJspApplicationContext
(getServletConfig().getServletContext()).getExpressionFactory();
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory
.getInstanceManager(getServletConfig());
} public void _jspDestroy() {
} public void _jspService(final javax.servlet.http.HttpServletRequest request,
final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException { final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null; try {
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out; out.write("\r\n");
out.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\r\n");
out.write("<html>\r\n");
out.write("<head></head>\r\n");
out.write("<body>\r\n");
out.write("\t");
out.write("\r\n");
out.write("\t<h2>\r\n");
out.write("\t\t欢迎阅读本文\r\n");
out.write("\t\t<h2>\r\n");
out.write("\t\t\t<br> 本文阅读次数:\r\n");
out.write("\t\t\t");
setCount();
out.println(count); out.write("\r\n");
out.write("\t\t\t<br>\r\n");
out.write("\t\t\ti=0,计算i++=\r\n");
out.write("\t\t\t"); int i = 0;
out.println(i++); out.write("\r\n");
out.write("\t\t\r\n");
out.write("</body>\r\n");
out.write("</html>\r\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}

也许你回疑问,counter_jsp.java并没有继承HttpServlet,为什么称它们为servlet?请注意下面

public final class counter_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent

在apache-tomcat-7.0.59\java\org\apache\jasper\runtime目录下存HttpJspBase这个类的源代码文件,

public abstract class HttpJspBase extends HttpServlet
implements HttpJspPage{...}

因为下面的关系,所以这些_jsp.java文件都是servlet。

HttpServlet
继承者 HttpJspBase
继承者 counter_jsp

回到counter_jsp.java中,我们可以应用记事本的查找功能,找到我们在JSP页面定义的变量。可以看到:

<%! %>中定义的变量和方法是类的成员变量和成员方法,是全局变量。

<% %>中定义的变量是_jspService(){}方法中的局部变量。

JSP的内部方法

_jspInit(){}:jsp Page被初始化的时候调用该方法,并且该方法仅在初始化时执行一次,所以可以在这里进行一些初始化的参数配置等一次性工作,由作者创建

_jspDestroy(){}:jsp Page由于某种原因被关闭的时候调用该方法,由作者创建

_jspService(){}:由jsp容器自动创建的处理jsp Page的方法,由jsp容器创建,不能由作者定义。

当jsp文件第一次被处理时,他会被转化成一个servlet文件。然后再创建一个 Servlet对象,首先执行_jspInit()方法进行初始化操作,由于整个执行过程_jspInit()方法只执行一次,所以可以在这个方法中进行一些必要的操作比如连接数据库,初始化部分参数等等,接着执行_jspService()方法,对客户端的请求进行处理,对每一个请求会创建一个线程,如果同时有多个请求需要处理的话就会创建多个线程。由于servlet长期贮存与内存中,所以执行速度快,但是由于初始化需要编译,所以第一次执行还是比较慢的,如果由于某种原因导致jsp网页关闭或者销毁的话会执行jspDestroy()方法。

JSP的多线程思考

当多个用户请求一个JSP页面时,Tomcat服务器为每个客户启动一个线程,该线程负责执行常住内存的字节码文件来响应客户的请求。这些线程有Tomcat服务器来管理。

这些线程共享JSP页面的成员变量(实例变量),因此任何一个用户对JSP页面成员变量的操作,都会影响到其他用户,这可能导致线程的不安全。为了保证线程安全,我们不要使用(实例变量+类变量),就这么简单。也可以使用synchronized同步方法,但是这样效率不高。

方法中的局部变量是不会影响线程安全的,因为他们是在栈上分配空间,而且每个线程都有自己私有的栈空间,运行在不同线程中的java程序片中的局部变量互不干扰。

JSP执行过程详解的更多相关文章

  1. Hadoop MapReduce执行过程详解(带hadoop例子)

    https://my.oschina.net/itblog/blog/275294 摘要: 本文通过一个例子,详细介绍Hadoop 的 MapReduce过程. 分析MapReduce执行过程 Map ...

  2. ping命令执行过程详解

    [TOC] ping命令执行过程详解 机器A ping 机器B 同一网段 ping通知系统建立一个固定格式的ICMP请求数据包 ICMP协议打包这个数据包和机器B的IP地址转交给IP协议层(一组后台运 ...

  3. Hadoop学习之Mapreduce执行过程详解

    一.MapReduce执行过程 MapReduce运行时,首先通过Map读取HDFS中的数据,然后经过拆分,将每个文件中的每行数据分拆成键值对,最后输出作为Reduce的输入,大体执行流程如下图所示: ...

  4. mysql中SQL执行过程详解与用于预处理语句的SQL语法

    mysql中SQL执行过程详解 客户端发送一条查询给服务器: 服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果.否则进入下一阶段. 服务器段进行SQL解析.预处理,在优化器生成对应的 ...

  5. MySQL 语句执行过程详解

    MySQL 原理篇 MySQL 索引机制 MySQL 体系结构及存储引擎 MySQL 语句执行过程详解 MySQL 执行计划详解 MySQL InnoDB 缓冲池 MySQL InnoDB 事务 My ...

  6. IIS 内部运行机制及Asp.Net执行过程详解

    一直以来对一个Asp.net页面穿过IIS后就返回给浏览器一个HTML页面感觉很是神奇.虽然做技术这么长时间了,也曾经大致了解过一点来龙去脉,但是如果你真的问起我比较详细的过程,我还真的回答不上来,好 ...

  7. PHP - pcntl_fork() 执行过程详解

    <?php   $pid = pcntl_fork();if ($pid == -1){    die("could not fork");}elseif($pid == 0 ...

  8. Java的初始化块及执行过程详解

    问题:Java对象初始化方式主要有哪几种?分别是什么?针对上面的问题,想必大家脑海中首先浮现出的答案是构造器,没错,构造器是Java中常用的对象初始化方式. 还有一种与构造器作用非常相似的是初始化块, ...

  9. [转]MySQL查询语句执行过程详解

    Mysql查询语句执行原理 数据库查询语句如何执行?语法分析:首先进行语法分析,对使用sql表示的查询进行语法分析,生成查询语法分析树.语义检查:检查sql中所涉及的对象以及是否在数据库中存在,用户是 ...

随机推荐

  1. c读写文件相关

    1.打开文件: 函数原型: FILE * fopen(const char * path,const char * mode); 返回值: 文件顺利打开后,指向该流的文件指针就会被返回.如果文件打开失 ...

  2. 面试后 follow up letter 分享

    分享一下最近面试外企的follow up letter. Dear Mr. Xu,     Thank you again for the time you and Mr. Guo spent wit ...

  3. js登录页面的 回车事件

    js登录页面的 回车事件 js登录页面的 回车事件(2012-12-26 10:37:03)转载▼标签: jseventkey回车事件登录 分类: js.jquery  //回车事件 第一种docum ...

  4. PHP数据学习-二维数组【3】

    <?php // $project = array( // array("bai",12,23.0), // array("zeng",34,12.0), ...

  5. PHP常用函数和常量

    PHP常用系统常量 __FILE__ 文件的完整路径和文件名.如果用在被包含文件中,则返回被包含的文件名.自 PHP 4.0.2 起,总是包含一个绝对路径(如果是符号连接,则是解析后的绝对路径),而在 ...

  6. MYSQL死锁

    转载时请以超链接形式标明文章原始出处和作者信息及本声明http://www.blogbus.com/ri0day-logs/59186177.html mysql使用myisam的时候锁表比较多,尤其 ...

  7. python学习的一些感悟

    首先声明,这里用到的库是在coursera上学习时,老师建立的一个库 #timer import simplegui import random # global state message = &q ...

  8. [BZOJ 2007] [Noi2010] 海拔 【平面图最小割(对偶图最短路)】

    题目链接:BZOJ - 2007 题目分析 首先,左上角的高度是 0 ,右下角的高度是 1.那么所有点的高度一定要在 0 与 1 之间.然而选取 [0, 1] 的任何一个实数,都可以用整数 0 或 1 ...

  9. Journey of Android for Mac

    下了决心要学Java,几个同事都建议我去学Android,自己觉得能做点应用放手机上玩玩也比较有动力. 沈逸有篇文章里面写道: 搞C的看不起搞C++的. 搞C++的看不起搞java的. 搞java的看 ...

  10. Unity3D 3D横版跑酷 跳跃

    Unity3d 跑酷动画的控制 首先给个图吧, 我们跑酷里面需要动画的,今天说一下动画的知识! 1.导入骨骼动画模型文件之后,如果使用之前版本的unity的播放动画的方式,需要设置AnimationT ...