التخزين المؤقت في الربيع باستخدام تعليقات EhCache التوضيحية

نشرت: 2022-03-11

EhCache عبارة عن ذاكرة تخزين مؤقت Java نقية مستخدمة على نطاق واسع ويمكن دمجها بسهولة مع معظم أطر Java الشائعة ، مثل Spring و Hibernate. غالبًا ما يعتبر الخيار الأكثر ملاءمة لتطبيقات Java لأنه يمكن دمجه في المشاريع بسهولة. خاصه:

  • يمكن إعداده ببساطة عن طريق تضمين JAR في مشروعك. لا توجد خطوات تثبيت إضافية مطلوبة.
  • يتم تشغيله بنفس العملية مع التطبيق ، لذا فهو سريع. لا توجد خدمة إضافية مطلوبة للتشغيل.

باختصار ، يعد EhCache خيارًا رائعًا لأي تطبيق Java خالص.

بالإضافة إلى ذلك ، تتيح التعليقات التوضيحية EhCache Spring التكامل السلس في أي تطبيق Spring ببساطة عن طريق إضافة التعليقات التوضيحية إلى الطرق القابلة للتخزين المؤقت ، دون تعديل عمليات تنفيذ الطريقة.

EhCache هو حل تخزين مؤقت رائع لمشاريع الربيع.

بينما يوفر EhCache واجهات برمجة تطبيقات مباشرة وغنية للتعامل مع ذاكرة التخزين المؤقت برمجيًا ، تركز هذه المقالة بشكل أساسي على تعزيز تطبيقات Spring بطريقة أقل تدخلاً مع EhCache Spring Annotations. سنقوم بإنشاء مشروع Spring MVC ونشر خدمة ويب RESTful في Tomcat. بعد ذلك ، سيتم دمج EhCache في خدمة الويب.

ملخص المشروع

سنقوم بشرح تعليقات EhCache التوضيحية في سياق مشروع كمثال. سنقوم بإعداد خدمة ويب قائمة على Spring MVC مستضافة على خادم Tomcat 8.

لقد قمت بتطوير المشروع في Eclipse ، والذي يمكن تثبيته باتباع الإرشادات هنا.

يمكن تنزيل أحدث إصدار مستقر من Tomcat ، Tomcat 8 ، هنا.

بالطبع ، هذه المنصات المحددة ليست من متطلبات EhCache ؛ يمكنك دائمًا اختيار IDE والخادم المفضل لديك.

يتوفر برنامج EhCache Spring للتعليقات التوضيحية هنا. كما نرى ، هناك نوعان من JAR لكل إصدار: واحد به تبعيات والآخر بدون. يتضمن أيضًا الشخص الذي يحتوي على تبعيات EhCache 2 و Spring 3 ، وهي مطلوبة حتى تعمل تعليقات EhCache التوضيحية. من الأسهل الإعداد إذا قمنا بتنزيل الملف ذي التبعيات وإضافته إلى مسار البناء الخاص بنا.

تتوافق تعليقات EhCache Spring التوضيحية أيضًا مع Spring 4 ، على الرغم من أنه يجب تهيئتها بشكل منفصل. ليس من الواضح ما إذا كان المشروع سيدعم EhCache 3 في المستقبل القريب. بالنسبة لأولئك الذين يستخدمون أو يعتزمون استخدام EhCache 3 ، لا يُنصح باتباع نهج التعليقات التوضيحية الذي تمت مناقشته في هذه المقالة.

أخيرًا ، سنستخدم Maven لإدارة كل شيء. يأتي Maven مُعبأًا مسبقًا مع معظم تركيبات Eclipse ، ولكن يمكن أيضًا الحصول عليه هنا. يمكن إضافة تبعيات Spring MVC و EhCache Spring Annotations بسهولة إلى حد ما ، كما هو موضح لاحقًا في هذه المقالة.

إعداد مشروع

إذا لم تكن قد أعددت مشروع Spring من قبل ، فقد تجد أيضًا مشاركة Stefan Varga حول هذا الموضوع مفيدة.

بالنسبة لهذا العرض التوضيحي ، سننشئ مشروعًا أساسيًا باستخدام تطبيق Maven الأصلي maven-archetype-webapp . سيبدو الهيكل العام للملف كما يلي:

الهيكل الأولي لمشروع الربيع.

قم بإنشاء دليل ، src/main/java ، بثلاث حزم: com.toptal.blog و com.toptal.blog.cache و com.toptal.blog.service . سيظهر مصدر التطبيق الخاص بنا في هذه الحزم ، كما هو موضح أدناه.

