[JSP]JSP到Servlet的转换

1. JSP生命周期:

    1) JSP即JavaServer Pages的简称,即Java服务器生成页面,见名知意;

    2) JSP和Servlet是一体两面,JSP页面最终会被转换成Servlet的Java类;

    3) 在J2EE标准下,JSP的生命周期是这样的:

         xxx.jsp的源码文件   --转译-->   xxx_jsp.java的Servlet源码   --编译-->   xxx_jsp.class的类文件   --进入正式的Servlet生命周期-->   ...

    4) 只有在第一次请求JSP页面时才会发生转译、编译的过程,所以在第一次请求页面时响应会慢很多;


2. xxx.jsp到xxx_jsp.java的转译结果:

    1) 伪代码表示大致为:

public final class xxx_jsp extends HttpJspBase {
	// 略...
	
	public void _jspInit() {
		// JSP语句转译过来的代码,如果JSP代码中定义过初始化初始化方法的话
	}
	
	public void _jspDestroy() {
		// JSP语句转译过来的代码,如果JSP代码中定义过资源回收方法的话
	}
	
	public void _jspService(HttpServletRequest request, HttpServletResponse response)
		throws IOException, ServletException {
		// 以下每一个数据都对应着JSP的隐式对象,这些变量名都可以直接在JSP代码中使用,相当于一种JSP的环境变量
		// 略...
		PageContext pageContext = null;
		HttpSession session = null;
		ServletContext application = null;
		ServletConfig config = null;
		JspWriter out = null;
		// 略...
		
		// 接着是加载这些JSP隐式对象,即“JSP的换件变量”
		// 略...
		pageContext = 获取pageContext的方法;
		session = pageContext.getSession();
		application = pageContext.getServletContext();
		config = pageContext.getServletConfig();
		out = pageContext.getOut();
		// 略...
		
		try {
			// 略...
			// JSP转译过来的语句,其中包换重要的画面输出语句
			// 略...
		} catch (Throwable t) {
			// 略...
		} finally {
			// 略...
		}
	}
}

    2) 可以看到三个_jsp方法分别对应着HttpServlet的init、destroy和service方法,只不过该jsp类是直接继承自HttpJspBase类;

    3) 其次是命名规则上:如果JSP文件命名为XXX,则转译后的jsp类名称就是XXX_jsp;

         i. 看以看到类名_jsp后缀和方法名_jsp前缀相同;

         ii. 其实_jsp这个名称在J2EE中是有特殊含义的,是指一个动词,即从JSP代码转译而来;

         iii. 所以XXX_jsp就是指从XXX.jsp转译而来的"XXX"Servlet类,而_jspInit就是指从JSP代码中的初始化函数转译而来的init方法的意思;


3. HttpJspBase类:

    1) 既然JSP转译类是直接继承自HttpJspBase类,既然其中含有类init、destroy和service方法那么该类必然继承自HttpServlet类;

    2) 看一下HttpJspBase类源码的大致结构:

public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {
	// 略...

	public void jspInit() {}
	public void _jspInit() {}
	public final void init(ServletConfig config) throws ServletException {
		super.init(config);
		jspInit();
		_jspInit();
	}

	// 略...
	
	public void jspDestroy() {}
	public void _jspDestroy() {}
	public final void destroy() {
		jspDestroy();
		_jspDestroy();
	}

	public abstract void _jspService(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException;
	public final void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		_jspService(request, response);
	}
}
    3) 可以看到这是一个纯虚类,除了init(config: ServletConfig)、destroy、service三个方法是事先定义好的,基本不能改变,其余以jsp和_jsp打头的都是空的,都是留给今后要派生的类来实现的;

    4) _jsp和jsp方法:

         i. 前面讲过了,_jsp前缀的方法都是经过JSP代码转译而来的,所以在派生类xxx_jsp中这些_jsp方法的内容都是转译而来的,都是“已经存在”的;

         ii. jsp方法才是真正的空方法,在派生类中仍然是空的,这些方法是专门用来满足一些特殊需求的,只有在转译后打开xxx_jsp.java源码文件后才能添加,直接在JSP代码中无法实现这些方法;

         iii. 可以看到只有init和destroy方法提供了非转译型jsp方法,而service规定必须只能使用转译型_jsp,即服务内容直接用JSP代码实现无需再跑到转译后的Servlet代码中直接用Java语言实现了,这是J2EE的规定,因为JSP就是为了简化service的编写,所以何必要那么麻烦地继续使用Java代码呢?

         iv. 从上面的源码中可以看出,都是先调用Java非转译代码再执行JSP代码(转译型代码);

         v. 转译型代码(_jsp方法)都是由Web容器来维护的,用户不得修改,只有非转译行代码(jsp方法)用户可以修改;


你可能感兴趣的:(jsp,Servlet到JSP的转换)