同样是include,前者是一个指令,directive,后者是一个动作,action。
所有的指令,包括page, include都是在translation phase完成的。
而后者相法于RequestDispatcher.include()方法。
测试include directive
其中include_directive_test.jsp的内容如下:- 1 <% out.println("before including"); %>
- 2 <%@ include file="include_directive_including.inc" %>
- 3 <% out.println("after including"); %>
复制代码 而include_directive_including.inc的内容如下:- 1 <% out.println("including file content"); %>
复制代码 预编译后的java文件内容如下:- 57
- 58 out.println("before including");
- 59 out.write('\n');
- 60 out.println("including file content");
- 61 out.write('\n');
- 62 out.write('\n');
- 63 out.println("after including");
- 64 out.write('\n');
复制代码 显然,转换器把整个including文件嵌入主文件之中,形成一个translation unit。
理解这个translation unit的概念很重要,因为在JSP/Servlet语法中,有不少东西是以translation unit
为单位进行约束的。比如page的所有属性中,除了import外,其他属性最多只能出现 1 次。
可能还有同学注意到,这个预编译的.java文件还有几行很特别的内容:- 12 private static java.util.List _jspx_dependants;
- 13
- 14 static {
- 15 _jspx_dependants = new java.util.ArrayList(1);
- 16 _jspx_dependants.add("/include_directive_including.inc");
- 17 }
复制代码 这个让servlet container在每次执行更新检查的时候,需要注意把including文件一并进行
检查。
换成<jsp:include />看看
如果换成<jsp:include page="xxx" />的话,得到的结果是这样的:- org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "include_directive_including.inc", out, false);
复制代码 而更深入的了解需要看JspRuntimeLibrary.java的代码。相关部分代码如下:- 948 public static void include(ServletRequest request,
- 949 ServletResponse response,
- 950 String relativePath,
- 951 JspWriter out,
- 952 boolean flush)
- 953 throws IOException, ServletException {
- 954
- 955 if (flush && !(out instanceof BodyContent))
- 956 out.flush();
- 957
- 965 String resourcePath = getContextRelativePath(request, relativePath);
- 966 RequestDispatcher rd = request.getRequestDispatcher(resourcePath);
- 967
- 968 rd.include(request,
- 969 new ServletResponseWrapperInclude(response, out));
- 970
- 971 }
复制代码 一句rd.include()就把这司马昭之心暴露无遗了。 |