دعنا نحدد Tomcat servlet المسمى “springrest” في web.xml :

 <web-app> ... <servlet> <servlet-name>springrest</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springrest</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>

ما لم ينص صراحة على خلاف ذلك ، سيبحث Spring MVC DispatcherServlet عن ملف تكوين XML يسمى {servlet-name}-servlet.xml في الدليل WEB-INF . لنقم بإنشاء ملف تكوين يسمى springrest-servlet.xml . لتمكين طرق التحكم في عملية Spring التي تم شرحها باستخدام @RequestMapping ، دعنا نضيف ببساطة <mvc:annotation-driven /> إلى هذا الملف. أيضًا ، دعنا نحدد الحزمة الأساسية لـ Spring لمسح الفول وتسجيله تلقائيًا عن طريق إضافة <context:component-scan base-package="com.toptal.blog" /> . يصبح تكوين springrest-servlet.xml :

 <beans ... > <mvc:annotation-driven /> <context:component-scan base-package="com.toptal.blog" /> </beans>

خدمة ويب بسيطة ومريحة

الآن بعد أن تم تكوين مشروعنا بشكل صحيح ، دعنا ننفذ واجهة برمجة تطبيقات بسيطة لـ "خدمة الرسائل". في الحزمة الأساسية الخاصة بنا ، project.toptal.blog ، سنضيف SpringRestControllerWithEhCache.java ، مع طريقة GET واحدة للحصول على رسالة بواسطة المعرف ، وطريقة POST واحدة لتعيين رسالة بواسطة المعرف:

 @RestController @RequestMapping( "/" ) public class SpringRestControllerWithEhCache { @Autowired MessageService messageService; @RequestMapping( value = "/message/{id}", method = RequestMethod.GET ) public String getMessage( @PathVariable Integer id ) { String message = messageService.getMessage( id ); System.out.println( "get message ["+message+"] at "+new Date() ); return message; } @RequestMapping( value = "/message/set/{id}/{message}", method = RequestMethod.POST ) public String setMessage( @PathVariable Integer id, @PathVariable String message ) { System.out.println( "set message ["+message+"] at "+new Date() ); messageService.setMessage( id, message ); return message; } }

سنقوم بتعريف فئة MessageService في com.toptal.blog.service . سيصل إلى الرسائل المخزنة في نظام السجلات لدينا (SOR). في تطبيق الإنتاج ، سيكون SOR بمثابة قاعدة بيانات علائقية. للتبسيط ، سوف نستخدم HashMap :

 @Service public class MessageService { private ConcurrentHashMap<Integer, String> messages = new ConcurrentHashMap<Integer, String>(); public String getMessage( Integer id ) { System.out.println( "Getting data from SOR......" ); return messages.get( id ); } public void setMessage( Integer id, String message ){ messages.put( id, message ); } }

الآن ، إذا قمنا بتصدير المشروع باعتباره WAR ونشره في Tomcat ، يجب أن نكون قادرين على تعيين رسالة ، على سبيل المثال “test_message” ، للمعرف = 1 ، عن طريق إنشاء طلب HTTP POST على http://localhost:8080/EhCacheExample/message/set/1/test_message . يجب أن نكون قادرين بعد ذلك على استعادة "test_message" مع طلب HTTP GET على http://localhost:8080/EhCacheExample/message/1 . لقد استخدمت Insomnia كعميل REST مناسب لإجراء الاختبار.

قم بتوصيل التعليقات التوضيحية EhCache Spring

الآن دعنا نجعل EhCache يعمل لدينا. لا يتطلب الأمر سوى بضع خطوات سريعة لتهيئة مشروعنا لتشغيل EhCache بشكل صحيح.

تجعل تعليقات EhCache Spring Annotations EhCache سهلة وسلسة للنشر في تطبيقك.

الخطوة 1: تحديث التبعيات لاستخدام تعليقات EhCache Spring التوضيحية

أضف تبعية EhCache Spring Annotations في ملف Maven's pom.xml :

 <!-- ehcache --> <dependency> <groupId>com.googlecode.ehcache-spring-annotations</groupId> <artifactId>ehcache-spring-annotations</artifactId> <version>1.2.0</version> </dependency>

الخطوة 2: إعداد Custom Cache Manager

