衆所周知,每個JSP頁面都會被Web容器編譯成一個Java類,供web容器調用,而且生成HTML葉面回饋給用戶。而瞭解其中的變異方法和規則,對咱們學習JSP是很是有好處的,能夠說學習好了這個編譯原理,就已經學習好了大部分的JSP知識,剩下的工做就只剩下熟記一些tablib和反覆應用以使本身更加熟練而已了。。
先來看一下JSP頁面所對應的Class的基本結構。每個JSP頁面都會被編譯成成以下的格式樣子,先給一個大體的印象,詳細的說明在後面。
- public class My$jsp extends HttpJspBase {
-
- static {}
-
- public date$jsp() {}
-
- private static boolean _jspx_inited = false;
-
- public final void _jspx_init()
- throws org.apache.jasper.runtime.JspException {};
-
- public void _JSP pageservice(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;
- String _value = null;
- try {
- if (_jspx_inited == false) {
- synchronized (this) {
- if (_jspx_inited == false) {
- _jspx_init();
- _jspx_inited = true;
- }
- }
- }
- _jspxFactory = JspFactory.getDefaultFactory();
- response.setContentType("text/html;charset=ISO-8859-1");
- pageContext = _jspxFactory.getPageContext(this, request, response,
- "", true, 8192, true);
-
-
- application = pageContext.getServletContext();
- config = pageContext.getServletConfig();
- session = pageContext.getSession();
- out = pageContext.getOut();
-
-
- out.write("<html>\r\n<head>\r\n<title>Date</title>\r\n" +
- "</head>\r\n<body>\r\n<h3>\r\n" +
- "The date is\r\n");
-
-
- out.println((new java.util.Date()).toString());
-
-
- out.write("\r\n </h3>\r\n </body>\r\n</html>");
-
-
- } catch (Throwable t) {
- if (out != null && out.getBufferSize() != 0) {
- out.clearBuffer();
- }
- if (pageContext != null) {
- pageContext.handlePageException(t);
- }
- } finally {
- if (_jspxFactory != null) {
- _jspxFactory.releasePageContext(pageContext);
- }
- }
- }
- }
public class My$jsp extends HttpJspBase {
static {}
public date$jsp() {}
private static boolean _jspx_inited = false;
public final void _jspx_init()
throws org.apache.jasper.runtime.JspException {};
public void _JSP pageservice(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;
String _value = null;
try {
if (_jspx_inited == false) {
synchronized (this) {
if (_jspx_inited == false) {
_jspx_init();
_jspx_inited = true;
}
}
}
_jspxFactory = JspFactory.getDefaultFactory();
response.setContentType("text/html;charset=ISO-8859-1");
pageContext = _jspxFactory.getPageContext(this, request, response,
"", true, 8192, true);
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
// HTML // begin [file="/date.jsp";from=(0,0);to=(7,6)]
out.write("<html>\r\n<head>\r\n<title>Date</title>\r\n" +
"</head>\r\n<body>\r\n<h3>\r\n" +
"The date is\r\n");
// end
// begin [file="/date.jsp";from=(7,8);to=(7,57)]
out.println((new java.util.Date()).toString());
// end
// HTML // begin [file="/date.jsp";from=(7,59);to=(10,7)]
out.write("\r\n </h3>\r\n </body>\r\n</html>");
// end
} catch (Throwable t) {
if (out != null && out.getBufferSize() != 0) {
out.clearBuffer();
}
if (pageContext != null) {
pageContext.handlePageException(t);
}
} finally {
if (_jspxFactory != null) {
_jspxFactory.releasePageContext(pageContext);
}
}
}
}
咱們能夠清楚地看到,這裏面最重要的函數就是pageservice,web容器在編譯好一個JSP類之後,就申請這個類的對象,而且直接調用pageservice來得到Response,最後返回給客戶。做爲細節,咱們能夠總結以下: 1. 全部的JSP頁面翻譯出來的class,都從HttpJspBase繼承,而且命名爲PageName$jsp 2. 在第一次調用pageservice函數的時候,該class會進行一次初始化,而這個初始化函數是_jspx_init,若是咱們想,咱們還能夠自定義這個函數,來實現JSP頁面的初始化。 3. <% %> 這樣的代碼被轉換成什麼了? 這樣的代碼被直接轉成Java代碼放到pageservice函數裏面。 4. <%! %> 這樣的代碼被轉換成什麼了? 這樣的代碼被翻譯成成員函數和成員變量,也就是說,這些聲明在JSP的生命週期內都是存在的。 5. HTML代碼呢? html代碼直接被寫到PrintWriter裏面回饋給用戶。很是的直接 6. 爲何JSP頁面有那麼多省寫方式,好比說session , out , page , context之類。 這都是在pageservice裏面定義的臨時變量,具體的初始化能夠參看上面的例子代碼,每一次調用JSP頁面,這些變量都會被從新初始化一次。固然咱們也能夠方便的聲明本身的變量。 7. 省寫方式<%= object.doSomething()%> 這麼理解? 這種省寫方式調用doSomething所獲得的Object的toString(),而後直接寫到out裏面。至關於: out.print(object.doSomethiing().toString()) 8. JavaBean 裏面的scope定義了做用域範圍,這個範圍在這裏的意思是? 這是Bean對象句柄保存的地方的意思。咱們能夠想象一下,一個page範圍的Bean只是pageservice裏面的一個局部變量,當一次處理結束後,這個變量就會被Java虛擬機回收。而session變量。而request級別的Bean就應該是JSP頁面的成員變量。而session和application則不能在JSP頁面class裏面保存,而應該保存在JSP頁面的調用對象裏面。 9. 關於<%@ page %>命令,這個就太簡單了,只是一個一個的對應爲response.setContentType()的語句而已。 10. 關於JSP頁面轉向問題。這個語句被翻譯爲getServletContext().getRequestDispatcher("/List.jsp").forward(req, res);語句。 11. <%@ include file="included.jsp" %> 遇到這個語句,JSP翻譯器就會把這個文件的代碼和如今文件的代碼混合而後一塊兒編譯,生成JSP類。這個方法很好,可讓咱們統一文檔的樣式,好比說吧 header寫成一個文件,,而把footer也寫成一個JSP ,而且在index.html裏面把這兩個文件包含近來,這樣,無論Content怎麼變,上下樣式都不會變,有利於樣式的統一。 以上是JSP翻譯過程的簡單探討,更加詳細的細節能夠參考tomcat的源代碼,瞭解這些原理對於學習JSP來講,是很是重要的,能大大的提升學習的效率。