我将一些JSTL逻辑重构为Java。我当时没有考虑性能,只是假设Java会更快。这个假设是否正确?
包含在每个语句中的JSTL代码,这些语句被重构为Java for循环。我的假设是在编译之前必须首先将JSTL代码转换为Java。
答案 0 :(得分:2)
你的假设(大多数)是不正确的。您的servlet容器(例如Tomcat)将所有jsp页面编译为java servlet,然后编译为java字节码,这最终是在请求jsp页面时运行的。所以jsp页面无论如何都会透明地转换为java代码。 jstl自定义标记lib实现逻辑和您的Java代码之间可能存在性能差异,但这可能是由于特定的实现,而不是java与jstl。
在Tomcat的默认配置下,jsp编译直到第一次访问jsp资源时才会发生,因此对于jsp页面的第一个请求(仅限)会有启动惩罚。如果您担心第一次点击,可以配置jsp页面以进行预编译。大多数用例都不值得。
答案 1 :(得分:1)
我认为JSTL应该编译成Java字节码,所以我希望它们是相同的。如果直接用Java编写代码,你可能会期望更好的性能,但编译器在优化方面可能比你想象的更好。
如果您真的担心,我会运行profiler并比较结果。
答案 2 :(得分:1)
不仅必须将JSTL代码转换为java源代码然后进行编译(这不会影响运行时性能),而且由于创建了Tag个实例并且访问了请求属性(普通Java循环中的局部变量)。我认为大部分成本可以通过编译器优化来隐藏,例如escape analysis,和/或与其他“成本”(如网络延迟)相比足够小,但无论如何它都会收费。 / p>
出于好奇,我查看了Tomcat 6编译的JSP。这是从简单的c:forEach标签生成的源代码......
private boolean _jspx_meth_c_005fforEach_005f0(PageContext _jspx_page_context)
throws Throwable {
PageContext pageContext = _jspx_page_context;
JspWriter out = _jspx_page_context.getOut();
// c:forEach
org.apache.taglibs.standard.tag.el.core.ForEachTag _jspx_th_c_005fforEach_005f0 = (org.apache.taglibs.standard.tag.el.core.ForEachTag) _005fjspx_005ftagPool_005fc_005fforEach_0026_005fvar_005fitems.get(org.apache.taglibs.standard.tag.el.core.ForEachTag.class);
_jspx_th_c_005fforEach_005f0.setPageContext(_jspx_page_context);
_jspx_th_c_005fforEach_005f0.setParent(null);
_jspx_th_c_005fforEach_005f0.setVar("session");
_jspx_th_c_005fforEach_005f0.setItems("${session_info}");
int[] _jspx_push_body_count_c_005fforEach_005f0 = new int[] { 0 };
try {
int _jspx_eval_c_005fforEach_005f0 = _jspx_th_c_005fforEach_005f0.doStartTag();
if (_jspx_eval_c_005fforEach_005f0 != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {
do {
out.write(" \r\n");
out.write(" <TR>\r\n");
out.write(" <TD>"); //etc...
if (_jspx_meth_c_005fout_005f0(_jspx_th_c_005fforEach_005f0, _jspx_page_context, _jspx_push_body_count_c_005fforEach_005f0))
return true;
out.write("\r\n");
out.write(" <TD>");
if (_jspx_meth_c_005fif_005f0(_jspx_th_c_005fforEach_005f0, _jspx_page_context, _jspx_push_body_count_c_005fforEach_005f0))
return true;
int evalDoAfterBody = _jspx_th_c_005fforEach_005f0.doAfterBody();
if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)
break;
} while (true);
}
if (_jspx_th_c_005fforEach_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
} catch (Throwable _jspx_exception) {
while (_jspx_push_body_count_c_005fforEach_005f0[0]-- > 0)
out = _jspx_page_context.popBody();
_jspx_th_c_005fforEach_005f0.doCatch(_jspx_exception);
} finally {
_jspx_th_c_005fforEach_005f0.doFinally();
_005fjspx_005ftagPool_005fc_005fforEach_0026_005fvar_005fitems.reuse(_jspx_th_c_005fforEach_005f0);
}
return false;
}
答案 3 :(得分:0)
Java scriptlet将比JSTL代码更快,因为它是纯Java代码,并且在JSP转换为Servlet类时不需要任何解析。不过,您应该避免使用scriptlet as explained here。
如果使用Facelets而不是JSP作为表示层技术,则根本不需要使用scriptlet。
恕我直言,我怀疑解析JSTL(和其他标签)的100或200毫秒的开销会对你的应用产生很大的影响。
答案 4 :(得分:0)
会有一些开销,因为for
是一种语言构造,而<c:foreach>
不会被编译为仅仅for
循环。
JSTL标记就像其他标记一样,它们由容器执行,容器将调用它们的生命周期和回调方法。
如果您在容器(例如Tomcat或WebLogic)中查看生成的JSP源代码,您会发现使用简单标记会产生大量开销。
但我认为这种开销与您的数据访问,网络和延迟无法相比。所以忽略这个小延迟,并使用JSTL和标签使JSP更具可读性和可维护性。
顺便说一下,当你使用JSTL(或其他标签库)时,你通常也会使用 JSP EL ,而 EL 的评估会有一点开销。但是,与数据访问,网络延迟和....相比,这些开销再次无法计算。