java - شرح - كيف تعمل servlets؟ Instantization ، جلسات العمل ، المتغيرات المشتركة و multithreading




thread in java شرح (5)

افترض ، لدي خادم ويب يحمل العديد من servlets. للحصول على معلومات تمر بين تلك servlets أقوم بإعداد متغيرات جلسة ومثيل.

الآن ، إذا قام مستخدمان أو أكثر بإرسال طلب إلى هذا الخادم ، فماذا يحدث لمتغيرات الجلسة؟ هل ستكون كلها مشتركة لجميع المستخدمين أو أنها ستكون مختلفة لكل مستخدم. إذا كانت مختلفة ، فكيف تمكن الخادم من التفريق بين مختلف المستخدمين؟

سؤال واحد أكثر شبهاً ، إذا كان هناك مستخدمون يقومون بالوصول إلى servlet معين ، فحينئذٍ يتم نسخ هذه servlet فقط في المرة الأولى التي يقوم المستخدم الأول بالوصول إليها أو هل يتم إنشاء مثيل لها لجميع المستخدمين بشكل منفصل؟ بمعنى آخر ، ماذا يحدث لمتغيرات الحالة؟


ServletContext

عندما تبدأ حاوية servlet (مثل Apache Tomcat ) ، سيتم نشر وتحميل جميع تطبيقات الويب الخاصة بها. عند تحميل تطبيق ويب ، يقوم حاوية servlet بإنشاء ServletContext مرة واحدة ServletContext في ذاكرة الخادم. يتم تحليل ملف web.xml الخاص web.xml الويب ، ويتم إنشاء كل من كل من <servlet> و <filter> و <listener> (أو كل فئة @WebServlet باستخدام @WebServlet ، و @WebListener و @WebListener على التوالي) مرة واحدة ويتم الاحتفاظ بها في ذاكرة الخادم حسنا. لكل عامل تصفية تم init() يتم استدعاء أسلوب init() مع FilterConfig جديد.

عند إيقاف تشغيل حاوية servlet ، تقوم بإلغاء تحميل كافة تطبيقات الويب ، وتستدعي أسلوب destroy() لكافة وحدات الخدمة والمرشحات المبدئية ، ويتم نقل جميع مثيلات ServletContext و Servlet و Filter و Listener .

عندما يكون لدى Servlet <servlet><load-on-startup> أو @WebServlet(loadOnStartup) أكبر من 0 ، يتم استدعاء أسلوب init() أيضًا أثناء بدء التشغيل مع ServletConfig جديد. تتم تهيئة تلك servlets بنفس الترتيب المحدد بواسطة تلك القيمة (1 -> 1 ، 2 -> 2 ، إلخ). إذا تم تحديد نفس القيمة لأكثر من servlet واحد ، فسيتم تحميل كل من تلك servlets بالترتيب الذي تظهر به في web.xml ، أو @WebServlet . في حالة عدم وجود قيمة "التحميل عند بدء التشغيل" ، سيتم استدعاء أسلوب init() عندما يقوم طلب HTTP بالوصول إلى servlet لأول مرة.

HttpServletRequest و HttpServletResponse

يتم توصيل حاوية servlet بخادم ويب يستمع لطلبات HTTP على رقم منفذ معين (عادةً ما يتم استخدام المنفذ 8080 أثناء التطوير ومنفذ المنفذ 80 في الإنتاج). عندما يرسل عميل (مستخدم لديه مستعرض ويب) طلب HTTP ، ينشئ حاوية servlet كائنات HttpServletResponse و HttpServletRequest جديدة ويمررها من خلال أي سلسلة Filter محددة ، وفي النهاية ، مثيل Servlet .

في حالة filters ، يتم استدعاء أسلوب doFilter() . عندما يستدعي الرمز الخاص به chain.doFilter(request, response) ، يستمر الطلب والاستجابة إلى الفلتر التالي ، أو يضغط على servlet إذا لم تكن هناك فلاتر متبقية.

في حالة servlets ، يتم استدعاء أسلوب service() . بشكل افتراضي ، تحدد هذه الطريقة أي واحد من الطرق doXxx() استدعاء يستند doXxx() request.getMethod() . إذا كان الأسلوب المحدد غير موجود في servlet ، فسيتم إرجاع خطأ HTTP 405 في الاستجابة.

