您的位置:首页 > Web前端 > JavaScript

JSP实现原理

2016-01-07 09:31 543 查看
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引擎去处理。

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

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

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

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

具体代码示例:

jsp页面:

[html] view plaincopyprint?

<html>

<head>

<title> HelloWorld </title>

</head>

<body>

<%

out.println("HelloWorld");

%>

</body>

</html>

在tomcat的conf文件中的web.xml中

[html] view plaincopyprint?

<servlet>

<servlet-name>jsp</servlet-name>

<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>

<init-param>

<param-name>fork</param-name>

<param-value>false</param-value>

</init-param>

<init-param>

<param-name>xpoweredBy</param-name>

<param-value>false</param-value>

</init-param>

<load-on-startup>3</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>jsp</servlet-name>

<url-pattern>*.jsp</url-pattern>

</servlet-mapping>

<servlet-mapping>

<servlet-name>jsp</servlet-name>

<url-pattern>*.jspx</url-pattern>

</servlet-mapping>

tomcat源码中JSPServlet类的实现。

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

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

[java] view plaincopyprint?

public void service (HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException {

String jspUri = null;

String jspFile = (String) request.getAttribute(Constants.JSP_FILE);

if (jspFile != null) {

// JSP is specified via <jsp-file> in <servlet> declaration

jspUri = jspFile;

} else {

/*

* Check to see if the requested JSP has been the target of a

* RequestDispatcher.include()

*/

jspUri = (String) request.getAttribute(Constants.INC_SERVLET_PATH);

if (jspUri != null) {

/*

* Requested JSP has been target of

* RequestDispatcher.include(). Its path is assembled from the

* relevant javax.servlet.include.* request attributes

*/

String pathInfo = (String) request.getAttribute(

"javax.servlet.include.path_info");

if (pathInfo != null) {

jspUri += pathInfo;

}

} else {

/*

* Requested JSP has not been the target of a

* RequestDispatcher.include(). Reconstruct its path from the

* request's getServletPath() and getPathInfo()

*/

jspUri = request.getServletPath();

String pathInfo = request.getPathInfo();

if (pathInfo != null) {

jspUri += pathInfo;

}

}

}

if (log.isDebugEnabled()) {

log.debug("JspEngine --> " + jspUri);

log.debug("\t ServletPath: " + request.getServletPath());

log.debug("\t PathInfo: " + request.getPathInfo());

log.debug("\t RealPath: " + context.getRealPath(jspUri));

log.debug("\t RequestURI: " + request.getRequestURI());

log.debug("\t QueryString: " + request.getQueryString());

}

try {

boolean precompile = preCompile(request);

serviceJspFile(request, response, jspUri, null, precompile);

} catch (RuntimeException e) {

throw e;

} catch (ServletException e) {

throw e;

} catch (IOException e) {

throw e;

} catch (Throwable e) {

throw new ServletException(e);

}

}

生成的servlet类--HelloWorld_jsp.java

[java] view plaincopyprint?

package org.apache.jsp;

import javax.servlet.*;

import javax.servlet.http.*;

import javax.servlet.jsp.*;

public final class HelloWorld_jsp extends org.apache.jasper.runtime.HttpJspBase

implements org.apache.jasper.runtime.JspSourceDependent {

private static java.util.List _jspx_dependants;

public Object getDependants() {

return _jspx_dependants;

}

public void _jspService(HttpServletRequest request, HttpServletResponse response)

throws java.io.IOException, ServletException {

JspFactory _jspxFactory = null;

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 {

_jspxFactory = JspFactory.getDefaultFactory();

response.setContentType("text/html");

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("<html>\r\n");

out.write("\t<head>\r\n");

out.write("\t\t<title>HelloWorld</title>\r\n");

out.write("\t</head>\r\n");

out.write("\t<body>\r\n");

out.write("\t\t");

out.println("HelloWorld");

out.write("\r\n");

out.write("\t</body>\r\n");

out.write("</html>");

} catch (Throwable t) {

if (!(t instanceof SkipPageException)){

out = _jspx_out;

if (out != null && out.getBufferSize() != 0)

out.clearBuffer();

if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);

}

} finally {

if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context);

}

}

}

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

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

[java] view plaincopyprint?

package org.apache.jasper.runtime;

import java.io.IOException;

import javax.servlet.ServletConfig;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.jsp.HttpJspPage;

import javax.servlet.jsp.JspFactory;

import org.apache.jasper.compiler.Localizer;

/**

* This is the super class of all JSP-generated servlets.

*

* @author Anil K. Vijendran

*/

public abstract class HttpJspBase

extends HttpServlet

implements HttpJspPage

{

protected HttpJspBase() {

}

public final void init(ServletConfig config)

throws ServletException

{

super.init(config);

jspInit();

_jspInit();

}

public String getServletInfo() {

return Localizer.getMessage("jsp.engine.info");

}

public final void destroy() {

jspDestroy();

_jspDestroy();

}

/**

* Entry point into service.

*/

public final void service(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException

{

_jspService(request, response);

}

public void jspInit() {

}

public void _jspInit() {

}

public void jspDestroy() {

}

protected void _jspDestroy() {

}

public abstract void _jspService(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException;

}

如果:

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

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

总结:

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

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

其实我们学习的各类技术以及各种设计模式,它们的出现或形成都是软件设计思想的一种体现!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: