1: مقدمة في جلسة الربيع
1. مقدمة
لطالما كانت الجلسة مشكلة صعبة نحتاج إلى حلها عند القيام بالمجموعات. في الماضي ، يمكننا حلها من حاويات Servlet ، مثل مديرة Tomcat-Redis-Sentse و Memcached-Sent-Canager التي توفرها حاوية Servlet Open المصدر.
أو قم بعمل ip_hash من خلال موازنة التحميل مثل Nginx والتوجيه إلى خادم معين ..
لكن كلتا الطريقتين لها عيوب.
الربيع هو مشروع تحت الربيع. يحل محل HTTPSESSERESS التي تنفذها حاوية servlet مع جلسة الربيع ، مع التركيز على حل مشاكل إدارة الجلسة. يمكن دمجها في تطبيقاتنا بسرعة وسلاسة.
2. وظائف الدعم
1) تخزين الجلسات بسهولة في حاويات تخزين الطرف الثالث. يوفر Framework Redis و JVM Map و Mongo و Gemfire و Hazelcast و JDBC وحاويات أخرى لتخزين الجلسات.
2) نفس المتصفح ونفس الموقع يدعم مشاكل الجلسة المتعددة.
3) Restfulapi ، لا يعتمد على ملفات تعريف الارتباط. يمكن تمرير jessionid من خلال الرأس
4) الجمع بين WebSocket و Rublic Jession لمزامنة إدارة دورة الحياة.
3. طريقة التكامل
طريقة التكامل بسيطة للغاية ، فقط انظر إلى العينات والدليل على الموقع الرسمي. http://docs.spring.io/spring-session/docs/1.3.0.release/reference/html5/
ينقسم بشكل أساسي إلى خطوات التكامل التالية:
1) إدخال حزمة جرة التبعية
2) طريقة التعليق التوضيحي أو طريقة XML لتكوين طرق التخزين لحاويات تخزين محددة ، مثل طريقة تكوين XML الخاصة بـ Redis
<السياق: التعليق التوضيحي-config/>/** تهيئة جميع الاستعدادات للجلوس الربيعي ووضع springsessionfilter في IOC **/<beanclass = "org.springframework.session.data.redis.config.annotation.web.http.redishttsentession <beanclass = "org.springframework.data.redis.connection.lettuce.lettuceConnectionFactory"/>
3) تكوين web.xml في طريقة XML ، تكوين SpringsessionFilter في سلسلة مرشح
<Ivilter> <ilter-name> springsessionRepositoryFilter </filter-name> <lipter-class> org.springframework.web.filter.delegatingfilterproxy </filter-class> </filter> <filter mapping> <Url-pattern>/*</url-pattern> <spatcher> طلب </dispatcher> <spatcher> خطأ </dispatcher> </filter mapping>
اثنان: التحليل الداخلي لإطار العمل الربيعي
1. إطار الرسم التخطيطي للهيكل التجريدي عالي المستوى
2.SPRING-SESSET REWRETS Servlet request و Redis Storage ذات الصلة
المبدأ العام لجلسة الربيع يحل بسلاسة محل طلب خادم التطبيق هو:
1. تخصيص مرشح وتنفيذ طريقة dofilter
2. ورث فئات httpservletrequestwrapper و httpservletresponsewrapper ، وتجاوز Getessession والطرق الأخرى ذات الصلة (تسمى فئة تشغيل حاوية تخزين الجلسة ذات الصلة في هذه الطرق).
3. في خطوة Dofilter في الخطوة الأولى ، فئات الطلب والاستجابة الجديدة في الخطوة الثانية. وتمريرها بشكل منفصل إلى سلسلة المرشح
4. قم بتكوين المرشح إلى الموضع الأول لسلسلة المرشح
/** هذه الفئة هي رمز المصدر 1.30 للجلس الربيعي ، وهي أيضًا الفئة الرئيسية التي تنفذ الخطوات الأولى إلى الثالثة أعلاه **/SessionRepositoryFilter <s تمتد Expiringsession> على مقربة من SessionRepositistoristoristoristoristoristore ، mongodb ، و genfire و genfire all interface ** interposit <settoriposit <s interposit <s reposposit. خاص servletContext servletContext ؛ /** واجهة توصيل SessionID. يأتي Rump Ressess حاليًا مع فئتين للتنفيذ 1.CoOkie طريقة: CookieHttpSessionStrategy 2.http طريقة رأس: headerhttpessionstrategy بالطبع ، يمكننا أيضًا تخصيص طرق أخرى. **/ private multiHttpessionStrategy httpsessiontrategy = cookiehttpsessiontrategy () جديد ؛ SessionRepositoryFilter (SessionRepository <S> SessionRepository) {if (SessionRepository == NULL) {رمي جديد غير alfictRgumentException ("لا يمكن أن يكون SessionRepository فارغًا") ؛ } this.sessionRepository = SessionRepository ؛ } public void sethttpessionStrategy (httpsessionstrategy httpessiontrategy) {if (httpessionstrategy == null) {رمي غير alustalalaRgumentException ("httpessionstrategy لاغال") ؛ } /** من خلال مقدمة وظيفة الركاب في الربيع السابقة ، نعلم أن جلسة الربيع يمكن أن تدعم جلسات متعددة في متصفح واحد ، يتم تحقيقه من خلال multiHttsPessionStrategyAdapter. يحتوي كل متصفح على SessionId ، لكن هذا SessionId يحتوي على متعددة الأسماء المستعارة (وفقًا لعلامة التبويب المتصفح). على سبيل المثال: الاسم المستعار 1 sessionid alias 2 SessionId ... ويتم تمرير هذا الاسم المستعار عبر عنوان URL ، وهو مبدأ جلسات متعددة من قبل متصفح واحد **/ that.httpessionstrategy = multiHttPessionStrategyAdapter (httpsessiontrategy) ؛ } public void sethttpessionStrategy (multiHttpSessionStrategy HttpSessionStrategy) {if (httpessionstrategy == null) {رمي جديد غير شرعي alfictException ( } this.httpsessionStrategy = httpsessionStrategy ؛ } /** هذه الطريقة مكافئة لإعادة كتابة Dofilter ، لكن جلسة الربيع لها طبقة أخرى من التغليف. قم بإنشاء طلب مخصص واستجابة في هذه الطريقة ، ثم تمريره إلى مرشح سلسلة المرشح **/ Override المحمي Dofilterinternal (طلب httpservletrequest ، httpservletresponse ، filterchain filterchain) servletexception ، ioexception {request.setatresttribute (session_repository_attr ، /** servletrequest إعادة كتابة بحلول ربيع. يرث هذا الفئة httpservletrequestwrapper **/ SessionRepositoryRequestWrapper rapphrequest = new SessionRepositoryRequestWrapper (طلب ، استجابة ، this.servletcontext) ؛ SessionRepositoryResponseWrapper RapperResponse = SessionRepositoryResponseWrapper (RappedRequest ، الاستجابة) ؛ httpservletrequest strategyRequest = this.httpessionstrategy.wraprequest (rapphrequest ، rappresponse) ؛ httpservletResponse strategyResponse = this.httpessionstrategy .wrapresponse (rappedRequest ، RappedResponse) ؛ حاول { /** تمرير الطلب المخصص والاستجابة للسلسلة. تخيل لو أن Fring-Sentfessfilter موجود في أول سلسلة مرشح ، فهل هي المرشحات اللاحقة ، وكذلك الطلب والاستجابة التي تم الحصول عليها عن طريق الوصول إلى طبقة التحكم الأخيرة ، نحن نقوم بتخصيصها؟ **/ filterchain.dofilter (strategyRequest ، strategyResponse) ؛ } أخيرًا {rppredRequest.Commitsession () ؛ }} public void setServletContext (servletContext servletContext) {this.servletContext = servletContext ؛ } / ** هذه هي الفئة المعاد كتابة من Servlet Response* / Private Class SessionRepositoryResPonseWrapper تمتد OnCommatedResponseWrapper {Private SessionRepositoryRequestWrapper request ؛ SessionRepositoryResponseWrapper (طلب SessionRepositoryRequestWrapper ، استجابة httpservletresponse) {super (استجابة) ؛ إذا (request == null) {رمي New UntervalAlArgumentException ("لا يمكن أن يكون الطلب فارغًا") ؛ } this.request = request ؛ } /** هذه الخطوة هي استمرار الجلسة إلى حاوية التخزين. قد ندعو طريقة التشغيل للجلسة عدة مرات في طبقة التحكم. إذا استمرت كل عملية للجلسة في حاوية التخزين ، فمن المؤكد أن يكون لها تأثير في الأداء. على سبيل المثال ، Redis ، حتى نتمكن من تنفيذ طبقة التحكم بأكملها ، وإرجاع الاستجابة المعلومات إلى المتصفح ، وستظل الجلسة فقط عندما تُرجع الاستجابة المعلومات إلى المتصفح. **/ Override محمية void onResponsecmommitt () {this.request.commitsession () ؛ }} /** إن فئة إعادة كتابة الطلب من ربيع الجماعة هي تقريبًا أهم فئة إعادة كتابة. أعادت كتابة أساليب مثل GetSession و Session and Other Methods بالإضافة إلى الفصول */ SessionRepositoryRequestWrapper في الفصول الدراسية النهائية الخاصة. QuartedSessionInvalidated المنطقي الخاص ؛ استجابة HTTPSERVERSPONSE النهائية الخاصة ؛ Final Final ServletContext ServletContext ؛ SessionRepositoryRequestWrapper (طلب httpservletrequest ، استجابة httpservletresponse ، servletContext servletcontext) {super (request) ؛ this.reSponse = الاستجابة ؛ this.servletContext = servletContext ؛ } /** * يستخدم httpsessionstrategy لكتابة معرف الجلسة للاستجابة و * يستمر في الجلسة. */ private void commitsession () {httpsessionWrapper rappedsession = getCurrentsession () ؛ إذا انتهت صلاحية الجلسة {// الجلسة ، حذف ملفات تعريف الارتباط أو الرأس إذا (isInvalIdateClientsessession ()) }} else {s session = rappedsession.getSession () ؛ SessionRepositoryFilter.This.SessionRepository.save (Session) ؛ if (! isRequestessessionIdvalid () ||! session.getId (). متساوٍ (getRequestessessionId ())) {// اكتب ملف تعريف الارتباط أو الرأس إلى المتصفح لإنقاذ SessionRepositoryFilter.his.htpsessiontrategy.onnewsession (Sent.S. هذا. }}} suppressWarnings ("Unchected") httpsessionwrapper getCurrentsession () {return (httpsessionwrapper) getAttribute (current_session_attr) ؛ } private void setCurrentsession (httpsessionwrapper currentsession) {if (currentsession == null) {removeAttribute (current_session_attr) ؛ } آخر {setAttribute (current_session_attr ، currentsession) ؛ }} suppressWarnings ("غير مستخدمة") سلسلة متغيرة () {httpsession session = getSession (false) ؛ if (Session == NULL) {رمي New FalvealStateException ("لا يمكن تغيير معرف الجلسة. لا توجد جلسة مرتبطة بهذا الطلب.") ؛ } // احصل على سمات الجلسة بفارغ الصبر في حالة تنفيذ الأحمال الكسول تحميلها خريطة <string ، object> attrs = new hashmap <string ، Object> () ؛ التعداد <string> iattrnames = session.getAttributEnames () ؛ بينما (iattrnames.hasmoreElements ()) {string attrname = iattrnames.nextElement () ؛ قيمة الكائن = session.getAttribute (attrname) ؛ attrs.put (attrname ، value) ؛ } SessionRepositoryFilter.Tis.SessionRepository.Delete (Session.getId ()) ؛ httpsessionWrapper Original = getCurrentsession () ؛ setCurrentsession (NULL) ؛ httpsessionwrapper newsession = getSession () ؛ Original.SetSession (newsession.getSession ()) ؛ newsession.setMaxInaCtiveInterval (session.getMaxInaCtuctionInterval ()) ؛ لـ (map.entry <string ، object> attr: attrs.entryset ()) {String attrname = attr.getKey () ؛ الكائن attrvalue = attr.getValue () ؛ newsession.setattribute (attrname ، attrvalue) ؛ } return newsession.getId () ؛ } // تحديد ما إذا كانت الجلسة صالحة override boolean isRequedSessionIdvalid () {if (this.requestessionIdvalid == null) {String SessionId = getRequestessionId () ؛ S Session = SessionId == NULL؟ null: getSession (SessionId) ؛ إرجاع isRequestessessionIdvalid (جلسة) ؛ } إرجاع هذا. } boolean private isRequestessionIdvalid (s session) {if (this.requestessessionIdvalid == null) {this.requestessionidvalid = session! = null ؛ } إرجاع هذا. } isinvalidateClients isinvalidateClients {return getCurrentsession () == null && this.requestessionInvalidated ؛ } getessession s private (SettingId) {// الحصول على جلسة من حاوية تخزين الجلسة استنادًا إلى جلسة SessionId = SessionRepositoryFilter.This.SessionRepository .getSession (SessionId) ؛ if (الجلسة == null) {return null ؛ } // قم بتعيين آخر وقت وصول للجلسة لمنع الجلسة من Session.SetLastAccatedTime (System.CurrentTimeMillis ()) ؛ جلسة العودة ؛ } /** هل هذه الطريقة مألوفة جدًا؟ هناك أيضًا getsession () أدناه لتكون أكثر دراية. هذا صحيح ، ما عليك سوى إعادة طريقة الجلسة هنا **/Override Public HttpsessionWrapper Getession (Boolean Create) {// Get Fastly Get ، والتي يمكن فهمها على أنها علاقة بين ذاكرة التخزين المؤقت من المستوى الأول وذاكرة التخزين المؤقت من المستوى الثاني httpsessionwrapper currentsessession = getCurrentrentsess () ؛) ؛ if (currentsession! = null) {return currentsession ؛ } // get sessionId من httpsessiontret requestedSessionId = getRequedSessionId () ؛ if (requiredSessionId! = null && getAttribute (invalid_session_id_attr) == null) {// الحصول على جلسة من حاوية التخزين وتعيين جلسة التهيئة الحالية = getSession (requestedSessionId) ؛ if (الجلسة! = null) {this.requestessionIdvalid = true ؛ currentsession = جديد httpsessionwrapper (الجلسة ، getServletContext ()) ؛ currentsession.setnew (false) ؛ setCurrentsession (التيارات) ؛ يعود التيارات ؛ } else {if (session_logger.isdebugenabled ()) {session_logger.debug ("لا توجد جلسة موجودة بواسطة ID: نتيجة التخزين المؤقت لـ GetSession (false) لهذا httpservletrequest.") ؛ } setAttribute (invalid_session_id_attr ، "true") ؛ }} if (! create) {return null ؛ } if (session_logger.isdebugenabled ()) {session_logger.debug ("تم إنشاء جلسة جديدة. لمساعدتك على استكشاف الأخطاء وإصلاحها حيث تم إنشاء الجلسة ، قدمنا stacktrace (هذا ليس خطأً). يمكنك منع ذلك من خلال تعطيل Debug Logging لـ" + session_logger_name ، } // إذا كان المتصفح أو زائر HTTP آخر يصل إلى الخادم لأول مرة ، فقم بإنشاء جلسة جلسة جديدة له = SessionRepositoryFilter.This.SessionRepository.Createsession () ؛ Session.setLastAccatedTime (System.CurrentTimeMillis ()) ؛ currentsession = جديد httpsessionwrapper (الجلسة ، getServletContext ()) ؛ setCurrentsession (التيارات) ؛ يعود التيارات ؛ } Override public servletContext getServletContext () {if (this.servletcontext! = null) {return this.servletcontext ؛ } // servlet 3.0+ return Super.getServletContext () ؛ } Override public httpsessionwrapper getSession () {return getSession (true) ؛ } Override public string getRequestessionId () {return sessionRepositoryFilter.This.httpessionStrategy. } / ** rewrite فئة من httpsession* / private final class httpsessionwrapper يمتد ExpiringsessionHttpsession <s> {httpsessionwrapper (جلسة s ، servletcontxt servletcontext) {super (الجلسة ، servletcontext) ؛ } Override public void inviridaide () {super.invalidate () ؛ SessionRepositoryRequestWrapper.This.requestessionInvalidated = true ؛ setCurrentsession (NULL) ؛ SessionRepositoryfilter.This.SessionRepository.Delete (getId ()) ؛ }}}}لخص
ما سبق هو كل محتوى هذه المقالة حول إدخال جلسة الربيع وتحليل رمز المصدر لمبادئ التنفيذ. آمل أن يكون ذلك مفيدًا للجميع. يمكن للأصدقاء المهتمين الاستمرار في الرجوع إلى الموضوعات الأخرى ذات الصلة على هذا الموقع. إذا كانت هناك أي أوجه قصور ، فيرجى ترك رسالة لإشارةها!