يوفر كائن الطلب الوصول إلى جميع المعلومات المتعلقة بطلب HTTP ، مثل رؤوسه ونصه. يوفر كائن الاستجابة القدرة على التحكم وإرسال استجابة HTTP بالطريقة التي تريدها ، على سبيل المثال ، مما يسمح لك بتعيين الرؤوس والجسم (عادةً مع محتوى HTML تم إنشاؤه من ملف JSP). عندما تلتزم استجابة HTTP وتنتهي ، يتم إعادة تدوير كل من طلب وكائنات الاستجابة ويتم إعادة استخدامها.

HttpSession

عندما يزور العميل موقع الويب للمرة الأولى و / أو يتم الحصول على HttpSession لأول مرة عبر request.getSession() ، ينشئ حاوية servlet كائن HttpSession جديدًا ، ينشئ HttpSession طويلاً وفريدًا (يمكنك الحصول عليه من خلال session.getId() ) ، وتخزينها في ذاكرة الخادم. تحدد حاوية servlet أيضًا ملف Cookie JSESSIONID رأس Set-Cookie لاستجابة HTTP باستخدام JSESSIONID ومعرّف الجلسة الفريد كقيمة لها.

وفقًا لمواصفات ملف تعريف ارتباط HTTP (عقد يجب أن يلتزم به متصفح ويب لائق وخادم الويب) ، يجب على العميل (متصفح الويب) إرسال ملف تعريف الارتباط هذا في الطلبات اللاحقة في رأس ملف تعريف الارتباط طالما أن ملف تعريف الارتباط صالح (على سبيل المثال ، يجب أن يشير المعرّف الفريد إلى جلسة غير منتهي الصلاحية ويكون المجال والمسار صحيحين). باستخدام جهاز عرض حركة مرور HTTP المضمن في المستعرض الخاص بك ، يمكنك التحقق من صلاحية ملف تعريف الارتباط (اضغط F12 في Chrome / Firefox 23+ / IE9 + ، وتحقق من علامة التبويب Net / Network ). تقوم حاوية servlet بالتحقق من رأس ملف تعريف الارتباط لكل طلب HTTP الوارد لوجود ملف تعريف الارتباط بالاسم JSESSIONID واستخدام قيمته (معرف الجلسة) للحصول على HttpSession المقترن من ذاكرة الخادم.

يبقى HttpSession حيًا حتى لا يتم استخدامه لأكثر من قيمة المهلة المحددة في <session-timeout> ، إعداد في web.xml . قيمة المهلة الافتراضية هي 30 دقيقة. لذلك ، عندما لا يزور العميل تطبيق الويب لفترة أطول من الوقت المحدد ، فإن حاوية servlet تنقل المهملات إلى الجلسة. كل طلب لاحق ، حتى مع ملف تعريف الارتباط المحدد ، لن يتمكن من الوصول إلى نفس الجلسة مرة أخرى ؛ ستعمل حاوية servlet على إنشاء جلسة جديدة.

على جانب العميل ، يبقى ملف تعريف ارتباط جلسة العمل على قيد الحياة طالما يتم تشغيل مثيل المستعرض. لذا ، إذا أغلق العميل مثيل المتصفح (جميع علامات التبويب / النوافذ) ، فسيتم حذف الجلسة على جانب العميل. في حالة متصفح جديد ، لن يكون ملف تعريف الارتباط المرتبط بالجلسة موجودًا ، لذلك لن يتم إرساله بعد الآن. يؤدي هذا إلى إنشاء HTTPSession جديد تمامًا ، مع بدء استخدام ملف تعريف ارتباط جلسة جديد تمامًا.

شيء صغير

  • يعيش ServletContext طوال فترة بقاء تطبيق الويب. تتم مشاركتها بين جميع الطلبات في جميع الجلسات.
  • يعيش HttpSession طالما يتفاعل العميل مع تطبيق الويب مع نفس مثيل المتصفح ، ولم تنقضي الجلسة على جانب الخادم. تتم مشاركتها بين جميع الطلبات في نفس الجلسة.
  • يعيش HttpServletResponse و HttpServletResponse من الوقت الذي يتلقى فيه servlet طلب HTTP من العميل ، حتى وصول الاستجابة الكاملة (صفحة الويب). لا يتم مشاركته في مكان آخر.
  • جميع مثيلات Servlet و Filter و Listener تعيش طالما يعيش تطبيق الويب. تتم مشاركتها بين جميع الطلبات في جميع الجلسات.
  • أي attribute يتم تعريفها في ServletContext و HttpServletRequest و HttpSession ستعيش طالما يعيش الكائن المعني. يمثل الكائن نفسه "النطاق" في أطر إدارة الفول مثل JSF ، CDI ، الربيع ، إلخ. هذه الأُطر تخزن حبوبها ذات النطاق الواسع كخاصية لأقرب نطاق مطابق لها.

سلامة الموضوع

ومع ذلك ، فإن قلقك الرئيسي ربما يكون موضوع السلامة . يجب أن تعرف الآن أنه يتم مشاركة servlets والفلاتر بين جميع الطلبات. هذا هو الشيء الجميل في Java ، إنه مؤشرات ترابط ومؤشرات مختلفة (اقرأ: طلبات HTTP) يمكنه الاستفادة من نفس المثيل. كان من المفيد للغاية إعادة إنشاء ، init() destroy() لهم لكل طلب واحد.

يجب أن تدرك أيضًا أنه لا ينبغي عليك أبدًا تعيين أي طلب أو بيانات خاصة بجلسة الجلسة كمتغير مثيل ل servlet أو مرشح. سيتم مشاركته بين جميع الطلبات الأخرى في الجلسات الأخرى. هذا ليس موضوع آمن! يوضح المثال التالي هذا:

public class ExampleServlet extends HttpServlet {

    private Object thisIsNOTThreadSafe;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Object thisIsThreadSafe;

        thisIsNOTThreadSafe = request.getParameter("foo"); // BAD!! Shared among all requests!
        thisIsThreadSafe = request.getParameter("foo"); // OK, this is thread safe.
    } 
}

أنظر أيضا:


جلسات

باختصار: يصدر خادم الويب معرفًا فريدًا لكل زائر في أول زيارة له. يجب على الزائر إعادة هذا الرقم له حتى يتم التعرف عليه في المرة القادمة. يسمح هذا المعرف أيضًا للخادم بفصل الكائنات التي تملكها جلسة واحدة بشكل صحيح مقارنة بآخر.

Instantlet Servlet

إذا كان التحميل عند بدء التشغيل غير صحيح :

إذا كان التحميل عند بدء التشغيل صحيحًا :

حالما يعمل على وضع الخدمة وعلى الأخدود ، ستعمل نفس servlet على الطلبات من جميع العملاء الآخرين.

لماذا ليست فكرة جيدة أن يكون لديك مثيل واحد لكل عميل؟ فكر في هذا: هل ستوظف بيتزا واحدة لكل طلب يأتي؟ افعل ذلك وستكون خارج العمل في وقت قصير.

انها تأتي مع خطر صغير رغم ذلك. تذكر: هذا الشخص الوحيد يحمل جميع معلومات الطلب في جيبه: حتى إذا لم تكن حذرا بشأن سلامة الخيط على servlets ، فقد ينتهي الأمر بإعطاء أمر خاطئ لعميل معين.


تحدد مواصفات سيرتليت JSR-315 بشكل واضح سلوك حاوية الويب في الخدمة (وطرق doGet ، doPost ، doPut إلخ.) (2.3.3.1 مسائل متعددة مؤشرات الترابط ، صفحة 9):

قد ترسل حاوية servlet طلبات متزامنة من خلال طريقة خدمة servlet. للتعامل مع الطلبات ، يجب أن يقوم مطور Servlet بتكوين بنود كافية للمعالجة المتزامنة مع سلاسل عمليات متعددة في طريقة الخدمة.

على الرغم من أنه لا يوصى به ، إلا أن البديل للمطور هو تنفيذ واجهة SingleThreadModel التي تتطلب الحاوية لضمان وجود مؤشر ترابط طلب واحد فقط في وقت في طريقة الخدمة. قد تستوفي حاوية servlet هذا المطلب من خلال إجراء تسلسل للطلبات على servlet ، أو عن طريق الاحتفاظ بمجموعة من مثيلات servlet. إذا كانت servlet جزءًا من تطبيق ويب تم وضع علامة عليه باعتباره قابل للتوزيع ، فقد تحتفظ الحاوية بمجموعة من مثيلات servlet في كل JVM التي يتم توزيع التطبيق عبرها.

بالنسبة إلى servlets التي لا تقوم بتطبيق واجهة SingleThreadModel ، إذا تم تعريف طريقة الخدمة (أو طرق مثل doGet أو doPost التي يتم إرسالها إلى طريقة الخدمة للفئة المجردة HttpServlet) باستخدام الكلمة الأساسية المتزامنة ، فلا يمكن استخدام حاوية servlet في نهج تجمع المثيل ، ولكن يجب أن تسلسل الطلبات عبرها. يوصى بشدة بعدم قيام المطورين بمزامنة طريقة الخدمة (أو الطرق المرسلة إليها) في هذه الظروف بسبب التأثيرات الضارة على الأداء


