`

容器如何处理JSP——原理及执行流程详解

阅读更多

1、当客户第一次访问Jsp页面时,容器主要按以下流程处理JSP文件。大体流程如下图所示。
   

                                                       图1 JSP总体执行流程图

 

2、执行原理及流程

 

    假设:容器=具体的Jsp引擎(Tomcat中的JSP引擎就是一个Servlet程序,它负责解释和执行JSP页面

 

    1)客户通过浏览器向服务器端的JSP页面发送请求。

 

    2)容器接受到客户请求后,会检查JSP文件对应编译后的Servlet文件(.class)是否存在。如果不存在,则跳转到第4)步,否则执行下一步。

 

    3)容器检查JSP页面是否有更新(修改),没有更新,则跳转到第5)步,否则执行下一步。

 

    4)容器将JSP文件转换为Servlet类源文件(.java)。(此步会检查和捕获JSP语法错误)

 

    5)容器将Servlet源文件(.java)编译成相应的字节码(.class)文件。(会检查和捕获Java语法错误)

 

    6)容器将字节码(.class)文件加载到内存。

 

    7)容器实例化Servlet(调用构造函数),然后调用初始化方法(jspInit())初始化Servlet。到此为止,Servlet对象真正成为一个Servlet,准备就绪,可以处理客户的请求了。

 

    8)容器创建一个新的线程来运行Servlet并运行Servlet的_jspService()方法处理客户的请求。

 

    9)Servlet生成并向客户返回一个响应(或把请求转发给另一个Web应用组件处理)。

 

3、流程补充说明

 

    1)按照容器处理Jsp的流程,通常可以大体分为两个时期:转译时期(Translate Time)和请求时期(Request Time)。

 

        a)转译时期:将Jsp文件转换成Servlet类 。

        b)请求时期:使用Servlet处理请求并把响应返回客户端。

 

    而转译时期具体包含转换和编译工作

        a)转换:将JSP文件转换为Servlet类源文件(.java)。(此步会检查和捕获JSP语法错误)

        b)编译:将Servlet源文件(.java)编译成字节码(.class)文件。(会检查和捕获Java语法错误)

 

    2) 容器在转译时期的转换工作主要包括哪些呢?

 

        a)容器(Jsp引擎)查看Jsp指令(page、include及taglib),得到转换时可能需要的信息。

        b)容器创建一个HttpServlet子类。生成的Servlet一般继承org.apache.jasper.runtime.HttpJspBase。

        c)如果page指令带有import属性,则容器会在类文件的pagekage语句下面插入import语句。在Tomcat5中,pagekage语句为:package org.apache.jsp。

        d)如果有声明(<%! %>标志的内容以及容器自己的声明),容器会将声明作为实例变量写到类文件中,通常是类声明下面,service()方法前面。

        e)容器建立_jspService()服务方法。所生成Servlet的_jspService()方法会覆盖超类的service()方法,而且通过超类的service()方法调用,由超类的service()方法传入请求和响应参数。于此同时,容器会声明并初始化Jsp中的所有隐式(内置)对象。

        f)容器将普通的Html(模板文件)、scriptlet(脚本文件)和表达式放到jsp_Service()方法中,并最终写到PrintWriter响应输出。

 

    实例参考:一个简单的Jsp文件转换为Servlet文件

    Jsp源文件:index.jsp   

<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%@ page import="com.linwei.model.*" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>
  <head>
    <base href="<%=basePath%>">
    <title>My JSP page</title>
  </head>
  <body>
    <%! 
    	int count=0;
        public int doubleCount(){
        	return count*2;
        }
    %>
    The page count is now:<%=++count %>
    <br>
    doubleCount:<%= doubleCount()%>
    <br>
    <%  
        String localVar = "World";
    	Person p=new Person();
        p.setName("Hello");
    %>
    person.name:<%=p.getName() %>
    <br>
    localVar:<%=localVar %>
    <br>
    Today is:<%= new Date()%>
  </body>
</html>

   

   编译后形成的Servlet文件:index_jsp.java

package org.apache.jsp;   //容器生成的package语句

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import java.util.*;
import com.linwei.model.*; //自定义导入的包

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

  //Jsp中定义的全局变量=Servlet类的实例变量
  int count=0;

  //Jsp中定义的方法=Servlet类的方法
  public int doubleCount(){
	return count*2;
  }
    
  private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();

  private static java.util.List _jspx_dependants;

  private javax.el.ExpressionFactory _el_expressionfactory;
  private org.apache.AnnotationProcessor _jsp_annotationprocessor;

  public Object getDependants() {
    return _jspx_dependants;
  }
  
  //初始化方法
  public void _jspInit() {
    _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
    _jsp_annotationprocessor = (org.apache.AnnotationProcessor) getServletConfig().getServletContext().getAttribute(org.apache.AnnotationProcessor.class.getName());
  }
  
  //销毁方法
  public void _jspDestroy() {
  }
  
  //服务方法
  public void _jspService(HttpServletRequest request, HttpServletResponse response)
        throws java.io.IOException, ServletException {
    
   //以下是容器生成的一系列Jsp隐式(内置)对象
    PageContext pageContext = null;
    HttpSession session = null;
    ServletContext application = null;
    ServletConfig config = null;
    JspWriter out = null;
    Object page = this;
    JspWriter _jspx_out = null;
    PageContext _jspx_page_context = null;

    try {
	  //设置响应内容类型
      response.setContentType("text/html;charset=ISO-8859-1");
	  //实例化各种隐式(内置)对象
      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;
	  
      //普通的Html模板文件
       out.write("\r\n");
      out.write("\r\n");
      
      //scriptlet脚本代码(Java语句)
       String path = request.getContextPath();
      String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

      out.write("\r\n");
      out.write("<html>\r\n");
      out.write("  <head>\r\n");
      //表达式
       out.write("    <base href=\""); 
      out.print(basePath);
      out.write("\">\r\n");
      out.write("    <title>My JSP page</title>\r\n");
      out.write("  </head>\r\n");
      out.write("  <body>\r\n");
      out.write("    ");
      out.write("\r\n");
      out.write("    The page count is now:");
      //实例变量
       out.print(++count ); 
      out.write("\r\n");
      out.write("    <br>\r\n");
      out.write("    doubleCount:");
      //调用方法
       out.print( doubleCount());
      out.write("\r\n");
      out.write("    <br>\r\n");
      out.write("    ");
      
      //局部变量
       String localVar = "World"; 
      Person p=new Person();
      p.setName("Hello");
    
      out.write("\r\n");
      out.write("    person.name:");
      out.print(p.getName() );
      out.write("\r\n");
      out.write("    <br>\r\n");
      out.write("    localVar:");
      out.print(localVar );
      out.write("\r\n");
      out.write("    <br>\r\n");
      out.write("    Today is:");
      out.print( new Date());
      out.write("\r\n");
      out.write("  </body>\r\n");
      out.write("</html>\r\n");
    } catch (Throwable t) {
      if (!(t instanceof SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try { out.clearBuffer(); } catch (java.io.IOException e) {}
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}

   

    3)容器转译(转换和编译)Jsp的工作只发生一次,即容器第一次收到客户的Jsp请求时。Jsp转译后就成为一个“Servlet”对象(初始化前还只是一个普通的Java对象)了。一旦Servlet得到加载和初始化,当有新的请求到达时,容器要做的就是创建或分配一个线程来运行service()方法并处理请求,然后返回响应。

 

  • 大小: 53.9 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics