شرح تفصيلي للتخزين المؤقت للمحتوى الديناميكي ضمن JSP 2.0
الكاتب:Eve Cole
وقت التحديث:2009-07-03 16:56:34
يعد التخزين المؤقت للمحتوى أحد تقنيات التحسين الأكثر شيوعًا في تطبيقات الويب ويمكن تنفيذها بسهولة. على سبيل المثال، يمكنك استخدام علامة JSP مخصصة - دعنا نسميها <jc:cache> - مع <jc:cache> و</jc:cache> لتغليف كل جزء من الصفحة التي تحتاج إلى التخزين المؤقت. يمكن لأي علامة مخصصة التحكم في وقت تنفيذ الجزء الذي تحتوي عليه (أي جزء الصفحة المعبأ مسبقًا)، ويمكن التقاط نتائج المخرجات الديناميكية. تتيح العلامة <jc:cache> لحاوية JSP (مثل Tomcat) إنشاء محتوى مرة واحدة فقط، كمتغيرات JSP على مستوى التطبيق، لتخزين كل جزء من ذاكرة التخزين المؤقت. في كل مرة يتم فيها تنفيذ صفحة JSP، ستقوم العلامة المخصصة بتحميل جزء الصفحة المخزنة مؤقتًا دون الحاجة إلى تنفيذ كود JSP مرة أخرى لإنشاء الإخراج. كجزء من مشروع جاكرتا، تم تطوير مكتبة العلامات باستخدام هذه التكنولوجيا. إنه يعمل بشكل جيد عندما لا يلزم تخصيص المحتوى المخزن مؤقتًا لكل مستخدم أو طلب.
تعمل هذه المقالة على تحسين التقنية الموضحة أعلاه باستخدام لغة التعبير JSP 2.0 (EL)، مما يسمح لصفحات JSP بتخصيص المحتوى المخزن مؤقتًا لكل طلب ومستخدم. يمكن أن تحتوي أجزاء صفحة ذاكرة التخزين المؤقت على تعبيرات JSP لا يتم تقييمها بواسطة حاوية JSP، ويتم تحديد قيم هذه التعبيرات بواسطة علامات مخصصة في كل مرة يتم فيها تنفيذ الصفحة. لذلك، تم تحسين إنشاء المحتوى الديناميكي، ولكن الأجزاء المخزنة مؤقتًا يمكن أن تحتوي على أجزاء من المحتوى الذي تم إنشاؤه بواسطة كل طلب باستخدام لغة تعبير JSP الأصلية. بمساعدة JSP 2.0 EL API، يمكن لمطوري Java جعل ذلك ممكنًا باستخدام لغات التعبير.
التخزين المؤقت للمحتوى مقابل التخزين المؤقت للبيانات لا يعد التخزين المؤقت للمحتوى هو الخيار الوحيد. على سبيل المثال، يمكن أيضًا تخزين البيانات المستخرجة من قاعدة البيانات مؤقتًا. في الواقع، قد يكون التخزين المؤقت للبيانات أكثر كفاءة نظرًا لأن المعلومات المخزنة لا تحتوي على علامات HTML وتتطلب ذاكرة أقل. ومع ذلك، في كثير من الحالات، يكون تنفيذ التخزين المؤقت في الذاكرة أسهل. افترض أنه في حالة معينة، يتكون التطبيق من عدد كبير من كائنات المعاملات، ويحتل موارد مهمة لوحدة المعالجة المركزية، ويقوم بإنشاء بيانات معقدة، ويستخدم صفحات JSP لتقديم البيانات. كان كل شيء يسير على ما يرام حتى يوم واحد زاد الحمل على الخادم فجأة وكان هناك حاجة إلى حل طارئ. في هذا الوقت، يعد إنشاء طبقة ذاكرة تخزين مؤقت بين كائن المعاملة وطبقة العرض حلاً جيدًا وفعالاً للغاية. لكن صفحات JSP التي تخزن المحتوى الديناميكي مؤقتًا يجب تعديلها بسرعة وسلاسة كبيرة. بالنسبة إلى التحرير البسيط لصفحة JSP، تتطلب التغييرات في منطق عمل التطبيق عادةً المزيد من العمل والاختبار؛ بالإضافة إلى ذلك، إذا قامت الصفحة بتجميع المعلومات من مصادر مركبة متعددة، فإن طبقة الويب تحتاج فقط إلى قدر صغير من التغييرات. تكمن المشكلة في ضرورة تحرير مساحة ذاكرة التخزين المؤقت عندما تصبح المعلومات المخزنة مؤقتًا قديمة، ويجب أن يعرف كائن المعاملة متى يحدث ذلك. ومع ذلك، عند اختيار تنفيذ التخزين المؤقت للمحتوى أو التخزين المؤقت للبيانات أو تقنيات التحسين الأخرى، هناك العديد من العوامل التي يجب أخذها في الاعتبار، وفي بعض الأحيان تكون هناك متطلبات خاصة للبرنامج الذي يتم تطويره.
التخزين المؤقت للبيانات والتخزين المؤقت للمحتوى لا يستبعدان بالضرورة بعضهما البعض، بل يمكن استخدامهما معًا. على سبيل المثال، في تطبيق يعتمد على قاعدة البيانات، يتم تخزين البيانات المستخرجة من قاعدة البيانات وHTML الذي يقدم البيانات بشكل منفصل. يشبه هذا إلى حد ما استخدام JSP لإنشاء قوالب في الوقت الفعلي. توضح تقنيات API المستندة إلى EL والتي تمت مناقشتها في هذه المقالة كيفية استخدام JSP EL لتحميل البيانات في قوالب العرض.
تخزين المحتوى الديناميكي مؤقتًا باستخدام متغيرات JSP عندما تقوم بتنفيذ آلية تخزين مؤقت، فإنك تحتاج إلى طريقة لتخزين كائنات ذاكرة التخزين المؤقت. في هذه المقالة، يتم تضمين كائنات من النوع String. أحد الخيارات هو استخدام إطار عمل التخزين المؤقت للكائنات، أو استخدام خرائط Java لتنفيذ نظام تخزين مؤقت مخصص. يحتوي JSP بالفعل على ما يسمى "السمات المحددة النطاق" أو "متغيرات JSP" لتوفير تعيين كائن المعرف، وهو ما تتطلبه آلية التخزين المؤقت. لاستخدام نطاق الصفحة أو الطلب، لا يكون هذا منطقيًا، بينما في نطاق التطبيق يعد هذا مكانًا جيدًا لتخزين المحتوى المخزن مؤقتًا نظرًا لأنه مشترك بين جميع المستخدمين والصفحات. يمكن أيضًا استخدام نطاق الجلسة عند الحاجة إلى تخزين مؤقت منفصل لكل مستخدم، لكن هذا ليس فعالاً للغاية. يمكن استخدام مكتبة علامات JSTL مع ذلك لتخزين المحتوى مؤقتًا، وذلك باستخدام متغيرات JSP كما هو موضح في المثال التالي:
<%@ taglib prefix="c" uri=" http://java.sun.com/jsp/jstl/core " %><c:if test="${empty cachedFragment}">
<c:set var="cachedFragment" نطاق = "application">
...
</c:set></c:if>
يقوم جزء الصفحة المخزنة مؤقتًا بإخراج النتائج باستخدام العبارة التالية:
${applicationScope.cachedFragment}
ماذا يحدث عندما يلزم تخصيص جزء ذاكرة التخزين المؤقت لكل طلب؟ على سبيل المثال، إذا كنت تريد تضمين عداد، فأنت بحاجة إلى تخزين جزأين مؤقتًا:
<%@ taglib prefix="c" uri=" http://java.sun.com/jsp/jstl/core " %><c:if test="${sessionScope.counter == null}"> <c :set var="counter"scope="session" value="0"/></c:if><c:set var="counter" value="${counter+1}"scope="session"/ ><c:if test="${empty cachedFragment1}">
<c:set var="cachedFragment1" نطاق = "application">
...
</c:set></c:if><c:if test="${empty cachedFragment2}">
<c:set var = "cachedFragment2" نطاق = "التطبيق">
...
</c:set></c:if>
يمكنك استخدام العبارة التالية لإخراج محتوى ذاكرة التخزين المؤقت:
${cachedFragment1} ${counter} ${cachedFragment2}
بمساعدة مكتبة العلامات المخصصة، يصبح التخزين المؤقت لأجزاء الصفحة التي تتطلب التخصيص أمرًا سهلاً للغاية. كما ذكر أعلاه، يمكن تضمين المحتوى المخزن مؤقتًا عن طريق علامات الفتح (<jc:cache>) وعلامات الإغلاق (</jc:cache>). يمكن التعبير عن كل تخصيص باستخدام علامة أخرى (<jc:dynamic expr="..."/>) لإخراج تعبير JSP (${...}). يتم تخزين المحتوى الديناميكي مؤقتًا باستخدام تعبيرات JSP ويتم تعيينه في كل مرة يتم فيها إصدار المحتوى المخزن مؤقتًا. يمكنك أن ترى كيف يتم تحقيق ذلك في القسم أدناه. يقوم Counter.jsp بتخزين جزء من الصفحة يحتوي على عداد، وسيزيد العداد تلقائيًا بمقدار 1 في كل مرة يقوم فيها المستخدم بتحديث الصفحة.
<%@ taglib prefix="c" uri=" http://java.sun.com/jsp/jstl/core " %><%@ taglib prefix="jc" uri=" http://devsphere.com/ المقالات/jspcache " %><c:if test="${sessionScope.counter == null}">
<c:set var="counter"scope="session" value="0"/></c:if><c:set var="counter" value="${counter+1}"scope="session "/><jc:cache id="cachedFragmentWithCounter">
... <jc:dynamic expr="sessionScope.counter"/>
...</jc:ذاكرة التخزين المؤقت>
تعد متغيرات JSP سهلة الاستخدام وهي حل جيد للتخزين المؤقت للمحتوى لتطبيقات الويب البسيطة. ومع ذلك، إذا كان التطبيق ينشئ الكثير من المحتوى الديناميكي، فإن عدم التحكم في حجم ذاكرة التخزين المؤقت يمثل مشكلة بالتأكيد. يمكن لإطار عمل ذاكرة التخزين المؤقت المخصص أن يوفر حلاً أكثر قوة، مما يسمح بمراقبة ذاكرة التخزين المؤقت، والحد من حجم ذاكرة التخزين المؤقت، والتحكم في سياسة ذاكرة التخزين المؤقت، وما إلى ذلك...
استخدام واجهة برمجة تطبيقات لغة التعبير JSP 2.0
تقوم حاويات JSP (مثل Tomcat) بتقييم التعبيرات في صفحات JSP باستخدام EL API ويمكن استخدامها بواسطة تعليمات Java البرمجية. وهذا يسمح بالتطوير خارج صفحات الويب باستخدام JSP EL، على سبيل المثال، على ملفات XML، والموارد المستندة إلى النص، والبرامج النصية المخصصة. تعد EL API مفيدة أيضًا عندما تحتاج إلى التحكم في وقت تعيين التعبيرات الموجودة في صفحة الويب أو التعبيرات المكتوبة المتعلقة بها. على سبيل المثال، يمكن أن تحتوي أجزاء الصفحة المخزنة مؤقتًا على تعبيرات JSP مخصصة، وسيتم استخدام EL API لتعيين هذه التعبيرات أو إعادة تقييمها في كل مرة يتم فيها إصدار المحتوى المخزن مؤقتًا.
توفر المقالة نموذجًا لبرنامج (راجع قسم الموارد في نهاية المقالة). يحتوي هذا التطبيق على فئة Java (JspUtils) وطريقة eval() في الفئة. تحتوي هذه الطريقة على ثلاث معلمات: تعبير JSP، النوع المتوقع للتعبير وكائن سياق JSP. تحصل طريقة Eval () على ExpressionEvaluator من سياق JSP وتستدعي طريقة التقييم () وتمرير التعبير ونوع التعبير المتوقع والمتغير الذي تم الحصول عليه من نص JSP. يقوم الأسلوب JspUtils.eval() بإرجاع قيمة التعبير.
الحزمة com.devsphere.articles.jspcache;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.el.ELException;
import javax.servlet.jsp.el.ExpressionEvaluator;
import java.io.IOException;public class JspUtils {
تقييم الكائن الثابت العام (
سلسلة expr، نوع الفئة، JspContext jspContext)
يلقي JspException {
يحاول {
إذا (expr.indexOf("${") == -1)
عودة إكسبر؛
مقيم التعبير
= jspContext.getExpressionEvaluator();
تقييم الإرجاع. تقييم (expr، type،
jspContext.getVariableResolver(), null);
} مسك (ELException e) {
رمي JspException (e) جديد ؛
}
}
...}
ملاحظة: يقوم JspUtils.eval() بشكل أساسي بتغليف ExpressionEvaluator القياسي. إذا لم يحتوي expr على ${، فلن يتم استدعاء JSP EL API لأنه لا يوجد تعبير JSP.
إنشاء ملف واصف مكتبة العلامات (TLD) تتطلب مكتبة علامات JSP ملف واصف مكتبة العلامات (TLD) لتخصيص تسمية العلامات وسماتها وفئات Java التي تعمل على العلامة. يصف jspcache.tld علامتين مخصصتين. يحتوي <jc:cache> على سمتين: معرف جزء الصفحة المخزنة مؤقتًا ونطاق JSP — نطاق محتوى صفحة JSP التي يجب تخزينها دائمًا. يحتوي <jc:dynamic> على سمة واحدة فقط، وهي تعبير JSP الذي يجب تقييمه في كل مرة يتم فيها إخراج جزء ذاكرة التخزين المؤقت. يقوم ملف TLD بتعيين هاتين العلامتين المخصصتين إلى فئتي CacheTag وDynamicTag كما يلي:
<?xml version="1.0" encoding="UTF-8" ?><taglib xmlns=" http://java.sun.com/xml/ns/j2ee "
xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance "
xsi:schemaLocation=" http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd"
الإصدار = "2.0">
<tlib-version>1.0</tlib-version>
<short-name>jc</short-name>
<uri>http://devsphere.com/articles/jspcache</uri>
<العلامة>
<الاسم>ذاكرة التخزين المؤقت</الاسم>
<tag-class>com.devsphere.articles.jspcache.CacheTag</tag-class>
<body-content>بدون نصوص</body-content>
<السمة>
<الاسم>المعرف</الاسم>
<required>صحيح</required>
<rtexprvalue>صحيح</rtexprvalue>
</السمة>
<السمة>
<الاسم>النطاق</الاسم>
<required>خطأ</required>
<rtexprvalue>خطأ</rtexprvalue>
</السمة>
</العلامة>
<العلامة>
<الاسم>ديناميكي</الاسم>
<tag-class>com.devsphere.articles.jspcache.DynamicTag</tag-class>
<body-content>فارغ</body-content>
<السمة>
<الاسم>إكسبر</الاسم>
<required>صحيح</required>
<rtexprvalue>خطأ</rtexprvalue>
</السمة>
</tag></taglib>
يتم تضمين ملف TLD في ملف واصف تطبيق الويب (web.xml). تحتوي هذه الملفات الخمسة أيضًا على معلمة أولية تشير إلى ما إذا كانت ذاكرة التخزين المؤقت متاحة أم لا.
<?xml version="1.0" encoding="ISO-8859-1"?><web-app xmlns=" http://java.sun.com/xml/ns/j2ee "
xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance "
xsi:schemaLocation=" http://java.sun.com/xml/ns/j2ee web-app_2_4.xsd"
الإصدار = "2.4">
<سياق المعلمة>
<param-name>com.devsphere.articles.jspcache.enabled</param-name>
<param-value>صحيح</param-value>
</context-param>
<jsp-التكوين>
<taglib>
<taglib-uri>http://devsphere.com/articles/jspcache</taglib-uri>
<taglib-location>/WEB-INF/jspcache.tld</taglib-location>
</taglib>
</jsp-config></web-app>
فهم آلية عمل <jc:cache>. تقوم حاوية JSP بإنشاء مثيل CacheTag لكل علامة <jc:cache> في صفحة JSP لمعالجتها. حاوية JSP مسؤولة عن استدعاء أساليب setJsp () وsetParent () وsetJspBody ()، وهي فئة CacheTag الموروثة من SimpleTagSupport. تستدعي حاوية JSP أيضًا طريقة الضبط لكل سمة من سمات العلامة التي تم التعامل معها. تقوم طريقتا SetId() وsetScope() بتخزين قيمة السمة في حقل خاص. تمت تهيئة هذه القيمة بالقيمة الافتراضية باستخدام مُنشئ CacheTag().
الحزمة com.devsphere.articles.jspcache;
import javax.servlet.ServletContext;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import java.io.IOException;import java.io.StringWriter;
الطبقة العامة CacheTag تمتد SimpleTagSupport {
السلسلة النهائية العامة الثابتة CACHE_ENABLED
= "com.devsphere.articles.jspcache.enabled";
معرف السلسلة الخاصة؛
نطاق كثافة العمليات الخاصة؛
ذاكرة التخزين المؤقت المنطقية الخاصة ممكنة؛ public CacheTag() {
معرف = نطاق فارغ = PageContext.APPLICATION_SCOPE؛
} مجموعة الفراغ العام (معرف السلسلة) {
this.id = id;
} مجموعة الفراغ العام (نطاق السلسلة) {
this.scope = JspUtils.checkScope(scope);
}
...}
يستدعي الأسلوب setScope() JspUtils.checkScope() للتحقق من قيمة خاصية النطاق الذي تم تحويله من نوع String إلى النوع int.
...فئة عامة JspUtils {
...
عام ثابت int checkScope (نطاق السلسلة) {
إذا ("الصفحة".equalsIgnoreCase(النطاق))
إرجاع PageContext.PAGE_SCOPE؛
وإلا إذا ("طلب".equalsIgnoreCase(نطاق))
إرجاع PageContext.REQUEST_SCOPE؛
وإلا إذا ("الجلسة".equalsIgnoreCase(النطاق))
إرجاع PageContext.SESSION_SCOPE؛
وإلا إذا ("التطبيق".equalsIgnoreCase(النطاق))
إرجاع PageContext.APPLICATION_SCOPE؛
آخر
رمي IllegalArgumentException جديد (
"النطاق غير صالح:" + النطاق)؛
}}
بمجرد أن يصبح مثيل CacheTag جاهزًا للعمل على العلامة، تستدعي حاوية JSP طريقة doTag() وتحصل على سياق JSP باستخدام getJspContext(). تم تحويل هذا الكائن إلى PageContext، بحيث يمكن استدعاء طريقة getServletContext(). يتم استخدام سياق servlet للحصول على قيمة معلمة التهيئة، والتي تشير إلى ما إذا كانت آلية التخزين المؤقت ممكّنة أم لا. إذا تم تمكين التخزين المؤقت، فسيحاول doTag() الحصول على جزء الصفحة المخزنة مؤقتًا باستخدام قيم سمات المعرف والنطاق. إذا لم يتم تخزين جزء الصفحة مؤقتًا، فإن doTag() يستخدم getJspBody().invoc() لتنفيذ كود JSP المغلف بواسطة <jc:cache> و </jc:cache>. يتم تخزين المخرجات التي تم إنشاؤها بواسطة نص JSP مؤقتًا في StringWriter ويتم استردادها بواسطة طريقة toStirng (). بهذه الطريقة، تستدعي doTag() طريقة setAttribute() لسياق JSP لإنشاء متغير JSP جديد يتحكم هذا المتغير في محتوى ذاكرة التخزين المؤقت التي قد تحتوي على تعبيرات JSP (${…}). يتم تعيين هذه التعبيرات بواسطة JspUtils.eval() قبل إخراج المحتوى باستخدام jspContext.getOut().print(). يحدث هذا السلوك فقط عند تمكين التخزين المؤقت. بخلاف ذلك، تقوم doTag() فقط بتنفيذ نص JSP من خلال getJspBody().invoc(null) ولا يتم تخزين نتيجة الإخراج مؤقتًا.
...فئة عامة CacheTag تمتد SimpleTagSupport {
...
public void doTag() يلقي JspException، IOException {
JspContext jspContext = getJspContext();
تطبيق سيرفلت كونتيكست
= ((PageContext) jspContext).getServletContext();
سلسلة ذاكرة التخزين المؤقتEnabledParam
= application.getInitParameter(CACHE_ENABLED);
CacheEnabled = CacheEnabledParam != null
&& CacheEnabledParam.equals("true");
إذا (تم تمكين ذاكرة التخزين المؤقت) {
سلسلة مخبأةالإخراج
= (String) jspContext.getAttribute(id,scope);
إذا (cachedOutput == فارغة) {
StringWriter buffer = new StringWriter();
getJspBody().invoc(buffer);
cachedOutput = buffer.toString();
jspContext.setAttribute(id,cachedOutput,scope);
} سلسلة تقييمهاوتبوت = (سلسلة) JspUtils.eval(
cachedOutput, String.class, jspContext);
jspContext.getOut().print(evaluatedOutput);
} آخر
getJspBody().invoc(null);
}
...}
لاحظ أن استدعاء JspUtils.eval() واحد يقوم بتقييم جميع تعبيرات ${...} . لأن النص الذي يحتوي على عدد كبير من بنيات ${...} هو أيضًا تعبير. يمكن معالجة كل جزء من ذاكرة التخزين المؤقت كتعبير JSP معقد.
تقوم طريقة IsCacheEnabled () بإرجاع قيمة ذاكرة التخزين المؤقت التي تمت تهيئتها بواسطة doTag ().
...فئة عامة CacheTag تمتد SimpleTagSupport {
... المنطقية العامة isCacheEnabled() {
إرجاع ذاكرة التخزين المؤقت Enabled؛
}}
تسمح العلامة <jc:cache> لمطوري الصفحة باختيار معرف أجزاء الصفحة المخزنة مؤقتًا. يسمح هذا بمشاركة أجزاء الصفحة المخزنة مؤقتًا بواسطة صفحات JSP متعددة، وهو أمر مفيد عند إعادة استخدام كود JSP. ولكن لا تزال هناك حاجة إلى بعض بروتوكولات التسمية لتجنب التعارضات المحتملة. يمكن تجنب هذا التأثير الجانبي عن طريق تعديل فئة CacheTag لتضمين عنوان URL داخل المعرف التلقائي.
فهم ما يفعله <jc:dynamic> تتم معالجة كل <jc:dynamic> بواسطة مثيل لفئة DynamicTag، ويقوم الأسلوب setExpr() بتخزين قيمة السمة expr في حقل خاص. تقوم طريقة DoTag() بإنشاء تعبير JSP وتضيف البادئة ${ واللاحقة } إلى قيمة السمة expr. بعد ذلك، يستخدم doTag() findAncestorWithClass() للعثور على معالج CacheTag الخاص بـ <jc:cache> الذي يحتوي على عنصر العلامة <jc:dynamic>. إذا لم يتم العثور عليه أو تم تعطيل التخزين المؤقت، فسيتم تقييم تعبير JSP باستخدام JspUtils.eval() ويتم إخراج القيمة. بخلاف ذلك، ستُخرج الدالة doTag() تعبيرًا لا قيمة له.
الحزمة com.devsphere.articles.jspcache;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import java.io.IOException;
الطبقة العامة DynamicTag تمتد SimpleTagSupport {
سلسلة خاصة expr؛
مجموعة الفراغ العام (سلسلة إكسبر) {
this.expr = expr;
} public void doTag() يطرح JspException، IOException {
إخراج السلسلة = "${" + expr + "}";
سلف CacheTag = (CacheTag) findAncestorWithClass(
هذا، CacheTag.class)؛
إذا (السلف == فارغ || !ancestor.isCacheEnabled())
الإخراج = (سلسلة) JspUtils.eval(
الإخراج، String.class، getJspContext())؛
getJspContext().getOut().print(output);
}}
من خلال تحليل الكود أعلاه، يمكنك ملاحظة أن <jc:cache> و <jc:dynamic> يتعاونان لتحقيق حل فعال قدر الإمكان. إذا كانت ذاكرة التخزين المؤقت متاحة، فسيتم وضع جزء الصفحة في المخزن المؤقت مع تعبير JSP الذي تم إنشاؤه بواسطة <jc:dynamic> وتعيين قيمة CacheTag. إذا تم تعطيل التخزين المؤقت، يصبح التخزين المؤقت بلا معنى ويقوم <jc:cache> ببساطة بتنفيذ الجزء الأساسي الخاص بـ JSP، تاركًا DynamicTag لتعيين قيم لتعبير JSP. يعد تعطيل التخزين المؤقت ضروريًا في بعض الأحيان، خاصة أثناء عملية التطوير عندما يتغير المحتوى ويتم إعادة ترجمة صفحات JSP. بالطبع، يجب تمكين التخزين المؤقت في بيئة الإنتاج بعد التطوير.
تلخيص
لتطوير تطبيقات كبيرة على مستوى المؤسسة، يجب أن تفكر في استخدام إطار عمل يدعم آليات تخزين مؤقت أفضل بدلاً من استخدام متغيرات JSP فقط. ولكن من المفيد بلا شك فهم تقنية التخصيص المستندة إلى EL API.