عندما يبدأ تشغيل servletcontainer (مثل Apache Tomcat) ، فإنه سيقرأ من ملف web.xml (واحد فقط لكل تطبيق) إذا حدث أي خطأ أو يظهر خطأ في وحدة التحكم في الحاوية ، وإلا فإنه سيتم نشر وتحميل كل تطبيقات الويب باستخدام الويب .xml (لذا أطلق عليها اسم واصف النشر).

خلال مرحلة إنشاء مثيل servlet ، يكون servletInstance جاهزًا ولكنه لا يمكن أن يخدم طلب العميل لأنه مفقود مع معلومتين:
1: معلومات السياق
2: معلومات التكوين الأولية

يقوم محرك Servlet بإنشاء كائن واجهة servletConfig بتضمين المعلومات المفقودة أعلاه في محرك أقراص servlet الخاص به init () لـ servlet بواسطة suplying مراجع كائن servletConfig كوسيطة. بمجرد تنفيذ init () servlet تم تنفيذها بالكامل جاهز لخادم طلب العميل.

س) في زمن حياة servlet ، كم مرة يحدث التأريخ والشروع؟

أ) مرة واحدة فقط (لكل طلب عميل يتم إنشاء مؤشر ترابط جديد) يخدم مثيل واحد فقط من servlet أي عدد من طلب العميل أي ، بعد أن لا يموت خادم طلب عميل واحد. ينتظر طلبات العميل الأخرى أي ما CGI (لكل طلب عميل يتم إنشاء عملية جديدة) يتم التغلب على القيد مع servlet (محرك servlet داخليًا ينشئ مؤشر ترابط).

س) كيف يعمل مفهوم الجلسة؟

أ) عندما يتم استدعاء getSession () على كائن HttpServletRequest

الخطوة 1 : يتم evalauated كائن الطلب لمعرف جلسة العمل الواردة.

الخطوة 2 : إذا لم يكن معرّف avaiable تم إنشاء كائن HttpSession جديد تمامًا وتم إنشاء معرّف الجلسة المطابق له (أي HashTable) في IDservable ، تمّ تخزين معرّف الجلسة واسترجاع مرجع كائن HttpSession إلى servlet (doGet / doPost).

الخطوة 3 : إذا لم يتم إنشاء معرف جلسة عمل العلامة التجارية الجديدة avaiable تم التقاط معرف جلسة العمل من إجراء البحث عن كائن الطلب في مجموعة جلسات باستخدام معرف جلسة العمل كمفتاح.

بمجرد أن يتم تخزين البحث هو معرف جلسة نجاح في HttpServletResponse يتم إرجاع مراجع كائن جلسة العمل السابقين إلى doGet () أو doPost () من UserDefineservlet.

ملحوظة:

1) عندما يترك التحكم من كود servlet إلى العميل لا تنسى أن كائن الجلسة يتم الاحتفاظ به بواسطة servletcontainer أي ، servletengine

2) يتم ترك multithreading إلى servl devlopers الناس لتنفيذ ie. ، والتعامل مع طلب متعددة من العميل أي شيء عناء عن رمز multithread

الشكل الداخلي:

يتم إنشاء servlet عند بدء تشغيل التطبيق (يتم نشره على حاوية servlet) أو عند الوصول إليه لأول مرة (بناءً على إعداد التحميل عند بدء التشغيل) عند إنشاء servlet ، تسمى طريقة init () الخاصة بـ servlet ثم تعالج servlet (مثيلها واحد فقط) كافة الطلبات (يتم استدعاء أسلوب الخدمة () الخاص به بواسطة مؤشرات ترابط متعددة). هذا هو السبب في أنه ليس من المستحسن أن يكون هناك أي تزامن في ذلك ، ويجب عليك تجنب متغيرات المثال من servlet عند إلغاء التطبيق (توقف حاوية servlet) ، يتم استدعاء طريقة destroy ().


لا. الخزانات ليست آمنة

يسمح بالوصول إلى أكثر من سلسلة واحدة في المرة الواحدة

إذا كنت تريد أن تجعل من سيرفت كسلسلة آمنة ، يمكن أن تذهب ل

Implement SingleThreadInterface(i) وهو واجهة فارغة لا يوجد

أساليب

أو يمكننا الذهاب لطرق التزامن

يمكننا أن نجعل طريقة الخدمة بأكملها متزامنة باستخدام متزامن

keword أمام الطريقة

مثال::

public Synchronized class service(ServletRequest request,ServletResponse response)throws ServletException,IOException

أو يمكننا وضع الكود في الكود المتزامن

مثال::

Synchronized(Object)

{

----Instructions-----

}

أشعر أن كتلة متزامنة أفضل من جعل الأسلوب كله

تزامن





instance-variables