zoukankan      html  css  js  c++  java
  • JSP实现原理

    JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术。

     

    起源:

    在很多动态网页中,绝大部分内容都是固定不变的,只有局部内容需要动态产生和改变。如果使用Servlet程序来输出只有局部内容需要动态改变的网页,其中所有的静态内容也需要程序员用Java程序代码产生,整个Servlet程序的代码将非常臃肿,编写和维护都将非常困难。

    解决方案:

    为了弥补Servlet的缺陷,SUN公司在Servlet的基础上推出了JSP(Java Server Pages)技术作为解决方案。JSP是简化Servlet编写的一种技术,它将Java代码和HTML语句混合在同一个文件中编写,只对网页中的要动态产生的内容采用Java代码来编写,而对固定不变的静态内容采用普通静态HTML页面的方式编写

    Html相比:

    html只能为用户提供静态数据,而Jsp技术允许在页面中嵌套java代码,为用户提供动态数据。

    与Servlet相比:

    servlet很难对数据进行排版,而jsp除了可以用java代码产生动态数据的同时,也很容易对数据进行排版,避免了servlet中编写大量的拼接HTML代码。

    思考:JSP为什么可以像Servlet一样,也可以叫做动态web资源的开发技术?

    解释:其实Jsp就是一个Servlet。下面是对这句话的具体解释!

    JSP的调用过程原理图:

     

          

    执行流程简介:

    1,当WEB容器(Servlet引擎)接收到以.jsp为扩展名的URL的访问请求时,它将把该访问请求交给JSP引擎去处理。

    2Tomcat中的JSP引擎就是一个Servlet程序,它负责解释和执行JSP页面。

    3,当我们第一次访问Jsp的时候,Jsp引擎都会将这个Jsp翻译成一个Servlet,这个文件存放在Tomcat中的work目录中

    4接着再把这个Servlet源程序编译成Servlet的class类文件

    5然后再由WEB容器(Servlet引擎)像调用普通Servlet程序一样的方式来装载和解释执行这个由JSP页面翻译成的Servlet程序。

    具体代码示例:

    jsp页面:

    1. <html>  
    2.     <head>  
    3.         <title> HelloWorld </title>  
    4.     </head>  
    5.     <body>  
    6.         <%  
    7.             out.println("HelloWorld");  
    8.         %>  
    9.     </body>  
    10. </html>  

    tomcatconf文件中的web.xml

     

    1. <servlet>  
    2.         <servlet-name>jsp</servlet-name>  
    3.         <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>  
    4.         <init-param>  
    5.             <param-name>fork</param-name>  
    6.             <param-value>false</param-value>  
    7.         </init-param>  
    8.         <init-param>  
    9.             <param-name>xpoweredBy</param-name>  
    10.             <param-value>false</param-value>  
    11.         </init-param>  
    12.         <load-on-startup>3</load-on-startup>  
    13.     </servlet>  
    14.   
    15.  <servlet-mapping>  
    16.         <servlet-name>jsp</servlet-name>  
    17.         <url-pattern>*.jsp</url-pattern>  
    18.  </servlet-mapping>  
    19.   
    20.  <servlet-mapping>  
    21.         <servlet-name>jsp</servlet-name>  
    22.         <url-pattern>*.jspx</url-pattern>  
    23.  </servlet-mapping>  

    tomcat源码中JSPServlet类的实现。

    这个类主要也是继承HttpServlet。重写了HttpServlet的service方法。

    如果jsp第一次使用,要将它编译成servlet。编译好后将生成我们相关的文件即HelloWorld_jsp.java

    1. public void service (HttpServletRequest request,   
    2.              HttpServletResponse response)  
    3.                throws ServletException, IOException {  
    4.   
    5.        String jspUri = null;  
    6.   
    7.        String jspFile = (String) request.getAttribute(Constants.JSP_FILE);  
    8.        if (jspFile != null) {  
    9.            // JSP is specified via <jsp-file> in <servlet> declaration  
    10.            jspUri = jspFile;  
    11.        } else {  
    12.            /* 
    13.             * Check to see if the requested JSP has been the target of a 
    14.             * RequestDispatcher.include() 
    15.             */  
    16.            jspUri = (String) request.getAttribute(Constants.INC_SERVLET_PATH);  
    17.            if (jspUri != null) {  
    18.                /* 
    19.      * Requested JSP has been target of 
    20.                 * RequestDispatcher.include(). Its path is assembled from the 
    21.                 * relevant javax.servlet.include.* request attributes 
    22.                 */  
    23.                String pathInfo = (String) request.getAttribute(  
    24.                                    "javax.servlet.include.path_info");  
    25.                if (pathInfo != null) {  
    26.                    jspUri += pathInfo;  
    27.                }  
    28.            } else {  
    29.                /* 
    30.                 * Requested JSP has not been the target of a  
    31.                 * RequestDispatcher.include(). Reconstruct its path from the 
    32.                 * request's getServletPath() and getPathInfo() 
    33.                 */  
    34.                jspUri = request.getServletPath();  
    35.                String pathInfo = request.getPathInfo();  
    36.                if (pathInfo != null) {  
    37.                    jspUri += pathInfo;  
    38.                }  
    39.            }  
    40.        }  
    41.   
    42.        if (log.isDebugEnabled()) {        
    43.            log.debug("JspEngine --> " + jspUri);  
    44.            log.debug("      ServletPath: " + request.getServletPath());  
    45.            log.debug("         PathInfo: " + request.getPathInfo());  
    46.            log.debug("         RealPath: " + context.getRealPath(jspUri));  
    47.            log.debug("       RequestURI: " + request.getRequestURI());  
    48.            log.debug("      QueryString: " + request.getQueryString());  
    49.        }  
    50.   
    51.        try {  
    52.            boolean precompile = preCompile(request);  
    53.            serviceJspFile(request, response, jspUri, null, precompile);  
    54.        } catch (RuntimeException e) {  
    55.            throw e;  
    56.        } catch (ServletException e) {  
    57.            throw e;  
    58.        } catch (IOException e) {  
    59.            throw e;  
    60.        } catch (Throwable e) {  
    61.            throw new ServletException(e);  
    62.        }  
    63.   
    64.    }  

    生成的servlet--HelloWorld_jsp.java

     

    1. package org.apache.jsp;  
    2.   
    3. import javax.servlet.*;  
    4. import javax.servlet.http.*;  
    5. import javax.servlet.jsp.*;  
    6.   
    7. public final class HelloWorld_jsp extends org.apache.jasper.runtime.HttpJspBase  
    8.     implements org.apache.jasper.runtime.JspSourceDependent {  
    9.   
    10.   private static java.util.List _jspx_dependants;  
    11.   
    12.   public Object getDependants() {  
    13.     return _jspx_dependants;  
    14.   }  
    15.   
    16.   public void _jspService(HttpServletRequest request, HttpServletResponse response)  
    17.         throws java.io.IOException, ServletException {  
    18.   
    19.     JspFactory _jspxFactory = null;  
    20.     PageContext pageContext = null;  
    21.     HttpSession session = null;  
    22.     ServletContext application = null;  
    23.     ServletConfig config = null;  
    24.     JspWriter out = null;  
    25.     Object page = this;  
    26.     JspWriter _jspx_out = null;  
    27.     PageContext _jspx_page_context = null;  
    28.   
    29.   
    30.     try {  
    31.       _jspxFactory = JspFactory.getDefaultFactory();  
    32.       response.setContentType("text/html");  
    33.       pageContext = _jspxFactory.getPageContext(this, request, response,  
    34.                 null, true, 8192, true);  
    35.       _jspx_page_context = pageContext;  
    36.       application = pageContext.getServletContext();  
    37.       config = pageContext.getServletConfig();  
    38.       session = pageContext.getSession();  
    39.       out = pageContext.getOut();  
    40.       _jspx_out = out;  
    41.   
    42.       out.write("<html> ");  
    43.       out.write(" <head> ");  
    44.       out.write(" <title>HelloWorld</title> ");  
    45.       out.write(" </head> ");  
    46.       out.write(" <body> ");  
    47.       out.write(" ");  
    48.  out.println("HelloWorld");  
    49.       out.write(" ");  
    50.       out.write(" </body> ");  
    51.       out.write("</html>");  
    52.     } catch (Throwable t) {  
    53.       if (!(t instanceof SkipPageException)){  
    54.         out = _jspx_out;  
    55.         if (out != null && out.getBufferSize() != 0)  
    56.           out.clearBuffer();  
    57.         if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);  
    58.       }  
    59.     } finally {  
    60.       if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context);  
    61.     }  
    62.   }  
    63. }  

    我们看到,这个类继承了org.apache.jasper.runtime.HttpJspBase,具体HttpJspBase类的tomcat的源码如下:

    根据时序图,首先调用service方法,然后service方法内部调用_jspService抽象方法,此方法并没有实现,故继承它的HelloWorld_jsp.java类实现。

    1. package org.apache.jasper.runtime;  
    2.   
    3. import java.io.IOException;  
    4.   
    5. import javax.servlet.ServletConfig;  
    6. import javax.servlet.ServletException;  
    7. import javax.servlet.http.HttpServlet;  
    8. import javax.servlet.http.HttpServletRequest;  
    9. import javax.servlet.http.HttpServletResponse;  
    10. import javax.servlet.jsp.HttpJspPage;  
    11. import javax.servlet.jsp.JspFactory;  
    12.   
    13. import org.apache.jasper.compiler.Localizer;  
    14.   
    15. /** 
    16.  * This is the super class of all JSP-generated servlets. 
    17.  * 
    18.  * @author Anil K. Vijendran 
    19.  */  
    20. public abstract class HttpJspBase   
    21.     extends HttpServlet   
    22.     implements HttpJspPage   
    23.           
    24.       
    25. {  
    26.       
    27.     protected HttpJspBase() {  
    28.     }  
    29.   
    30.     public final void init(ServletConfig config)   
    31.     throws ServletException   
    32.     {  
    33.         super.init(config);  
    34.     jspInit();  
    35.         _jspInit();  
    36.     }  
    37.       
    38.     public String getServletInfo() {  
    39.     return Localizer.getMessage("jsp.engine.info");  
    40.     }  
    41.   
    42.     public final void destroy() {  
    43.     jspDestroy();  
    44.     _jspDestroy();  
    45.     }  
    46.   
    47.     /** 
    48.      * Entry point into service. 
    49.      */  
    50.     public final void service(HttpServletRequest request, HttpServletResponse response)   
    51.     throws ServletException, IOException   
    52.     {  
    53.         _jspService(request, response);  
    54.     }  
    55.       
    56.     public void jspInit() {  
    57.     }  
    58.   
    59.     public void _jspInit() {  
    60.     }  
    61.   
    62.     public void jspDestroy() {  
    63.     }  
    64.   
    65.     protected void _jspDestroy() {  
    66.     }  
    67.   
    68.     public abstract void _jspService(HttpServletRequest request,   
    69.                      HttpServletResponse response)   
    70.     throws ServletException, IOException;  
    71. }  

    如果:

    让jsp既用java代码产生动态数据,又做美化会导致jsp的职责过重且页面难以维护。

    让servlet既产生数据,又在里面嵌套html代码美化数据,同样也会导致程序可读性差,难以维护。

    总结:

       不管是JSP还是Servlet,都可以用于开发动态web资源(学习的共同点)。但由于这2门技术各自的特点,在长期的软件实践中,人们逐渐把servlet作为web应用中的控制器组件来使用,而把JSP技术作为数据显示模板来使用(不同点,也可以说发挥各自优势!其中,JSP对于程序员来说省去了在后台手动拼接html代码的过程)。

       因此最好的办法就是根据这两门技术的特点,让它们各自负责各的,servlet只负责响应请求产生数据,并把数据通过转发技术带给jsp,数据的显示jsp来做,这样职责单一,容易维护也正符合我们软件设计中的分层与单一职责等思想。

       其实我们学习的各类技术以及各种设计模式,它们的出现形成都是软件设计思想的一种体现!

     

  • 相关阅读:
    Qt ini文件
    Qt我的文档 桌面路径
    windows zlib库编译步骤
    环形缓冲区
    openssl生成随机数
    怎样安装Scrapy
    CentOS7怎样安装GoAccess1.3
    Docker创建数据卷容器
    Docker创建数据卷
    Docker创建容器
  • 原文地址:https://www.cnblogs.com/askDing/p/5108712.html
Copyright © 2011-2022 走看看