复习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. Linux下su与su -命令的区别

    在启动服务器ntpd服务时遇到一个问题 使用 su root 切换到root用户后,不可以使用service命令: 使用 su - 后,就可以使用service命令了. 原因: su命令和su -命令 ...

  2. alsa utils工具使用

    1.amixer用于控制设置 amixer [-c card] [cmd] ./amixer contents ./amixer cset ./amixer cget 2. aplay ./aplay ...

  3. grunt live

    { "name": "grunt-live-test", "version": "0.1.0", "autho ...

  4. Jquery 获取日期date()对象

    获取JavaScript 的时间使用内置的Date函数完成 var mydate = new Date(); mydate.getYear(); //获取当前年份(2位) mydate.getFull ...

  5. Fatal error: Class 'ZipArchive' not found的解决办法

    今天在Linux底下编写导出EXCEL文件并显示输出时,抛出“ZipArchive library is not enabled” 的异常.而我在本地的windows下的代码则是运行正常的. 原因是: ...

  6. html5 实现手机端相册浏览功能

    原文地址:http://www.cootm.com/?p=710 在网上找到个浏览图片的jq插件,针对手机做的非常不错,看到乐享的微信微站新开发的功能就是这个,特此分享下! 时间匆忙,没做代码分析,勿 ...

  7. Flask-SQLALchemy查询

    from: http://blog.sina.com.cn/s/blog_633277f90100kpvm.html 似乎ORM最难设计的部分是查询.特别是面向对象的查询,今天学习SQLAlchemy ...

  8. 七天学会 SALT STACK 自动化运维 (1)

    七天学会 SALT STACK 自动化运维 (1) 简单理解 SALTSTACK 安装与配置 基本的使用方法 结束语 引用资源 简单理解 SALT STACK 笔者是初次接触 自动化运维 这一技术领域 ...

  9. 研究不定数量参数的函数并实现一个printf函数

    一.前提知识 1.如何传递参数(主函数) a.函数的参数是通过栈传递,而且是从右到左依次入栈 b.即使是char型变量,在传递参数时,也是占用两个字节,因为push操作是两个字节为单位的. c.sho ...

  10. PHP与MYSQL配合完成IP的存取

    如何存储IP 程序设计要在功能实现的基础上最大限度的优化性能.而数据库设计是程序设计中不可忽略的重要部分,巧存IP地址可以一定程度提升性能. 利用函数算法处理 MySQL没有直接提供IP类型字段,但有 ...