يحتوي Spring على مدير ذاكرة تخزين مؤقت EhCache مدمج ، org.springframework.cache.ehcache.EhCacheManagerFactoryBean . هذا مناسب لمعظم حالات التخزين المؤقت ، لكنني وجدت أن تحديد مدير ذاكرة تخزين مؤقت مخصص مفيد لأنه يسمح لي بالتحكم في ذاكرة التخزين المؤقت إما برمجيًا أو مع التعليقات التوضيحية ، باستخدام نفس مدير ذاكرة التخزين المؤقت. تركز هذه المقالة على التعليقات التوضيحية ، ولكن دعنا نمضي قدمًا ونحدد مدير ذاكرة تخزين مؤقت مخصص لذلك سنكون مستعدين في حال احتجنا إليه. إذا كنت تفضل الاستمرار في استخدام مدير ذاكرة التخزين المؤقت الافتراضي ، فيمكنك تخطي هذه الخطوة.

سنقوم بتعريف الفئة الجديدة في com.toptal.blog.cache.CustomCacheManager :

 public class CustomCacheManager extends net.sf.ehcache.CacheManager{ public CustomCacheManager(){ super(); } /* Add your own cache methods here. * * public void myCustomCacheMethod(){ * // your code here * } * */ }

قم بتمكينه عن طريق تحديث springrest-servlet.xml النحو التالي:

 ... <ehcache:annotation-driven cache-manager="customCacheManager" /> <bean class="com.toptal.blog.cache.CustomCacheManager" scope="singleton"></bean> ...

الخطوة 3: تكوين EhCache

أخيرًا ، قم بإنشاء ملف تكوين ehcache.xml في classpath. بشكل افتراضي ، سيتضمن Eclipse src/main/resources في classpath ، وسنضع الملف هنا. هذا الملف مطلوب لـ EhCache لكي يعمل بشكل صحيح. يحدد أسماء ذاكرة التخزين المؤقت وبعض خصائص كل ذاكرة تخزين مؤقت ، مثل timeToLiveSeconds :

 <ehcache xmlms:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd"> <diskStore path="cache" /> <cache name="messageCache" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="0" timeToLiveSeconds="10" overflowToDisk="false" memoryStoreEvictionPolicy="LFU" /> </ehcache>

الخطوة 4: اختبر ذاكرة التخزين المؤقت

الآن ، مع إعداد كل شيء وجاهز للعمل ، يجب أن يكون استخدام EhCache عملاً سهلاً وسعيدًا. يمكننا ببساطة إضافة @Cacheable إلى الطريقة أو الفئة التي نريد تخزينها مؤقتًا. على سبيل المثال ، أضفت @Cacheable إلى طريقة getMessage في MessageService . انه من السهل!

 @Cacheable( cacheName = "messageCache" ) public String getMessage( Integer id ) { System.out.println( "Getting data from SOR......" ); return messages.get( id ); }

لاختبار عمل ذاكرة التخزين المؤقت لدينا ، يمكننا إنشاء رسالة للمعرف = 1 عن طريق إصدار طلب HTTP POST على http://localhost:8080/EhCacheExample/message/set/1/newMessage ، ثم الحصول على الرسالة للمعرف = 1 عدة مرات ، مع طلبات GET إلى http://localhost:8080/EhCacheExample/message/1 . كما ترى في إخراج وحدة التحكم أدناه ، تطلب خدمة الويب من SOR تلقي الرسالة في المرة الأولى التي نطلب فيها الرسالة ، ولكن ليس للطلبين التاليين ، مع إعادة الرسالة المخزنة مؤقتًا بدلاً من ذلك. نظرًا لأننا حددنا timeToLiveSeconds ليكون 10 ، فإن خدمة الويب تستدعي SOR لتلقي الرسالة مرة أخرى بعد 10 ثوانٍ:

 set message [newMessage] at Sun Dec 06 23:55:39 MST 2015 get message [newMessage] at Sun Dec 06 23:55:42 MST 2015 Getting data from SOR...... get message [newMessage] at Sun Dec 06 23:55:47 MST 2015 get message [newMessage] at Sun Dec 06 23:55:49 MST 2015 get message [newMessage] at Sun Dec 06 23:55:54 MST 2015 Getting data from SOR......

تحديث ذاكرة التخزين المؤقت

