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来做,这样职责单一,容易维护也正符合我们软件设计中的分层与单一职责等思想。

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

 

原文地址:https://www.cnblogs.com/askDing/p/5108712.html