يتم استخدام ذاكرة التخزين المؤقت لـ Springboot في العمل ، وهو مناسب تمامًا للاستخدام. يقدم مباشرة حزم تبعية ذاكرة التخزين المؤقت مثل redis أو ehcache وحزم تبعية المبتدئين من ذاكرة التخزين المؤقت ذات الصلة ، ثم تضيف شرح enableCaching إلى فئة بدء التشغيل ، ثم يمكنك استخدام @cacheevict لاستخدام وحذف التخزين المؤقت عند الحاجة. هذا بسيط جدا للاستخدام. أعتقد أن أولئك الذين استخدموا ذاكرة التخزين المؤقت لـ Springboot سيلعبون ، لذلك لن أقول المزيد هنا. العيب الوحيد هو أن Springboot يستخدم تكامل المكونات الإضافية. على الرغم من أنها مريحة للغاية للاستخدام ، عند دمج ehcache ، فإنك تستخدم ehcache ، وعند دمج redis ، يمكنك استخدام redis. إذا كنت ترغب في استخدام كلاهما معًا ، فسيتم استخدام ehcache كذاكرة التخزين المؤقت للمستوى المحلي 1 ويتم استخدام Redis كذاكرة التخزين المؤقت من المستوى 2 المتكامل. على حد علمي ، من المستحيل تحقيق الطريقة الافتراضية (إذا كان هناك خبير يمكنه تنفيذه ، فيرجى إعطائي بعض النصائح). بعد كل شيء ، تتطلب العديد من الخدمات نشر متعدد النقاط. إذا اخترت ehcache وحدها ، فيمكنك إدراك ذاكرة التخزين المؤقت المحلية جيدًا. ومع ذلك ، إذا قمت بمشاركة ذاكرة التخزين المؤقت بين الآلات المتعددة ، فسوف يستغرق الأمر وقتًا لتوضيح المتاعب. إذا اخترت ذاكرة التخزين المؤقت Redis المركزية ، لأنه يتعين عليك الذهاب إلى الشبكة في كل مرة تحصل فيها على البيانات ، فسوف تشعر دائمًا أن الأداء لن يكون جيدًا جدًا. يناقش هذا الموضوع بشكل أساسي كيفية دمج Ehcache و Redis بسلاسة كخزائن من المستوى الأول والثاني استنادًا إلى Springboot ، وتحقيق مزامنة ذاكرة التخزين المؤقت.
من أجل عدم غزو طريقة ذاكرة التخزين المؤقت الأصلية لـ Springboot ، قمت بتعريف اثنين من التعليقات التوضيحية المتعلقة بالتخزين المؤقت هنا ، على النحو التالي
target ({elementType.method}) retention (attreentionpolicy.runtime) public interface cachable {string value () افتراضي "" ؛ مفتاح السلسلة () الافتراضي "" ؛ // فئة نوع الفئة العامة <؟> type () استثناء الافتراضي. } target ({elementType.method}) @repinetypolicy.runtime) public interface cacheevict {string value () افتراضي "" ؛ مفتاح السلسلة () الافتراضي "" ؛ }نظرًا لأن التعليقات الروحية المذكورة أعلاه هما في الأساس نفس التعليقات التوضيحية المخزنة مؤقتًا في الربيع ، ولكن تتم إزالة بعض السمات المستخدمة بشكل غير متكرر. عند الحديث عن هذا ، أتساءل عما إذا كان أي أصدقاء قد لاحظوا أنه عندما تستخدم Redis Cache وحده في Springboot ، فإن سمات القيمة المشروحة بواسطة cacheable و cacheevict تصبح في الواقع مفتاح قيمة ZSET في redis ، ولا تزال ZSET فارغة ، مثل cachable (value = "cache1" ، key = "key1"). في ظل الظروف العادية ، يجب أن تظهر Cache1 -> MAP (key1 ، value1) في Redis ، حيث يتم استخدام Cache1 كاسم ذاكرة التخزين المؤقت ، خريطة كقيمة ذاكرة التخزين المؤقت ، والمفتاح كمفتاح في الخريطة ، والتي يمكن أن تعزل ذاكرة التخزين المؤقت بشكل فعال تحت أسماء ذاكرة التخزين المؤقت المختلفة. ولكن في الواقع ، هناك Cache1 -> فارغ (ZSET) و Key1 -> value1 ، زوجان من القيمة الرئيسية المستقلة. وجدت التجربة أن ذاكرة التخزين المؤقت تحت أسماء ذاكرة التخزين المؤقت المختلفة تتم مشاركتها تمامًا. إذا كنت مهتمًا ، فيمكنك تجربته. وهذا يعني أن سمة القيمة هذه هي في الواقع زخرفة ، ويضمن تفرد المفتاح فقط السمة الرئيسية. لا يمكنني إلا أن أعتقد أن هذا خطأ في تنفيذ ذاكرة التخزين المؤقت لربيع ، أو تم تصميمه على وجه التحديد (إذا كنت تعرف السبب ، فيرجى إعطائي بعض النصائح).
العودة إلى الموضوع ، مع التعليقات التوضيحية ، هناك أيضًا فئة معالجة التعليقات التوضيحية. هنا أستخدم قسم AOP للاعتراض ، والتنفيذ الأصلي متشابه بالفعل. فئة معالجة القسم هي كما يلي:
استيراد com.xuanwu.apaas.core.multicache.annotation.cacheevict ؛ استيراد com.xuanwu.apaas.core.multicache.annotation.cachable ؛ استيراد com.xuanwu.apaas.core.utils.jsonutil ؛ استيراد org.apache.commons.lang3.StringUtils ؛ استيراد org.aspectj.lang.proceditingjoinpoint ؛ استيراد org.aspectj.lang.annotation.around ؛ استيراد org.aspectj.lang.annotation.around ؛ استيراد org.aspectj.lang.annotation.Aspect ؛ استيراد org.aspectj.lang.annotation.pointCut ؛ استيراد org.aspectj.lang.reflect.MethodSignature ؛ استيراد org.json.jsonarray ؛ استيراد org.json.jsonobject ؛ استيراد org.slf4j.logger ؛ استيراد org.slf4j.loggerfactory ؛ استيراد org.springframework.beans.factory.annotation.autowired ؛ استيراد org.springframework.core.localvariaBletableParameTerNameDiscoverer ؛ استيراد org.springframework.expression.expressionparser ؛ استيراد org.springframework.expression.spel.standard.spelexpressionparser ؛ استيراد org.springframework.expression.spel.support.standardevaluationContext ؛ استيراد org.springframework.stereotype.component ؛ استيراد java.lang.reflect.method ؛ / *** قسم ذاكرة التخزين المؤقت متعددة المستويات* Author Rongdi*/ Aspect Component Public Class MultiCacheaspect {private Static Final Logger = loggerfactory.getLogger (MultiCacheaspect.class) ؛ @autowired cacachefactory cachefactory ؛ // هنا يتم تهيئة المستمع من خلال حاوية ، ويتم التحكم في مفتاح ذاكرة التخزين المؤقت وفقًا لتوضيح enablecaching الذي تم تكوينه خارجيًا. @pointcut ("@annotation (com.xuanwu.apaas.core.multicache.annotation.cachable)") public void cacheaspect () {}@pointcut ("@annotation (com.xuanwu.apaas.core.multicache.antation.cacheevict) AROUND ("CacheAbleAspect ()") ذاكرة التخزين المؤقت للكائنات العامة (proseingJoinPoint JoinPoint) {// الحصول على قائمة المعلمة بالطريقة التي يتم تعديلها بواسطة كائن Facet [] args = JoinPoint.getArgs () ؛ // النتيجة هي نتيجة الإرجاع النهائية لنتيجة كائن الطريقة = فارغة ؛ // إذا لم يتم تمكين ذاكرة التخزين المؤقت ، فاستدعاء طريقة المعالجة مباشرةً للعودة إذا (! cacheenable) {try {result = joinpoint.proceed (args) ؛ } catch (throwable e) {logger.error ("" ، e) ؛ } نتيجة الإرجاع ؛ } // احصل على نوع قيمة الإرجاع لفئة طريقة الوكيل returntype = ((MaysEscript) // احصل على طريقة طريقة الوكيل = (((MaysInature) joinpoint.getSignature ()). getMethod () ؛ // احصل على التعليق على طريقة الوكيل ca = method.getAnnotation (cachable.class) ؛ // احصل على قيمة المفاتيح التي يتم تحليلها بواسطة el String Key = parsekey (ca.key () ، method ، args) ؛ class <؟> elementClass = ca.type () ؛ // احصل على اسم ذاكرة التخزين المؤقت من اسم سلسلة التعليقات التوضيحية = ca.value () ؛ حاول {// أولاً الحصول على بيانات من ehcache string cachevalue = cachefactory.ehget (الاسم ، المفتاح) ؛ if (stringUtils.isempty (cachevalue)) {// إذا لم تكن هناك بيانات في ehcache ، احصل على بيانات من redis cachevalue = cachefactory.redisget (الاسم ، المفتاح) ؛ if (stringUtils.isempty (cachevalue)) {// إذا لم تكن هناك بيانات في ehcache ، احصل على بيانات من redis cachevalue = cachefactory.redisget (الاسم ، المفتاح) ؛ if (stringUtils.isempty (cachevalue)) {// إذا لم تكن هناك بيانات في redis // استدعاء طريقة العمل للحصول على النتيجة = joinpoint.proceed (args) ؛ // تسلسل النتيجة ووضعها في redis cachefactory.redisput (الاسم ، المفتاح ، التسلسل (النتيجة)) ؛ } آخر {// إذا كان يمكن الحصول على البيانات من redis // deserialize البيانات التي تم الحصول عليها في ذاكرة التخزين المؤقت وإرجاع if (elementClass == inscsters.class) {result = deserialize (cachevalue ، returntype) ؛ } آخر {result = deserialize (cachevalue ، returntype ، elementClass) ؛ }} // قم بتسلسل النتيجة ووضعها في ehcache cachefactory.ehput (الاسم ، المفتاح ، التسلسل (النتيجة)) ؛ } آخر {// deserialize البيانات التي تم الحصول عليها في ذاكرة التخزين المؤقت وإرجاع if (elementClass == inscrept.class) {result = deserialize (cachevalue ، returntype) ؛ } آخر {result = deserialize (cachevalue ، returntype ، elementClass) ؛ }}} catch (throwable throwable) {logger.error ("" ، throwable) ؛ } نتيجة الإرجاع ؛ } / ** * قم بمسح ذاكرة التخزين المؤقت قبل أن يتم استدعاء الطريقة ، ثم استدعاء طريقة العمل * param JoinPoint * regurn * @throws reamable * * / around ("cacheevict ()") الكائنات العامة evictcache (prosectjoinpoint joinpoint) ترفع {// الحصول على طريقة proxy method = (methaysignature) // احصل على قائمة المعلمات بالطريقة المعدلة بواسطة كائن Facet [] args = JoinPoint.getArgs () ؛ // احصل على التعليق التوضيحي على طريقة الوكيل cacheevict ce = method.getAnnotation (cacheevict.class) ؛ // احصل على قيمة المفاتيح التي يتم تحليلها بواسطة el String Key = parsekey (ce.key () ، method ، args) ؛ // احصل على اسم ذاكرة التخزين المؤقت من اسم سلسلة التعليقات التوضيحية = ce.value () ؛ // قم بمسح ذاكرة التخزين المؤقت المقابلة cachefactory.cachedel (الاسم ، المفتاح) ؛ إرجاع JoinPoint.proceed (args) ؛ } / ** * احصل على مفتاح المخزونات * المحددة على التعليقات التوضيحية ، ودعم تعبيرات spel * @return * / private string parsekey (مفتاح السلسلة ، طريقة الطريقة ، الكائن [] args) {if (stringUtils.isempty (مفتاح)) إرجاع null ؛ // احصل على قائمة اسم المعلمة بالطريقة المعتادة (باستخدام مكتبة فئة الدعم الربيعي) LocalVariaBletableParameTerNamediscoverer u = New LocalVariableTibleParameterNamediscovererer () ؛ String [] paranamearr = U.GetParameterNames (method) ؛ // استخدم spel for expressing expression expresser key parser = new SpelexpressionParser () ؛ // spel context StandardEvaluation Context = New StandardEvaluationContext () ؛ // ضع معلمات الطريقة في سياق spel لـ (int i = 0 ؛ i <paranamearr.length ؛ i ++) {context.setVariable (paranamearr [i] ، args [i]) ؛ } return parser.parseexpression (key) .getValue (context ، string.class) ؛ } // Serialize Private String Serialize (Object OBJ) {String result = null ؛ حاول {result = jsonutil.serialize (obj) ؛ } catch (استثناء e) {result = obj.toString () ؛ } نتيجة الإرجاع ؛ } // deserialize كائن خاص deserialize (String str ، class clazz) {object result = null ؛ حاول {if (clazz == jsonobject.class) {result = new JSonObject (str) ؛ } آخر إذا (clazz == jsonarray.class) {result = new jsonarray (str) ؛ } آخر {result = jsonutil.deserialize (str ، clazz) ؛ }} catch (استثناء e) {} نتيجة الإرجاع ؛ }. حاول {if (clazz == jsonobject.class) {result = new JSonObject (str) ؛ } آخر إذا (clazz == jsonarray.class) {result = new jsonarray (str) ؛ } آخر {result = jsonutil.deserialize (str ، clazz ، elementClass) ؛ }} catch (استثناء e) {} نتيجة الإرجاع ؛ } public void setCacheenable (boolean cacheenable) {this.cacheenable = cacheenable ؛ }}تستخدم الواجهة أعلاه متغير Cacheenable للتحكم في ما إذا كنت تريد استخدام ذاكرة التخزين المؤقت. من أجل تحقيق وصول سلس إلى Springboot ، من الضروري التحكم في شرح enableCaching الأصلي. أستخدم هنا مستمعًا تم تحميله بواسطة حاوية الربيع ، ثم أجد في المستمع ما إذا كان هناك تصنيف تم تعديله بواسطة enablecaching. إذا كان الأمر كذلك ، احصل على الكائن متعدد الطوابق من حاوية الربيع ، ثم قم بتعيين cacheenable على True. هذا سيمكن من الوصول السلس إلى سبرينغ بوت. أتساءل عما إذا كان هناك أي طريقة أكثر أناقة للأصدقاء؟ مرحبا بكم في التواصل! فئة المستمع على النحو التالي
استيراد com.xuanwu.apaas.core.multicache.cachefactory ؛ استيراد com.xuanwu.apaas.core.multicache.multicacheaspect ؛ استيراد org.springframework.cache.annotation.enableCaching ؛ استيراد org.springframework.context.applicationListener ؛ استيراد org.springframework.context.event.contextrefreshedevent ؛ استيراد org.springframework.stereotype.component ؛ استيراد java.util.map ؛ / ** * يستخدم للعثور على ما إذا كان هناك تعليق توضيحي لتمكين ذاكرة التخزين المؤقت في المشروع بعد الانتهاء من تحميل الربيع enableCaching * Author rongdi */ component الفئة العامة contextrefreshedlister تنفذ تطبيق applicationsener <contextrefreshedevent> منع حدوث مكالمتين (سيتم تحميل MVC أيضًا مرة واحدة) إذا (Event.getApplicationContext (). getParent () == null) {// الحصول على جميع الفئات المعدلة بواسطة enableCaching Map <string ، Object> beans = event.getapplicationContext (). if (beans! = null &&! beans.isempty ()) {multiCacheasspect multiCache = (multicacheaspect) event.getApplicationContext (). getBean ("multiCacheaspect") ؛ multicache.setCacheenable (صواب) ؛ }}}}}لتحقيق وصول سلس ، نحتاج أيضًا إلى التفكير في كيفية توافق Ehcache متعدد النقاط مع ذاكرة التخزين المؤقت Redis عند نشر Ehcache متعدد النقاط. في التطبيقات العادية ، يكون Redis مناسبًا بشكل عام لتذاكر ذاكرة التخزين المؤقت المركزية على المدى الطويل ، و Ehcache مناسب لذاكرة التخزين المؤقت المحلية على المدى القصير. افترض أن هناك الآن خوادم A و B و C و A و B Services Business Services و C تنشر خدمات redis. عندما يأتي الطلب ، فإن إدخال الواجهة الأمامية ، سواء كان برنامج تحميل مثل LVS أو NGINX ، سيقوم بإعادة توجيه الطلب إلى خادم معين. على افتراض أنه يتم إعادة توجيهه إلى الخادم A ويتم تعديل محتوى معين ، وهذا المحتوى متاح في كل من Redis و Ehcache. في هذا الوقت ، من الأسهل التحكم في ذاكرة التخزين المؤقت لـ Ehcache من الخادم A و Redis من الخادم C ما إذا كانت ذاكرة التخزين المؤقت غير صالحة أو محذوفة. ولكن كيف تتحكم في ehcache من الخادم B في هذا الوقت؟ الطريقة الشائعة الاستخدام هي استخدام وضع الاشتراك النشر. عندما تحتاج إلى حذف ذاكرة التخزين المؤقت ، تقوم بنشر رسالة على قناة ثابتة. ثم يشترك كل خادم أعمال في هذه القناة. بعد تلقي الرسالة ، تقوم بحذف أو تنتهي صلاحية ذاكرة التخزين المؤقت لـ Ehcache المحلية (من الأفضل استخدام انتهاء الصلاحية ، ولكن Redis يدعم حاليًا العمليات المنتهية الصلاحية فقط على المفتاح. يكتب. باختصار ، تتمثل العملية في تحديث جزء معين من البيانات ، وقم أولاً بحذف ذاكرة التخزين المؤقت المقابلة في redis ، ثم نشر رسالة مع ذاكرة التخزين المؤقت غير صالحة في قناة معينة من redis. تشترك خدمة الأعمال المحلية في رسالة هذه القناة. عندما تتلقى خدمة الأعمال هذه الرسالة ، فإنها تحذف ذاكرة التخزين المؤقت Ehcache المحلية. التكوينات المختلفة من redis هي كما يلي.
استيراد com.fasterxml.jackson.annotation.jsonautodeTect ؛ استيراد com.fasterxml.jackson.annotation.PropertyAccessor ؛ استيراد com.fasterxml.jackson.databind.objectMapper ؛ استيراد com.xuanwu.apaas.core.multicache.subscriber.messagesubscriber ؛ استيراد org.springframework.cache.cachemanager ؛ استيراد org.springframework.context.annotation.bean ؛ استيراد org.springframework.context.annotation.configuration ؛ استيراد org.springframework.data.redis.cache.rediscachemanager ؛ استيراد org.springframework.data.redis.connection.redisconnectionFactory ؛ استيراد org.springframework.data.redis.core.redistemplate ؛ استيراد org.springframework.data.redis.core.StringRediStemplate ؛ استيراد org.springframework.data.redis.listener.patterntopic ؛ استيراد org.springframework.data.redis.listener.redismessagelistenercontainer ؛ استيراد org.springframework.data.redis.listener.adapter.messagelisteneradapter ؛ استيراد org.springframework.data.redis.serializer.jackson2jsonredisserializer ؛ configuration الفئة العامة redisconfig {bean public cachemanager cachemanager (redistemplate redistemplate) {rediscachemanager rcm = new rediscachemanager (redistemplate) ؛ // تعيين وقت انتهاء صلاحية ذاكرة التخزين المؤقت (Seconds) rcm.setDefaultExpiration (600) ؛ إرجاع RCM ؛ } bean public redistemplate <string ، string> redistemplate (redisconnectionFactory Factory) {StringRedIstemplate template = new StringRedIstemplate (Factory) ؛ Jackson2Jsonredisserializer Jackson2JsonRedisserializer = New Jackson2JsonRedisserializer (Object.class) ؛ ObjectMapper om = new ObjectMapper () ؛ om.SetVisibility (propertyAccessor.all ، jsonautodetect.vibility.yan) ؛ om.enabledefaulttyping (ObjectMapper.defaulttyping.non_final) ؛ Jackson2Jsonredisserializer.setObjectMapper (OM) ؛ template.setValueserializer (Jackson2JsonRedisserializer) ؛ template.afterPropertiesset () ؛ قالب العودة. } /*** حاوية مستمع رسالة Redis* يمكنك إضافة العديد من مستمعي Redis الذين يستمعون إلى مواضيع مختلفة. تحتاج فقط إلى ربط مستمع الرسائل ومعالج اشتراك الرسائل المقابل ، ومستمع الرسائل * استدعاء الأساليب ذات الصلة لمعالج الاشتراك في الرسائل من خلال تقنية الانعكاس لبعض معالجة الأعمال * param connectionfactory * param leaderadapter * @return */ @public redissagelistenercontainer container (redisconnectionfactoryfactory ، messageListerAdapter letningerAdapter letning letnerAdapter letnerAdAdapter charlec. حاوية REDISMESSAGELISTENERCONTAINER = جديد redismessagelistenerContainer () ؛ container.setConnectionFactory (connectionFactory) ؛ // الاشتراك في حاوية القناة. addmessagelistener (مستمع ، new patterntopic ("redis.uncache")) ؛ // يمكن أن تضيف هذه الحاوية حاوية إرجاع messagelistener متعددة ؛ } /** * محول مستمع الرسائل ، ويربط معالج الرسائل ، ويستخدم تقنية الانعكاس لاستدعاء أساليب عمل معالج الرسائل * stripe reciver * @return * /bean messagelistenerAdapter leaderAdapter (messagesubscriber receiver) {// هذا المكان messagelisteneradapter (جهاز الاستقبال ، "مقبض") ؛ }}فئة نشر الرسائل كما يلي:
استيراد com.xuanwu.apaas.core.multicache.cachefactory ؛ استيراد org.apache.commons.lang3.StringUtils ؛ استيراد org.slf4j.logger ؛ استيراد org.slf4j.loggerfactory ؛ استيراد org.springframework.beans.factory.annotation.autowired ؛ استيراد org.springframework.stereotype.component ؛ @component public class messagesubscriber {private static final logger logger = loggerfactory.getLogger (messagesUBScriber.class) ؛ @autowired cacachefactory cachefactory ؛ / *** بعد استلام رسالة اشتراك redis ، يتم إبطال ذاكرة التخزين المؤقت لـ ehcache* تنسيق رسالة param هو name_key*/ public void handle (رسالة سلسلة) {logger.debug ("redis.ehcache:"+message) ؛ if (stringUtils.isempty (message)) {return ؛ } string [] strs = message.split ("#") ؛ اسم السلسلة = Strs [0] ؛ مفتاح السلسلة = فارغ ؛ if (strs.length == 2) {key = strs [1] ؛ } cachefactory.ehdel (الاسم ، المفتاح) ؛ }}فئات ذاكرة التخزين المؤقت للتشغيل المحددة هي كما يلي:
استيراد com.xuanwu.apaas.core.multicache.publisher.MessagePublisher ؛ استيراد net.sf.ehcache.cache ؛ استيراد net.sf.ehcache.cachemanager ؛ استيراد net.sf.ehcache.element ؛ استيراد org.apache.commons.lang3.StringUtils ؛ استيراد org.slf4j.logger ؛ استيراد org.slf4j.loggerfactory ؛ استيراد org.springframework.beans.factory.annotation.autowired ؛ استيراد org.springframework.data.redis.redisconnectionFailureException ؛ استيراد org.springframework.data.redis.core.hashoperations ؛ استيراد org.springframework.data.redis.core.redistemplate ؛ استيراد org.springframework.stereotype.component ؛ استيراد java.io.inputstream ؛ / *** قسم ذاكرة التخزين المؤقت متعددة المستويات* Author Rongdi*/ component الفئة العامة cachefactory {private static final logger = loggerfactory.getLogger (cachefactory.class) ؛ @autowired redistemplate redistemplate ؛ Autowired Private MessagePublisher MessagePublisher ؛ Cachemanager الخاص Cachemanager ؛ public cachefactory () {inputStream is = this.getClass (). getResourCeasStream ("/ehcache.xml") ؛ if (is! = null) {cachemanager = cachemanager.create (is) ؛ }} public void cachedel (اسم السلسلة ، مفتاح السلسلة) {// حذف ذاكرة التخزين المؤقت المقابلة لـ redis ؛ // حذف ذاكرة التخزين المؤقت Ehcache المحلية ، والتي ليست مطلوبة ، وسيقوم المشترك بحذف // ehdel (الاسم ، المفتاح) ؛ if (cachemanager! = null) {// نشر رسالة تخبر الخدمة المشتركة بأن ذاكرة التخزين المؤقت هي messagePublisher.publish (الاسم ، المفتاح) ؛ }} السلسلة العامة ehget (اسم السلسلة ، مفتاح السلسلة) {if (cachemanager == null) return null ؛ ذاكرة التخزين المؤقت Cache = cachemanager.getCache (name) ؛ إذا (ذاكرة التخزين المؤقت == فارغة) إرجاع فارغ ؛ cache.AcquirereadClockonkey (مفتاح) ؛ حاول {element ele = cache.get (key) ؛ إذا (ele == null) return null ؛ إرجاع (سلسلة) ele.getObjectValue () ؛ } أخيرًا {cache.releasereadlockonkey (key) ؛ }} string public redisget (اسم السلسلة ، مفتاح السلسلة) {hashoperations <string ، string ، string> opera = redistemplate.opsforhash () ؛ حاول {return opera.get (الاسم ، المفتاح) ؛ } catch (redisconnectionFailureException e) {// فشل الاتصال ، لا يتم طرح أي خطأ ، و logger.error ("connect redis error" ، e) ؛ العودة لاغية. }} public void ehput (اسم السلسلة ، مفتاح السلسلة ، قيمة السلسلة) {if (cachemanager == null) return ؛ if (! cachemanager.cacheexists (name)) {cachemanager.addcache (name) ؛ } cache cache = cachemanager.getCache (name) ؛ // احصل على قفل الكتابة على المفتاح ، لا تؤثر المفاتيح المختلفة على بعضها البعض ، على غرار متزامن (key.intern ()) {} cache.acquirewritelockonkey (مفتاح) ؛ حاول {cache.put (عنصر جديد (مفتاح ، قيمة)) ؛ } أخيرًا {// refer the Writting lock cache.releasewritelockonkey (key) ؛ }} redisput public void (اسم السلسلة ، مفتاح السلسلة ، قيمة السلسلة) {hashoperations <string ، string ، string> opera = redistemplate.opsforhash () ؛ حاول {properator.put (الاسم ، المفتاح ، القيمة) ؛ } catch (redisconnectionFailureException e) {// فشل الاتصال ، ولم يتم إلقاء أي خطأ ، و logger.error ("connect redis error" ، e) ؛ }} public void ehdel (اسم السلسلة ، مفتاح السلسلة) {if (cachemanager == null) return ؛ إذا كان (cachemanager.cacheexists (name)) {// إذا كان المفتاح فارغًا ، فقم بحذفه مباشرة وفقًا لاسم ذاكرة التخزين المؤقت if (stringUtils.isempty (key)) {cachemanager.removecache (name) ؛ } آخر {cache cache = cachemanager.getCache (name) ؛ cache.remove (مفتاح) ؛ }}} public void redisdel (اسم السلسلة ، مفتاح السلسلة) {hashoperations <string ، string ، string> opera = redistemplate.opsforhash () ؛ جرب {// إذا كان المفتاح فارغًا ، فاحذف إذا (stringUtils.isempty (key)) {redistemplate.delete (name) ؛ } آخر {opera.delete (الاسم ، المفتاح) ؛ }} catch (redisconnectionFailureException e) {// فشل الاتصال ، ولم يتم إلقاء أي خطأ ، و logger.error ("connect redis error" ، e) ؛ }}}فئة الأدوات كما يلي
استيراد com.fasterxml.jackson.core.type.typereference ؛ استيراد com.fasterxml.jackson.databind.deserializationFeature ؛ استيراد com.fasterxml.jackson.databind.javatype ؛ استيراد com.fasterxml.jackson.databind.objectMapper ؛ استيراد org.apache.commons.lang3.StringUtils ؛ استيراد org.json.jsonarray ؛ استيراد org.json.jsonobject ؛ استيراد java.util.*؛ الطبقة العامة jsonutil {private static ObjectMapper mapper ؛ ثابت {mapper = new ObjectMapper () ؛ mapper.configure (deserializationfeature.fail_on_unknown_properties ، false) ؛ } / ** * قم بتسلسل الكائن في كائن JSON * * param OBJ ليتم تسلسله * return * @throws استثناء * / سلسلة ثابتة عامة (كائن OBJ) يلقي استثناء {if (obj == null) {رمي newalalArgumentException ("OBJ لا ينبغي أن يكون فارغًا") ؛ } return mapper.writevalueasString (OBJ) ؛ } / ** deserialization مع generics ، مثل إلغاء التخلص من jsonarray في القائمة <Sether>* / static public <t> t deserialize (string jsonstr ، class <؟> collectionClass ، class <؟ elementclasses) ؛ return mapper.readvalue (JSonstr ، javatype) ؛ } / *** deserialize json string في كائن* param src سلسلة json لتكون deverialized* param t نوع فئة الكائن deserialized في* @return* starw باطل")؛ } if ("{}". equals (src.trim ())) {return null ؛ } return mapPPer.ReadValue (src ، t) ؛ }}لاستخدام ذاكرة التخزين المؤقت على وجه التحديد ، ما عليك سوى الانتباه إلى التعليقات التوضيحية Cachable و CacheeVict ، وكذلك دعم تعبيرات الربيع EL. علاوة على ذلك ، فإن اسم ذاكرة التخزين المؤقت التي يمثلها سمة القيمة هنا ليس لديها المشكلة المذكورة أعلاه. يمكن عزل ذاكرة التخزين المؤقت المختلفة باستخدام القيمة. الأمثلة على النحو التالي
cachable (value = "bo" ، key = "#session.productversioncode+''+#session.tenantcode+''+#objectCode")@cacheevict (value = "bo" ، key = "#session.productversioncode+''+#session.tenantcode+'+' ObjectCode")
إرفاق حزمة التبعية الرئيسية
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.