هل تطبيق J2EE الخاص بك يعمل ببطء؟ هل يمكنهم تحمل ارتفاع حركة المرور؟ توضح هذه المقالة تقنية تحسين الأداء لتطوير صفحات JSP وServlets عالية الأداء ومرنة للغاية. والفكرة هي البناء في أسرع وقت ممكن والتكيف مع العدد المتزايد من المستخدمين وطلباتهم. في هذه المقالة، سأرشدك إلى تعلم تقنيات ضبط الأداء العملية والمثبتة والتي من شأنها تحسين أداء servlets وصفحات jsp بشكل كبير، وبالتالي تحسين أداء J2EE. يتم استخدام بعض هذه التقنيات في مراحل التطوير، مثل مراحل التصميم والترميز. جزء آخر من التكنولوجيا يتعلق بالتكوين.
الأسلوب 1: تخزين البيانات مؤقتًا بطريقة HttpServletinit()
يقوم الخادم باستدعاء طريقة init() الخاصة بـ servlet بعد إنشاء مثيل servlet وقبل أن يعالج servlet أي طلبات. يتم استدعاء هذه الطريقة مرة واحدة فقط خلال دورة حياة servlet. لتحسين الأداء، قم بتخزين البيانات الثابتة في init() أو قم بإجراء عمليات باهظة الثمن أثناء التهيئة. على سبيل المثال، إحدى أفضل الممارسات هي استخدام تجمع اتصال JDBC الذي يقوم بتنفيذ واجهة javax.sql.DataSource.
يتم الحصول على مصدر البيانات من شجرة JNDI. يعد استخدام JNDI للعثور على مصدر البيانات في كل مرة يتم فيها استدعاء SQL أمرًا مكلفًا للغاية، ويؤثر ذلك بشكل خطير على أداء التطبيق. يمكن استخدام طريقة init () الخاصة بـ Servlet للحصول على مصدر البيانات وتخزينه مؤقتًا لإعادة استخدامه لاحقًا:
publicclassControllerServletextendsHttpServlet
{
Privatejavax.sql.DataSourcetestDS=null
publicvoidinit(ServletConfigconfig)throwsServletException
{
super.init(config);
contextctx=null;
يحاول
{
ctx=newInitialContext();
testDS=(javax.sql.DataSource)ctx.lookup("jdbc/testDS");
}
قبض على (استثناء التسمية)
{
printStackTrace();
}
قبض (استثناء)
{
printStackTrace();
}
}
publicjavax.sql.DataSourcegetTestDS()
{
returntestDS;
}
...
...
}
الأسلوب 2: قم بتعطيل وظيفة التحميل التلقائي لـ servlet وJSPs
. سيتعين عليك إعادة تشغيل الخادم في كل مرة تقوم فيها بتعديل Servlet/JSP. وبما أن ميزة التحميل التلقائي تقلل من وقت التطوير، فإن هذه الميزة تعتبر مفيدة جدًا أثناء مرحلة التطوير. ومع ذلك، فهو مكلف للغاية في مرحلة التشغيل؛ ويتسبب servlet/JSP في ضعف الأداء بسبب التحميل غير الضروري وزيادة العبء على مُحمل الفئة. مرة أخرى، يمكن أن يتسبب هذا في حدوث تعارضات غريبة في تطبيقك لأن الفئات التي تم تحميلها بواسطة مُحمل فئة معينة لا يمكنها التعاون مع الفئات التي تم تحميلها بواسطة مُحمل الفئة الحالي. لذلك، من أجل الحصول على أداء أفضل في بيئة التشغيل، قم بإيقاف تشغيل وظيفة التحميل التلقائي لـ servlet/JSP.
الأسلوب 3: التحكم في جلسة HttpSession
تتطلب العديد من التطبيقات سلسلة من طلبات العميل حتى يمكن ربطها ببعضها البعض. نظرًا لأن بروتوكول HTTP عديم الحالة، يجب أن تكون التطبيقات المستندة إلى الويب مسؤولة عن الحفاظ على مثل هذه الحالة التي تسمى الجلسة. من أجل دعم التطبيقات التي يجب أن تحافظ على حالتها، توفر تقنية Javaservlet واجهات برمجة التطبيقات التي تدير الجلسات وتسمح بآليات متعددة لتنفيذ الجلسات. يعمل كائن HttpSession كجلسة، ولكن هناك تكلفة لاستخدامه. عندما يتم استخدام HttpSession وتجاوزه، تتم قراءته بواسطة servlet. يمكنك تحسين الأداء باستخدام التقنيات التالية:
لا تقم بإنشاء جلسة HttpSession افتراضية في صفحة JSP: بشكل افتراضي، تقوم صفحة JSP بإنشاء جلسة HttpSession. إذا كنت لا تستخدم HttpSession في صفحة JSP الخاصة بك، ومن أجل توفير حمل الأداء، استخدم إرشادات الصفحة التالية لتجنب إنشاء كائنات HttpSession تلقائيًا:
< %@pagesession="false"% >
1) لا تقم بتخزين الرسوم البيانية للكائنات الكبيرة في HttpSession: إذا قمت بتخزين البيانات في HttpSession كرسم بياني لكائن كبير، فسيتعين على خادم التطبيق معالجة كائن HttpSession بالكامل في كل مرة. سيؤدي هذا إلى فرض تسلسل Java وزيادة الحمل الحسابي. نظرًا لعبء التسلسل، ستنخفض إنتاجية النظام مع زيادة كائنات البيانات المخزنة في كائن HttpSession.
2) قم بتحرير جلسة HttpSession بعد الاستخدام: عندما لا تعد جلسة HttpSession قيد الاستخدام، استخدم طريقة HttpSession.invalidate() لإبطال الجلسة.
3) تعيين قيمة المهلة: يحتوي محرك servlet على قيمة مهلة افتراضية. إذا لم تقم بحذف الجلسة أو الاستمرار في استخدام الجلسة حتى انتهاء المهلة، فسيقوم محرك servlet بحذف الجلسة من الذاكرة. نظرًا للحمل الزائد في الذاكرة وجمع البيانات المهملة، كلما زادت قيمة مهلة الجلسة، زاد تأثيرها على مرونة النظام وأدائه. حاول تعيين قيمة مهلة الجلسة عند أدنى مستوى ممكن.
الأسلوب 4: استخدام ضغط gzip
الضغط هو ممارسة إزالة المعلومات الزائدة عن الحاجة ووصف المعلومات الخاصة بك في أصغر مساحة ممكنة. يمكن أن يؤدي استخدام gzip (GNUzip) لضغط المستندات إلى تقليل وقت تنزيل ملفات HTML بشكل فعال. كلما كانت رسائلك أصغر، تم إرسالها بشكل أسرع. لذلك، إذا قمت بضغط المحتوى الذي تم إنشاؤه بواسطة تطبيق الويب الخاص بك، كلما وصل إلى المستخدم بشكل أسرع ويتم عرضه على شاشة المستخدم. لا يدعم كل متصفح ضغط gzip، ولكن من السهل التحقق مما إذا كان المتصفح يدعمه وإرسال محتوى مضغوط gzip إلى المتصفح. يوضح مقتطف الشفرة أدناه كيفية إرسال محتوى مضغوط.
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsIOException,ServletException
{
OutputStreamout=null
//ChecktheAccepting-EncodingheaderfromtheHTTPrequest.
// إذا كان الرأس يتضمن gzip، فاختر GZIP.
// إذا كان الرأس يتضمن ضغطًا، فاختر ZIP.
//Otherwisechoosenocompression.Stringencoding=request.getHeader("Accept-Encoding
")
;
{
Response.setHeader("تشفير المحتوى"،"gzip");
out=newGZIPOutputStream(response.getOutputStream());
}
elseif(encoding!=null&&encoding.indexOf("compress")!=-1)
{
Response.setHeader("تشفير المحتوى"،"ضغط");
out=newZIPOutputStream(response.getOutputStream());
}
آخر
{
out=response.getOutputStream()
;
...
...
}
الأسلوب 5: لا تستخدم SingleThreadModel
يضمن SingleThreadModel أن servlet يعالج طلبًا واحدًا فقط في كل مرة. إذا قام servlet بتنفيذ هذه الواجهة، فسيقوم محرك servlet بإنشاء مثيل servlet منفصل لكل طلب جديد، مما سيؤدي إلى زيادة حمل النظام. إذا كنت بحاجة إلى حل مشكلات سلامة الخيط، فيرجى استخدام طرق أخرى بدلاً من هذه الواجهة. لم يعد يوصى باستخدام SingleThreadModel في Servlet2.4.
التقنية 6: استخدم
محرك servlet لتجمع الخيوط لإنشاء سلسلة رسائل منفصلة لكل طلب، وتعيين سلسلة الرسائل لأسلوب الخدمة ()، ثم حذف سلسلة الرسائل بعد تنفيذ طريقة الخدمة (). بشكل افتراضي، قد يقوم محرك servlet بإنشاء موضوع جديد لكل طلب. نظرًا لأن إنشاء سلاسل الرسائل وحذفها أمر مكلف، فإن هذا السلوك الافتراضي يقلل من أداء النظام. يمكننا استخدام تجمع الخيوط لتحسين الأداء. وفقًا للعدد المتوقع من المستخدمين المتزامنين، قم بتكوين تجمع سلاسل الرسائل وتعيين الحد الأدنى والحد الأقصى لعدد سلاسل الرسائل في تجمع سلاسل الرسائل بالإضافة إلى الحد الأدنى والحد الأقصى لقيم النمو. في البداية، يقوم محرك servlet بإنشاء تجمع سلاسل رسائل يحتوي على عدد من سلاسل الرسائل يساوي الحد الأدنى لعدد سلاسل الرسائل في التكوين. يقوم محرك servlet بعد ذلك بتعيين مؤشر ترابط من التجمع لطلب بدلاً من إنشاء مؤشر ترابط جديد في كل مرة. بعد اكتمال العملية، يعيد محرك servlet الخيط مرة أخرى إلى تجمع سلاسل الرسائل. باستخدام تجمعات الخيوط، يمكن تحسين الأداء بشكل ملحوظ. إذا لزم الأمر، يمكن إنشاء المزيد من سلاسل الرسائل بناءً على الحد الأقصى لعدد سلاسل الرسائل وعدد النمو.
الأسلوب 7: اختيار آلية التضمين الصحيحة
في صفحات JSP، هناك طريقتان لتضمين الملفات: تضمين التعليمات (< %@includefile="test.jsp"% >) وتضمين الإجراءات (<jsp:includepage="test.jsp " فلوش = "صحيح"/>). يتضمن توجيه التضمين محتويات ملف محدد أثناء مرحلة الترجمة؛ على سبيل المثال، عندما يتم تجميع الصفحة في servlet. يتضمن إجراء التضمين تضمين محتوى الملف أثناء مرحلة الطلب، على سبيل المثال، عندما يطلب المستخدم صفحة. يعد تضمين التعليمات أسرع من تضمين الإجراءات. ولذلك، ما لم تتغير الملفات المضمنة بشكل متكرر، فسوف تحصل على أداء أفضل باستخدام توجيه التضمين.
التقنية 8: استخدام النطاقات المناسبة في إجراءات useBean
إحدى أقوى الطرق لاستخدام صفحات JSP هي العمل مع مكونات JavaBean. يمكن تضمين JavaBeans في صفحات JSP باستخدام العلامة <jsp:useBean>. بناء الجملة كما يلي:
<jsp:useBeanid="name"scope="page|request|session|application"class=
"package.className"type="typeName">
</jsp:useBean>
تصف سمة النطاق النطاق المرئي للفاصوليا. القيمة الافتراضية لسمة النطاق هي الصفحة. يجب عليك اختيار النطاق الصحيح بناءً على احتياجات تطبيقك، وإلا فسيؤثر ذلك على أداء تطبيقك.
على سبيل المثال، إذا كنت بحاجة إلى كائن محدد لبعض الطلبات، لكنك قمت بتعيين النطاق على الجلسة، فسيظل هذا الكائن في الذاكرة بعد انتهاء الطلب. وسيظل في الذاكرة ما لم تقم بحذفه بشكل صريح من الذاكرة، أو إبطال الجلسة، أو انتهاء مهلة الجلسة. إذا لم تختر سمة النطاق الصحيحة، فسيتأثر الأداء بسبب الحمل الزائد للذاكرة وجمع البيانات المهملة. لذا قم بتعيين نطاق مناسب للكائنات وقم بحذفها بمجرد الانتهاء منها.
تقنيات متنوعة
1) تجنب تسلسل السلسلة: نظرًا لأن كائنات السلسلة هي كائنات غير قابلة للتغيير، فإن استخدام عامل التشغيل "+" سيؤدي إلى إنشاء عدد كبير من كائنات الوقت الصفري. كلما زاد استخدام "+"، سيتم إنشاء المزيد من الكائنات ذات الوقت الصفري، مما سيؤثر على الأداء. عندما تحتاج إلى سلسلة السلاسل، استخدم StringBuffer بدلاً من العملية "+".
2) تجنب استخدام System.out.println: يقوم System.out.println بمعالجة إدخال/إخراج القرص بشكل متزامن، مما يقلل بشكل كبير من إنتاجية النظام. تجنب استخدام System.out.println كلما أمكن ذلك. على الرغم من توفر العديد من أدوات تصحيح الأخطاء الناضجة، إلا أن System.out.println لا يزال مفيدًا في بعض الأحيان لأغراض التتبع أو تصحيح الأخطاء. يجب عليك تكوين System.out.println لفتحه فقط أثناء مرحلتي الخطأ وتصحيح الأخطاء. باستخدام متغير FinalBoolean، عند تكوينه على خطأ، يتم إكمال عمليات التحقق من التحسين وإخراج تتبع التنفيذ أثناء مرحلة الترجمة.
3) مقارنة بين ServletOutputStream وPrintWriter: نظرًا لتدفق إخراج الأحرف وترميز البيانات إلى بايت، فإن استخدام PrintWriter يقدم حملًا صغيرًا للأداء. لذلك، يجب استخدام PrintWriter بعد إجراء كافة تحويلات مجموعة الأحرف بشكل صحيح. من ناحية أخرى، عندما تعلم أن servlet الخاص بك سيعيد البيانات الثنائية فقط، استخدم ServletOutputStream لأن حاوية servlet لا تقوم بتشفير البيانات الثنائية، لذلك يمكنك التخلص من عبء تحويل مجموعة الأحرف.
ملخص
الغرض من هذه المقالة هو عرض بعض تقنيات تحسين الأداء العملية والمثبتة لتحسين أداء servlet وJSP، مما سيؤدي إلى تحسين الأداء العام لتطبيقات J2EE الخاصة بك. يجب أن تكون الخطوة التالية هي مراقبة ضبط أداء التقنيات الأخرى ذات الصلة، مثل EJB وJMS وJDBC.