مقدمة
لمطوري Java فقط ، يجب أن نكون على دراية بالجلسة في مواصفات J2EE. بالنسبة لمعظم المطورين الذين يستخدمون Tomcat كحاوية ويب ، كيف يقوم Tomcat بتنفيذ جلسة لتمييز المستخدمين وإدارة معلومات الجلسة؟
ملخص
حصة
يعرّف Tomcat داخليًا الواجهات المتعلقة بالجلسة و HTTPSession ، ويظهر نظام الوراثة الفئة في الشكل 1.
الشكل 1 نظام ميراث فئة الجلسة
يسرد الشكل 1 بالإضافة إلى ذلك نظام الوراثة الفئة للجلسة ، ويتم تقديمها واحدًا تلو الآخر هنا.
الجلسة: يسرد مواصفات الواجهة الأساسية للجلسات في TOMCAT.
الجدول 1 وصف واجهة الجلسة
طريقة | يصف |
getCreationTime ()/setCreationTime (الوقت: طويل) | احصل وضبط وقت إنشاء الجلسة |
getId ()/setID (معرف: سلسلة) | احصل على معرف الجلسة وتعيينها |
getThisAccatedTime () | احصل على وقت بدء الطلب الأخير |
getLastAccatedTime () | احصل على وقت الانتهاء من الطلب الأخير |
GetManager ()/SetManager (مدير: مدير) | احصل على مدير الجلسة وإعداده |
getMaxInactiveInterval ()/setMaxInactiveInterval (الفاصل: int) | احصل على أقصى فاصل وصول بين تعيين الجلسة |
getSession () | الحصول على httpsession |
isValid ()/setValid (isValid: Boolean) | احصل على الحالة الصالحة للجلسة وتعيينها |
Access ()/endAccess () | ابدأ وإنهاء وصول الجلسة |
انتهاء الصلاحية () | اضبط انتهاء صلاحية الجلسة |
httpsession: مواصفات واجهة للجلسة المقدمة من عميل HTTP وخادم HTTP.
الجدول 2 وصف واجهة httpsession
طريقة | يصف |
getCreationTime () | احصل على وقت إنشاء الجلسة |
getid () | احصل على معرف الجلسة |
getLastAccatedTime () | احصل على وقت الانتهاء من الطلب الأخير |
getServletContext () | احصل على servletcontext التي تنتمي إليها الجلسة الحالية |
getMaxInactiveInterval ()/setMaxInactiveInterval (الفاصل: int) | احصل على أقصى فاصل وصول بين تعيين الجلسة |
getAttribute (الاسم: سلسلة) /setAttribute (الاسم: السلسلة ، القيمة: كائن) | احصل على خصائص نطاق الجلسة وتعيينها |
lexoveAttribute (الاسم: سلسلة) | خصائص نطاق جلسة واضحة |
إبطال () | إبطال الجلسة والتراجع عن أي كائن ملزم لهذه الجلسة |
Clustersession: يسرد مواصفات واجهة الجلسة ضمن نشر المجموعة.
الجدول 3 الواجهة الواجهة clustersession
طريقة | يصف |
isprimarysession () | هل هي الجلسة الرئيسية للمجموعة؟ |
setPrimarysession (Boolean PrimarySession) | قم بإعداد جلسة الكتلة الرئيسية |
المعايير: تنفيذ جلسة HTTP القياسية ، ستستخدم هذه المقالة هذا التنفيذ كمثال.
عند نشر مجموعة Tomcat ، يجب أن تتم مزامنة حالة جلسة كل عقدة في المجموعة.
REPLICATESSESSERESS: في كل مرة ، يتم مزامنة كائن الجلسة بأكمله مع العقد الأخرى في الكتلة ، ثم العقد الأخرى ثم تحديث كائن الجلسة بأكمله. هذا التنفيذ بسيط نسبيًا ومريحًا ، ولكنه سيؤدي إلى نقل كمية كبيرة من المعلومات غير الصالحة.
Deltasession: مزامنة الخصائص المعدلة بشكل تدريجي في الجلسة. نظرًا لأن هذه الطريقة تدريجية ، فإنها ستقلل بشكل كبير من النفقات العامة لشبكة I/O ، لكن التنفيذ سيكون أكثر تعقيدًا لأنه يتضمن إدارة عمليات تشغيل سمة الجلسة.
مدير الجلسة
يحدد Tomcat داخليًا واجهة المدير لصياغة مواصفات الواجهة لمدير الجلسة.
الشكل 2 الشكل 2 نظام الميراث من مدير الجلسة
سنصف المحتوى المقابل في الشكل 2 واحد تلو الآخر أدناه:
المدير: Tomcat لمواصفات الواجهة التي حددها مدير الجلسة ، وقد أدرج الشكل 2 الأساليب الرئيسية المحددة في واجهة المدير ، ويصف الجدول 4 دور هذه الأساليب بالتفصيل.
الجدول 4 الواجهة الواجهة المدير
طريقة | يصف |
getContainer ()/setContainer (حاوية: حاوية) | احصل على أو تعيين الحاوية المرتبطة بمدير الجلسة ، وعموما حاوية سياق |
GetDistributable ()/setDistributible (قابلة للتوزيع: منطقية) | احصل على أو تعيين ما إذا كان مدير الجلسة يدعم توزيعه |
getMaxInactiveInterval ()/setMaxInactiveInterval (الفاصل: int) | احصل على أو تعيين الحد الأقصى للفاصل الزمني غير النشط للجلسة التي أنشأها مدير الجلسة |
getSessionIdLength ()/setSessionIdLength (idlength: int) | احصل على أو تعيين طول معرف الجلسة الذي أنشأه مدير الجلسة |
GetSessionCounter ()/setSessionCounter (SessionCounter: Long) | احصل على أو تعيين إجمالي عدد الجلسات التي أنشأها مدير الجلسة |
getMaxactive ()/setMaxActive (maxave: int) | احصل على أو تعيين الحد الأقصى لعدد الجلسات التي تم تنشيطها حاليًا |
GetActactionStions () | احصل على جميع الجلسات التي يتم تنشيطها حاليًا |
GetExpiredSessions ()/setExpiredSessions (EpiriviredSessions: Long) | احصل على أو تعيين عدد الجلسات منتهية الصلاحية حاليًا |
getRejectedSessions ()/setRejectedSessions (DesjectedSessions: int) | الحصول على أو تعيين عدد الجلسات التي تم رفضها من الإنشاء |
getSessionMaxAlivetime ()/setSessionMaxAlivetime (SessionMaxAlivetime: int) | يحصل أو يحدد الحد الأقصى مدة النشاط في جلسة منتهية الصلاحية |
getSessionaVerAgeAliveTime ()/setSessionaVerAgeAliveTime (SessionAverageAliveTime: int) | احصل على أو تعيين متوسط مدة النشاط لجلسة منتهية الصلاحية |
إضافة (جلسة: جلسة)/إزالة (الجلسة: الجلسة) | إضافة أو حذف جلسات نشطة إلى مدير الجلسة |
تغييرات (الجلسة: الجلسة) | قم بتعيين معرف جلسة عشوائي تم إنشاؤه حديثًا للجلسة |
CreateSession (SessionId: سلسلة) | قم بإنشاء جلسة جديدة بناءً على تكوين السمة الافتراضي لمدير الجلسة |
FindSession (معرف: سلسلة) | إرجاع الجلسة مع العلامة الفريدة لمعلمة SessionId |
FindSessions () | يعيد جميع الأنشطة التي يديرها مدير الجلسة |
تحميل ()/تفريغ () | جلسة تحميل من آلية الثبات أو جلسة الكتابة إلى آلية الثبات |
BackgroundProcess () | يتم تعريف واجهة الحاويات على أنها تنفيذ عمل محدد لمعالجة الحاويات في الخلفية. |
Managerbase : يتضمن فئة مجردة يتم تنفيذها بشكل شائع من خلال واجهة المدير. جميع مديري الجلسة ورثوا من Managerbase.
ClusterManager : أضاف بعض الواجهات تحت نشر المجموعة بناءً على واجهة المدير.
PerferenceManagerBase: يوفر تنفيذًا أساسيًا لاستمرار الجلسة.
PerferenceManager: موروث من PerferenceManagerBase ، يمكن استخدامه عن طريق تكوين عنصر <store> في server.xml. يمكن لـ PercistentManager نسخة احتياطية من معلومات الجلسة في الذاكرة إلى ملف أو قاعدة بيانات. عند احتياطي كائن جلسة ، يتم نسخ كائن الجلسة إلى الذاكرة (ملف أو قاعدة بيانات) ، بينما يبقى الكائن الأصلي في الذاكرة. لذلك ، حتى إذا سقط الخادم ، لا يزال من الممكن استرداد كائن الجلسة النشط من الذاكرة. إذا تجاوز كائن الجلسة النشطة الحد الأعلى أو أن كائن الجلسة يكون خاملاً لفترة طويلة ، فسيتم تبديل الجلسة إلى الذاكرة لحفظ مساحة الذاكرة.
StandardManager: لا حاجة لتكوين عنصر <store>. . عند إعادة تشغيل Tomcat أو يتم تحميل التطبيق ، ستعيد Tomcat الجلسة في الملف إلى الذاكرة. إذا تم إنهاء الخادم فجأة ، فستفقد جميع الجلسات لأن StandardManager ليس لديها فرصة لتنفيذ معالجة حفظ.
ClusterManagerBase: يوفر تنفيذ إدارة الكتلة للجلسة.
Deltamanager: ورث من ClusterManagerBase. مدير الجلسة هذا هو المدير الافتراضي لـ Tomcat تحت نشر المجموعة.
BackupManager: لا يرث ClusterManagerBase ، ولكنه ينفذ مباشرة واجهة ClusterManager. إنه مدير جلسة اختياري لـ Tomcat تحت نشر المجموعة. يمكن لجميع العقد في الكتلة الوصول إلى عقدة النسخ الاحتياطي هذه لتحقيق تأثير النسخ الاحتياطي للجلسة في الكتلة.
من أجل البساطة ، تستخدم هذه المقالة StandardManager كمثال لشرح إدارة الجلسة. StandardManager هو مكون طفل في StandardContext ، ويستخدم لإدارة إنشاء وصيانة جميع جلسات السياق الحالي. إذا كان عليك قراءة أو على دراية بمحتوى المقالة "تحليل رمز المصدر Tomcat - إدارة دورة الحياة" ، فستعلم أنه عند إطلاق StandardContext رسميًا ، تسمى طريقة StandardContext (انظر القائمة 1) ، StandardContext سوف لا يزال يبدأ StandardManager.
كود قائمة 1
Override محمية Void Void startInternal () يلقي LifeCycleException {// الكود غير المرتبط بإدارة الجلسة // الحصول على المدير المجمع contextManager = null ؛ && distributed) {try {contextManager = getCluster (). createManager (getName () ؛ StandardManager () ؛ دع المجموعة تعرف أن هناك سياقًا يتم توزيعه // أن لديه مديرها الخاص GetCluster (). registerManager (مدير) ؛ if (manager! = null) && (manager extreal of life)) {(دورة الحياة) getManager (). start () ؛ .error ("مدير الخطأ. start ()" ، هـ) ؛
من القائمة 1 ، يمكنك أن ترى أن خطوات التنفيذ المشاركة في إدارة الجلسة في طريقة startinternal في StandardContext هي كما يلي:
إنشاء StandardManager.
إذا جمعت Tomcat بين Apache للنشر الموزع ، فسيتم تسجيل StandardManager الحالي في المجموعة ؛
بدء StandardManager ؛
يتم استخدام طريقة البدء في StandardManager لبدء StandardManager ، ويتم عرض التنفيذ في القائمة 2 من الكود.
كود قائمة 2
Override Public Synchronized Void Start () يلقي LifeCycleException {// حذف الكود للتحقق من الحالة if (state.equals (lifecyclestate.new)) {init () ؛ ! } if (state.equals (lifecyclestate.failed) || state.equals (lifecyclestate.must_stop)) القيام بما يفترض بهم.
من القائمة 2 ، يمكننا أن نرى أن خطوات بدء تشغيل StandardManager هي كما يلي:
استدعاء طريقة init لتهيئة StandardManager ؛
استدعاء طريقة البدء لبدء StandardManager ؛
تهيئة StandardManager
بعد التحليل أعلاه ، نعلم أن الخطوة الأولى لبدء StandardManager هي استدعاء طريقة init لدورة حياة الفئة الأصل. لرعاية initinternal من StandardManager. لا يقوم StandardManager نفسه بتنفيذ طريقة initinternal ، ولكن قاعدة Managerbase من فئة الوالدين StandardManager تنفذ هذه الطريقة ، انظر القائمة 3 لتنفيذها.
كود قائمة 3
Override proid initinternal () يلقي LifeCycleexception {super.initinternal () ؛
قائمة القراءة من الرمز 3 ، نلخص خطوات تنفيذ طريقة مبدئي Managerbase:
قم بتسجيل الحاوية نفسها ، The StandardManager ، إلى JMX (راجع المقالة "تحليل رمز المصدر Tomcat - إدارة دورة الحياة" لتنفيذ طريقة Lifecyclembeanbase) ؛
احصل على tomcat الحالي من حاوية الأصل StandardContext وقم بتعيينه على خاصية Boolean of ManagerBase Distributable ؛
استدعاء طريقة getRandomBytes للحصول على مجموعة بايت عشوائية من ملف الرقم العشوائي /dev /urandom.
ملاحظة: لن يتم استخدام مجموعة البايت العشوائية التي تم إنشاؤها عن طريق استدعاء GetRandomBytes هنا.
دعنا نقرأ تنفيذ التعليمات البرمجية لطريقة getRandomBytes بالتفصيل ، انظر القائمة 4 من الرمز.
كود قائمة 4
void getRandomBytes (بايت بايت []) {// إنشاء مجموعة بايت تحتوي على معرف جلسة إذا (devromsource! = null && rolants == null) {set randomfile (devrodomsource) ؛ int len = randomis.read (bytes) ؛ catch (استثناء) {// تجاهل} devromsource = null ؛ ) .extbytes (بايت) ؛
setRandomFile في القائمة 4
يتم استخدام الطرق (انظر القائمة 5 للرمز) للحصول على مجموعة عشوائية من البايتات من ملف الرقم العشوائي /dev /urandom.
قائمة الكود 5
public void setRandomFile (سلسلة S) {// كاختراق ، يمكنك استخدام ملف ثابت - وإنشاء نفس معرفات الجلسة (جيدة لتصحيح الأخطاء الغريبة) if (globals.is_se cority_enabled) TarilegedSetRandomFile) ؛ readlong () ؛ ) {try {randomis.close ()
تقوم طريقة setRandomFile في القائمة 4 (انظر القائمة 6) بإنشاء مثيل Java.security.SecureRandom من خلال التفكير ، ويستخدم هذا المثيل لإنشاء مجموعة من البايتات العشوائية.
كود قائمة 6
getRandom العشوائي العام () {if (this.random == null) {// احسب بذور الأرقام العشوائية الجديدة = system.currentTimeMillis () ؛ ) ؛ // بذرة فئة جديدة من الأرقام العشوائية <؟> class.forname (عشوائي) ؛ e) {// تعود إلى log.error sm.getString ("managerbase.random" ، e) ؛ (بذرة)) ؛ ) + " + (T2-T1) ؛
وفقًا للتحليل أعلاه ، ينفذ تهيئة StandardManager بشكل أساسي طريقة BITINTERNAL لقاعدة المدير.
بدء StandardManager
يتم استخدام استدعاء طريقة startinternal لـ StandardManager لبدء StandardManager ، انظر القائمة 7.
كود قائمة 7
Override محمية Void startInternal () يلقي LifeCycleexception {// قوة المولد العشوائي إذا (log.isdebugenable D () log.debug ("القوة العشوائية للبدء") ؛ isDebugenabled ()) log.debug ("التهيئة العشوائية القوية") ؛ managerload ") ، t) ؛} setState (LifecyClestate.starting) ؛}
من القائمة 7 ، يمكننا أن نرى أن خطوات بدء تشغيل StandardManager هي كما يلي:
الخطوة 1: استدعاء طريقة generatesessionid (انظر القائمة 8) لإنشاء معرف جلسة جديد ؛
كود قائمة 8
سلسلة متزامنة محمية () {byte random [] byte [16] ؛ {int resultlenbytes = 0 ؛ ؛ عشوائي [J] & 0x0F) ؛ ؛ JVMROUTE! ::::::::::::::::::::::::: :::::::::::::::::::::: ::::::::::::::::::::::::: :::::::::::::::::::::: ::::::::::::::::::::::::
الخطوة 2 تعمل على تحميل معلومات الجلسة المستمرة. لماذا يجب أن تستمر الجلسة؟ نظرًا لأن جميع الجلسات يتم الحفاظ عليها في concurrenthashmap في StandardManager ، فإن إعادة تشغيل الخادم أو التوقف عن العمل تتسبب في فقدان هذه الجلسات. دعنا نلقي نظرة على تنفيذ طريقة تحميل StandardManager ، انظر القائمة 9 من التعليمات البرمجية.
كود قائمة 9
public void load () classnotfoundexception ، ioexception {if (securityutil.ispackageprotectionEbling () استثناء من ClassNotFoundException) {throw (classnotfoundException) استثناء ؛ ؛
إذا كانت هناك حاجة إلى تشغيل آلية الأمان وتم تشغيل وضع حماية الحزمة ، فسيتم تحميل الجلسة المستمرة عن طريق إنشاء مميزة ، يتم تنفيذها كما هو موضح في القائمة 10 من الكود.
قائمة 10
الطبقة الخاصة تنفذ DirectionedException <Doid> {termilegeddoload ()
من القائمة 10 ، يمكننا أن نرى أن الطريقة المسؤولة بالفعل عن التحميل هي doload. لذلك نحتاج فقط إلى النظر في تنفيذ Doload ، انظر القائمة 11 من الكود.
قائمة 11
doload void المحمي () يلقي classnotfoundexception ، ioexception {if (log.isdebugenabled () log.debug ( إلى المسار المحدد ، إذا كان هناك ملف ملف =) ؛ FilePhstream = NULL ؛ حاوية! = null) إنشاء دفق إدخال كائن مخصص لعملية تحميل الفئة ") ؛ OIS = جديد customObjectInputStream (BIS ، ClassLoader) ؛} آخر {if (log.isdebugenabled ()) log.debug (" إنشاء دفق إدخال OB ject القياسي ") ؛ ois = ObjectInputStream (BIS) ؛ .getString ("standardManager.load .ioe" ، e) ، e) ؛ null) {try {bis. ReadObject () ؛ {SETTARDERSENTSERSESTERSSATOR ) {إذا كانت الجلسة غير صالحة ، // Session Session. GetString ("standardManager.loading.cnfe" ، هـ) ؛ . ois.close () ؛ Debug ("الانتهاء: استمرت Loa Ding جلسات") ؛
من القائمة 11 ، راجع خطوات تنفيذ طريقة Doload StandardManager على النحو التالي:
مسح معلومات الجلسة التي تحتفظ بها ذاكرة التخزين المؤقت للجلسات ؛
استدعاء طريقة الملف لإرجاع الملف المستمر للجلسة ضمن السياق الحالي ، مثل: d: /Workspace/tomcat7.0/work/catalina/localhost/host-manager/sessions.ser ؛
افتح دفق الإدخال للملف المستمر للجلسة وقم بتغليفه على أنه CustomEbectInputStream ؛
اقرأ عدد الجلسات المستمرة من الملف الثابت للجلسة ، ثم اقرأ معلومات الجلسة واحدة تلو الأخرى ووضعها في ذاكرة التخزين المؤقت للجلسات.
في هذه المرحلة ، فإن مقدمة لإطلاق StandardManager هنا.