الآن ، نحن نتمتع بالسرعة والراحة التي يوفرها لنا ذاكرة التخزين المؤقت ، و EhCache جيد بما يكفي للتحديث بنفسه كل 10 ثوانٍ. ولكن ماذا لو كنا نرغب في تحديثه فورًا بعد تحديث SOR الخاص بنا؟ تقدم @TriggersRemove Spring AnnotationTriggersRemove لإزالة المفاتيح المحددة من ذاكرة التخزين المؤقت عندما يتم استدعاء الطريقة المشروحة. في واجهة برمجة تطبيقات خدمة الرسائل الخاصة بنا ، يجب إزالة الرسالة المخزنة مؤقتًا من ذاكرة التخزين المؤقت عند setMessage . وبالتالي ، في المرة التالية التي يأتي فيها طلب getMessage ، ستحضر ذاكرة التخزين المؤقت سجلًا جديدًا من SOR:

 @Cacheable( cacheName = "messageCache", keyGenerator = @KeyGenerator ( // method name is not included in cache key to work with @TriggersRemove name = "HashCodeCacheKeyGenerator", properties = @Property( name="includeMethod", value="false" ))) public String getMessage( Integer id ) { System.out.println( "Getting data from SOR......" ); return messages.get( id ); } @TriggersRemove( cacheName = "messageCache", keyGenerator = @KeyGenerator ( name = "HashCodeCacheKeyGenerator", properties = @Property( name="includeMethod", value="false" ))) public void setMessage( @PartialCacheKey Integer id, String message ) { messages.put( id, message ); }

يتم استخدام مولد المفاتيح بواسطة مدير ذاكرة التخزين المؤقت لإنشاء مفتاح ذاكرة التخزين المؤقت. يمكن العثور هنا على قائمة بمولدات مفاتيح ذاكرة التخزين المؤقت المحددة مسبقًا. بشكل افتراضي ، يستهلك @KeyGenerator كلاً من اسم الطريقة والمعلمات التي تم تمريرها لإنشاء مفتاح ذاكرة التخزين المؤقت. ولكن نظرًا لأننا نريد أن تقوم طريقة setMessage بإنشاء نفس المفتاح مثل getMessage وحذف القيمة المخزنة مؤقتًا المرتبطة بهذا المفتاح ، يجب علينا استخدام معرف الرسالة فقط كمفتاح وإزالة اسم الطريقة لإنشاء المفتاح. لذلك قمنا بتعيين خاصية includeMethod الخاصة بمولد المفتاح لتكون false في كلتا الطريقتين. أيضًا ، نظرًا لأن setMessage تحتوي على وسيطين ، فإننا نستخدم التعليق التوضيحي لـ @PartialCacheKey على معلمة id لتحديد أنها الوحيدة التي يجب أن يستخدمها منشئ المفتاح. أخيرًا ، تذكر أننا قمنا بتكوين ذاكرة تخزين مؤقت مخصصة ، messageCache ، لهذا النوع من الموارد ، لذا فإن استخدام المعرف فقط للمفتاح لا يمثل خطر التعارض مع أنواع الموارد الأخرى.

الآن ، إذا قمنا بإجراء عدة طلبات HTTP للرسالة ذات المعرف = 1 ، على النحو التالي:

 HTTP POST: http://localhost:8080/EhCacheExample/message/set/1/newMessage1 HTTP GET:http://localhost:8080/EhCacheExample/message/1 HTTP POST: http://localhost:8080/EhCacheExample/message/set/1/newMessage2 HTTP GET:http://localhost:8080/EhCacheExample/message/1

ستظهر وحدة التحكم:

 set message [newMessage1] at Tue Dec 08 17:53:44 MST 2015 get message [newMessage1] at Tue Dec 08 17:53:47 MST 2015 Getting data from SOR...... set message [newMessage2] at Tue Dec 08 17:53:50 MST 2015 get message [newMessage2] at Tue Dec 08 17:53:53 MST 2015 Getting data from SOR......

خاتمة

يبدو الهيكل النهائي للمشروع كما يلي:

الهيكل النهائي للمشروع.

في هذا المثال ، أنشأنا أولاً تطبيق ويب Spring MVC RESTful بسيطًا. بدون تعديل حتى سطر واحد من كود التطبيق الحالي ، قمنا بعد ذلك بدمج EhCache بسلاسة في التطبيق باستخدام EhCache Spring Annotations. لقد أوضحنا أن EhCache Spring Annotations سهلة التثبيت (من خلال إضافة تبعية Maven) وأنيقة للاستخدام (عن طريق إضافة التعليقات التوضيحية إلى الأساليب).

قراءة متعمقة

يمكن العثور على توثيق EhCache هنا وتوثيق EhCache Spring Annotations هنا.

تحقق أيضًا من نموذج المشروع الموضح في هذه المقالة على GitHub.