JSP执行过程详解
复习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执行过程详解的更多相关文章
- Hadoop MapReduce执行过程详解(带hadoop例子)
https://my.oschina.net/itblog/blog/275294 摘要: 本文通过一个例子,详细介绍Hadoop 的 MapReduce过程. 分析MapReduce执行过程 Map ...
- ping命令执行过程详解
[TOC] ping命令执行过程详解 机器A ping 机器B 同一网段 ping通知系统建立一个固定格式的ICMP请求数据包 ICMP协议打包这个数据包和机器B的IP地址转交给IP协议层(一组后台运 ...
- Hadoop学习之Mapreduce执行过程详解
一.MapReduce执行过程 MapReduce运行时,首先通过Map读取HDFS中的数据,然后经过拆分,将每个文件中的每行数据分拆成键值对,最后输出作为Reduce的输入,大体执行流程如下图所示: ...
- mysql中SQL执行过程详解与用于预处理语句的SQL语法
mysql中SQL执行过程详解 客户端发送一条查询给服务器: 服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果.否则进入下一阶段. 服务器段进行SQL解析.预处理,在优化器生成对应的 ...
- MySQL 语句执行过程详解
MySQL 原理篇 MySQL 索引机制 MySQL 体系结构及存储引擎 MySQL 语句执行过程详解 MySQL 执行计划详解 MySQL InnoDB 缓冲池 MySQL InnoDB 事务 My ...
- IIS 内部运行机制及Asp.Net执行过程详解
一直以来对一个Asp.net页面穿过IIS后就返回给浏览器一个HTML页面感觉很是神奇.虽然做技术这么长时间了,也曾经大致了解过一点来龙去脉,但是如果你真的问起我比较详细的过程,我还真的回答不上来,好 ...
- PHP - pcntl_fork() 执行过程详解
<?php $pid = pcntl_fork();if ($pid == -1){ die("could not fork");}elseif($pid == 0 ...
- Java的初始化块及执行过程详解
问题:Java对象初始化方式主要有哪几种?分别是什么?针对上面的问题,想必大家脑海中首先浮现出的答案是构造器,没错,构造器是Java中常用的对象初始化方式. 还有一种与构造器作用非常相似的是初始化块, ...
- [转]MySQL查询语句执行过程详解
Mysql查询语句执行原理 数据库查询语句如何执行?语法分析:首先进行语法分析,对使用sql表示的查询进行语法分析,生成查询语法分析树.语义检查:检查sql中所涉及的对象以及是否在数据库中存在,用户是 ...
随机推荐
- 判断奇数,java陷阱
/** 判断是否为奇数 @author husky / public class IsOdd { public static void main(String[] args) { int demo1 ...
- Vijos1865 NOI2014 魔法森林 LCT维护生成树
基本思路: 首先按照weightA升序排序,然后依次在图中加边,并维护起点到终点路径上weightB的最大值 如果加边过程中生成了环,则删除环中weightB最大的边 由于是无向图,点之间没有拓扑序, ...
- How far away ?
#include<iostream> #include <algorithm> using namespace std; const int M=40010; int dis[ ...
- HTML5的Server-Sent Events (SSE)
HTML5有一个Server-Sent Events(SSE)功能,允许服务端推送数据到客户端.(通常叫数据推送).我们来看下,传统的WEB应用程序通信时的简单时序图: 现在Web App中,大都有A ...
- yii2源码学习笔记(三)
组件(component),是Yii框架的基类,实现了属性.事件.行为三类功能,如果需要事件和行为的功能,需要继承该类. yii\base\Component代码详解 <?php /** * @ ...
- DEDECMS栏目自定义字段添加
用到的文件: catalog_add.htm 路径:\dede\templets\ catalog_edit.htm 路径:\dede\templets\ catalog_add.php 路径 ...
- Java多线程:常用的实现多线程的两种方式
之所以说是常用的,是因为通过还可以通过java.util.concurrent包中的线程池来实现多线程.关于线程池的内容,我们以后会详细介绍;现在,先对的Thread和Runnable进行了解.本章内 ...
- 关于移动手机端富文本编辑器qeditor图片上传改造
日前项目需要在移动端增加富文本编辑,上网找了下,大多数都是针对pc版的,不太兼容手机,当然由于手机屏幕小等原因也限制富文本编辑器的众多强大功能,所以要找的编辑器功能必须是精简的. 找了好久,发现qed ...
- LINUX HA:Pacemaker + Corosync初配成功
参考很多文档: http://zhumeng8337797.blog.163.com/blog/static/100768914201218115650522/ 下一步,想想这个PC组和与HAPROX ...
- JavaScript encodeURI() 函数
encodeURI() 函数可把字符串作为 URI 进行编码. -------------------------------------------------------------------- ...