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程序片中的局部变量互不干扰。

时间: 2024-09-30 18:17:23

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

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

https://my.oschina.net/itblog/blog/275294 摘要: 本文通过一个例子,详细介绍Hadoop 的 MapReduce过程. 分析MapReduce执行过程 MapReduce运行的时候,会通过Mapper运行的任务读取HDFS中的数据文件,然后调用自己的方法,处理数据,最后输出.Reducer任务会接收Mapper任务输出的数据,作为自己的输入数据,调用自己的方法,最后输出到HDFS的文件中.整个流程如图: Mapper任务的执行过程详解 每个Mapper任

Hadoop学习之MapReduce执行过程详解

转自:http://my.oschina.net/itblog/blog/275294 分析MapReduce执行过程 MapReduce运行的时候,会通过Mapper运行的任务读取HDFS中的数据文件,然后调用自己的方法,处理数据,最后输出.Reducer任务会接收Mapper任务输出的数据,作为自己的输入数据,调用自己的方法,最后输出到HDFS的文件中.整个流程如图: Mapper任务的执行过程详解 每个Mapper任务是一个java进程,它会读取HDFS中的文件,解析成很多的键值对,经过我

PHP - pcntl_fork() 执行过程详解

<?php   $pid = pcntl_fork();if ($pid == -1){    die("could not fork");}elseif($pid == 0){    echo "I'm the child  process \n";}else{    echo "I'm the parent process \n";    exit;} 要搞清楚fork的执行过程,就必须先弄清楚操作系统中"进程(process

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

问题:Java对象初始化方式主要有哪几种?分别是什么?针对上面的问题,想必大家脑海中首先浮现出的答案是构造器,没错,构造器是Java中常用的对象初始化方式. 还有一种与构造器作用非常相似的是初始化块,它可以对Java对象进行初始化操作.下面主要阐述Java的初始化块及执行过程. Java初始化块其实是Java类的成员之一,其语法格式如下: [修饰符]{ //初始化块的可执行代码 ... } 初始化块的修饰符只能是static,使用static修饰符的初始化块称为静态初始化块,后面会介绍到. 下面

SQL语句执行过程详解

一.SQL语句执行原理: 第一步:客户端把语句发给服务器端执行 当我们在客户端执行select语句时, 客户端会把这条SQL语句发送给服务器端,让服务器端的进程来处理这语句.也就是说,Oracle客户端是不会做任何的操作,它的主要任务就是把客户端产生的一些SQL语句发送给服务器端.虽然在客户端也有一个数据库进程,但是,这个进程的作用跟服务器上的进程作用不同.服务器上的数据库进程才会对SQL语句进行相关的处理.不过,有个问题需要说明,就是客户端的进程跟服务器的进程是一 一对应的.也就是说,在客户端

linux命令执行过程详解

1.执行命令输入命令后回车提请shell程序找到键入命令所对应的可执行程序或者代码,并且由其分期后,提交给内核分配资源将其运行起来.在shell中可执行的命令有俩类:内部命令:由shell自带的内部集成命令help 可以查看内部命令列表 [[email protected] ~]# help GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu) These shell commands are defined internal

加密 解密过程详解及openssl自建CA &nbsp;

            加密 解密过程详解及openssl自建CA 为了数据信息能够安全的传输要求数据要有一定的安全性那么数据的安全性包含哪些方面的特性呢?    NIST(美国信息安全署)做了如下的定义:    保密性:       1,数据的保密性 指的是数据或隐私不向非授权者泄漏                   2,隐私性  信息不被随意的收集    完整性:       1,数据的的完整性:信息或程序只能被指定或授权的方式改变不能被随意的             修改        

Oracle执行计划详解

 简介: 本文全面详细介绍oracle执行计划的相关的概念,访问数据的存取方法,表之间的连接等内容. 并有总结和概述,便于理解与记忆! +++ 目录 --- 一.相关的概念 Rowid的概念 Recursive Sql概念 Predicate(谓词) DRiving Table(驱动表) Probed Table(被探查表) 组合索引(concatenated index) 可选择性(selectivity) 二.oracle访问数据的存取方法 1) 全表扫描(Full Table Scan

SVN中基于Maven的Web项目更新到本地过程详解

环境 MyEclipse:10.7 Maven:3.1.1 概述 最近在做项目的时候,MyEclipse下载SVN上面基于Maven的Web项目总是出现很多问题,有时候搞了很半天,Maven项目还是出现叉号,最后总结了方法步骤,终于可以将出现的问题解决,在此,将重现从SVN上将基于Maven的Web项目变成本地MyEclipse中项目的过程,问题也在其中进行解决. 问题补充 在使用Myeclipse的部署Web项目的时候,在点击部署按钮的时候,没有任何反应,在此提供两种解决方法,问题如图1所示: