Въведение в Ehcache

1. Общ преглед

В тази статия ще ви представим Ehcache, широко използван кеш, базиран на Java с отворен код. Той разполага с памет и дискови хранилища, слушатели, кеширащи устройства, RESTful и SOAP API и други много полезни функции.

За да покажем как кеширането може да оптимизира нашето приложение, ще създадем прост метод, който ще изчисли квадратни стойности на предоставените числа. При всяко извикване методът ще извиква метода calcuSquareOfNumber (int number) и ще отпечатва информационно съобщение на конзолата.

С този прост пример искаме да покажем, че изчисляването на квадратни стойности се извършва само веднъж и всяко друго повикване със същата входна стойност връща резултат от кеша.

Важно е да забележите, че сме фокусирани изцяло върху самия Ehcache (без Spring); ако искате да видите как Ehcache работи с Spring, разгледайте тази статия.

2. Зависимости на Maven

За да използваме Ehcache, трябва да добавим тази зависимост на Maven:

 org.ehcache ehcache 3.1.3 

Най-новата версия на артефакта Ehcache можете да намерите тук.

3. Конфигуриране на кеша

Ehcache може да бъде конфигуриран по два начина:

  • Първият начин е чрез Java POJO, където всички конфигурационни параметри се конфигурират чрез Ehcache API
  • Вторият начин е конфигурирането чрез XML файл, където можем да конфигурираме Ehcache според предоставената дефиниция на схемата

В тази статия ще покажем и двата подхода - Java, както и XML конфигурация.

3.1. Конфигурация на Java

Този подраздел ще покаже колко лесно е да конфигурирате Ehcache с POJO. Също така ще създадем помощен клас за по-лесно конфигуриране и наличност на кеша:

public class CacheHelper { private CacheManager cacheManager; private Cache squareNumberCache; public CacheHelper() { cacheManager = CacheManagerBuilder .newCacheManagerBuilder().build(); cacheManager.init(); squareNumberCache = cacheManager .createCache("squaredNumber", CacheConfigurationBuilder .newCacheConfigurationBuilder( Integer.class, Integer.class, ResourcePoolsBuilder.heap(10))); } public Cache getSquareNumberCacheFromCacheManager() { return cacheManager.getCache("squaredNumber", Integer.class, Integer.class); } // standard getters and setters }

За да инициализираме нашия кеш, първо трябва да дефинираме обекта Ehcache CacheManager . В този пример създаваме кеш по подразбиране squaredNumber ” с API на newCacheManagerBuilder () .

Кешът просто ще преобразува Integer ключовете в Integer стойности.

Забележете как, преди да започнем да използваме дефинирания кеш, трябва да инициализираме обекта CacheManager с метода init () .

И накрая, за да получим нашия кеш, можем просто да използваме API на getCache () с предоставените типове име, ключ и стойност на нашия кеш.

С тези няколко реда създадохме първия си кеш, който вече е достъпен за нашето приложение.

3.2. XML конфигурация

Конфигурационният обект от подраздел 3.1. е равно на използването на тази XML конфигурация:

 java.lang.Integer java.lang.Integer 10 

И за да включим този кеш в нашето Java приложение, трябва да прочетем XML конфигурационния файл в Java:

URL myUrl = getClass().getResource(xmlFile); XmlConfiguration xmlConfig = new XmlConfiguration(myUrl); CacheManager myCacheManager = CacheManagerBuilder .newCacheManager(xmlConfig);

4. Ehcache тест

В раздел 3. показахме как можете да дефинирате прост кеш за вашите цели. За да покажем, че кеширането всъщност работи, ще създадем клас SquaredCalculator, който ще изчисли квадратната стойност на предоставения вход и ще съхрани изчислената стойност в кеша.

Разбира се, ако кешът вече съдържа изчислена стойност, ще върнем кешираната стойност и ще избегнем ненужни изчисления:

public class SquaredCalculator { private CacheHelper cache; public int getSquareValueOfNumber(int input) { if (cache.getSquareNumberCache().containsKey(input)) { return cache.getSquareNumberCache().get(input); } System.out.println("Calculating square value of " + input + " and caching result."); int squaredValue = (int) Math.pow(input, 2); cache.getSquareNumberCache().put(input, squaredValue); return squaredValue; } //standard getters and setters; }

За да завършим нашия тестов сценарий, ще ни е необходим и кодът, който ще изчисли квадратни стойности:

@Test public void whenCalculatingSquareValueAgain_thenCacheHasAllValues() { for (int i = 10; i < 15; i++) { assertFalse(cacheHelper.getSquareNumberCache().containsKey(i)); System.out.println("Square value of " + i + " is: " + squaredCalculator.getSquareValueOfNumber(i) + "\n"); } for (int i = 10; i < 15; i++) { assertTrue(cacheHelper.getSquareNumberCache().containsKey(i)); System.out.println("Square value of " + i + " is: " + squaredCalculator.getSquareValueOfNumber(i) + "\n"); } }

Ако стартираме нашия тест, ще получим този резултат в нашата конзола:

Calculating square value of 10 and caching result. Square value of 10 is: 100 Calculating square value of 11 and caching result. Square value of 11 is: 121 Calculating square value of 12 and caching result. Square value of 12 is: 144 Calculating square value of 13 and caching result. Square value of 13 is: 169 Calculating square value of 14 and caching result. Square value of 14 is: 196 Square value of 10 is: 100 Square value of 11 is: 121 Square value of 12 is: 144 Square value of 13 is: 169 Square value of 14 is: 196

Както можете да забележите, методът calcu () правеше изчисления само при първо извикване. При второто извикване всички стойности бяха намерени в кеша и върнати от него.

5. Други опции за конфигуриране на Ehcache

Когато създадохме кеша си в предишния пример, това беше обикновен кеш без специални опции. Този раздел ще покаже други опции, които са полезни при създаването на кеш.

5.1. Устойчивост на диска

Ако има твърде много стойности за съхранение в кеша, можем да съхраним някои от тези стойности на твърдия диск.

PersistentCacheManager persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder() .with(CacheManagerBuilder.persistence(getStoragePath() + File.separator + "squaredValue")) .withCache("persistent-cache", CacheConfigurationBuilder .newCacheConfigurationBuilder(Integer.class, Integer.class, ResourcePoolsBuilder.newResourcePoolsBuilder() .heap(10, EntryUnit.ENTRIES) .disk(10, MemoryUnit.MB, true)) ) .build(true); persistentCacheManager.close();

Вместо CacheManager по подразбиране , сега използваме PersistentCacheManager, който ще запази всички стойности, които не могат да бъдат записани в паметта.

От конфигурацията можем да видим, че кешът ще запази 10 елемента в паметта и ще отдели 10MB на твърдия диск за постоянство.

5.2. Изтичане на данните

Ако кешираме много данни, естествено е да запазваме кеширани данни за определен период от време, за да можем да избегнем голямо използване на паметта.

Ehcache контролира свежестта на данните чрез интерфейс за изтичане :

CacheConfiguration cacheConfiguration = CacheConfigurationBuilder .newCacheConfigurationBuilder(Integer.class, Integer.class, ResourcePoolsBuilder.heap(100)) .withExpiry(Expirations.timeToLiveExpiration(Duration.of(60, TimeUnit.SECONDS))).build();

В този кеш всички данни ще живеят в продължение на 60 секунди и след този период от време те ще бъдат изтрити от паметта.

6. Заключение

В тази статия показахме как да използваме просто кеширане на Ehcache в Java приложение.

В нашия пример видяхме, че дори просто конфигуриран кеш може да спести много ненужни операции. Също така показахме, че можем да конфигурираме кешове чрез POJO и XML и че Ehcache има доста приятни функции - като постоянство и изтичане на данните.

Както винаги, кодът от тази статия може да бъде намерен в GitHub.