JavaにリファクタリングしたJSTLロジックがいくつかあります。当時、パフォーマンスについては考慮していませんでしたが、Javaの方が高速であると想定していました。この仮定は正しいですか?
Javaforループにリファクタリングされた各ステートメントに含まれるJSTLコード。私は、JSTLコードをコンパイルする前に最初にJavaに変換する必要があるという私の仮定に基づいています。
JavaにリファクタリングしたJSTLロジックがいくつかあります。当時、パフォーマンスについては考慮していませんでしたが、Javaの方が高速であると想定していました。この仮定は正しいですか?
Javaforループにリファクタリングされた各ステートメントに含まれるJSTLコード。私は、JSTLコードをコンパイルする前に最初にJavaに変換する必要があるという私の仮定に基づいています。
あなたの仮定は(ほとんど)間違っていました。サーブレットコンテナ(Tomcatなど)は、すべてのjspページをJavaサーブレットにコンパイルし、次にjavaバイトコードにコンパイルします。これは最終的にjspページが要求されたときに実行されるものです。したがって、jspページはとにかくJavaコードに透過的に変換されます。jstlカスタムタグlib実装ロジックとJavaコードの間にパフォーマンスの違いがあるかもしれませんが、これはJavaとjstlではなく、特定の実装によるものです。
Tomcatのデフォルト構成では、jspリソースに最初にアクセスするまで、jspコンパイルは実行されないため、jspページの最初の要求(のみ)に対して起動時のペナルティが発生します。その最初のヒットが心配な場合は、プリコンパイルされるようにjspページを構成できます。ほとんどのユースケースで問題を起こす価値はありません。
JSTLはJavaバイトコードにコンパイルする必要があると思うので、同じであると思います。Javaで直接コードを記述した場合は、おそらくパフォーマンスが向上することが期待できますが、コンパイラーは、おそらく、思ったよりも最適化を行うのに優れています。
本当に心配な場合は、プロファイラーを実行して結果を比較します。
JSTLコードをJavaソースコードに変換してからコンパイルする必要があるだけでなく(ランタイムパフォーマンスには影響しません)、タグインスタンスの作成とリクエスト属性(ローカル変数)へのアクセスのためにわずかなオーバーヘッドがありますプレーンJavaループ内)。このコストの大部分は、エスケープ分析などのコンパイラの最適化によって隠されたり、ネットワーク遅延などの他の「コスト」と比較して十分に小さいと思いますが、とにかくコストがかかります。
好奇心から、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;
}
Javaスクリプトレットは純粋なJavaコードであり、JSPがサーブレットクラスに変換されるときに解析を必要としないため、JSTLコードよりも高速になります。それでも、ここで説明されているスクリプトレットの使用は避けてください。
プレゼンテーション層のテクノロジとしてJSPの代わりにFaceletsを使用する場合は、スクリプトレットを使用する必要はまったくありません。
私見ですが、JSTL(およびその他のタグ)を解析するための100または200ミリ秒のオーバーヘッドがアプリケーションに大きな影響を与えるとは思えません。
for
は言語構造であり<c:foreach>
、単なるfor
ループにコンパイルされないため、オーバーヘッドが発生します。JSTLタグは他のタグと同じように、コンテナによって実行され、コンテナはライフサイクルメソッドとコールバックメソッドを呼び出します。コンテナ(TomcatやWebLogicなど)で生成されたJSPのソースコードを見ると、単純なタグを使用すると多くのオーバーヘッドが発生することがわかります。
しかし、このオーバーヘッドは、データアクセス、ネットワーク、および...の遅延に匹敵するものではないと思います。したがって、このわずかな遅延を無視し、JSTLとタグを使用して、JSPをより読みやすく保守しやすくします。
ちなみに、JSTL(または他のタグライブラリ)を使用する場合、通常はJSP ELも使用するため、 ELの評価には少しオーバーヘッドがあります。ただし、これらのオーバーヘッドは、データアクセス、ネットワーク遅延、および...と比較してカウントされません。