Spring Cache – wstęp i praktyczne wykorzystanie możliwości

26/01/2021

Co to jest cache? Co to jest Spring Cache? Jak go skonfigurować w swoim projekcie i jak go używać? Jak działa Spring Cache? Jak dodać zewnętrzny provider pozwalający na elastyczne zarządzanie naszym cache’em?

To właśnie na te pytania chciałbym odpowiedzieć w tym artykule, a także przedstawić sposoby konfiguracji i możliwości wykorzystania cache’owania danych oferowane przez framework Spring.

Co to jest cache?

Cache to z języka angielskiego pamięć podręczna, i jest to mechanizm, który pozwala chwilowo przechowywać dane w pamięci, które już raz zostały użyte. Celem tego jest zwiększenie szybkości dostępu do tych informacji, w przypadku gdy będą one nam potencjalnie potrzebne w najbliższej przyszłości. Mechanizm ten pozwala ograniczyć ilość zapytań do bazy danych, czy też liczbę wywołań zewnętrznych serwisów, z których korzystamy.

Cache jest wykorzystywany praktycznie we wszystkich systemach. Zaczynając od sprzętu komputerowego, możemy go znaleźć w procesorach, w pamięci RAM, a także w najróżniejszych aplikacjach desktopowych, mobilnych czy internetowych.

Tworząc aplikacje mamy możliwość użycia wielu cache’y, które głównie skupiają się na cache’owaniu danych z bazy danych, a ich głównym zadaniem jest optymalizacja zapytań i przyspieszenie działania naszej aplikacji. Ja natomiast chciałbym się skupić na możliwości wykorzystania cache’a, którego udostępnia nam framework Spring, czyli Spring Cache.

Co to jest Spring Cache?

Spring pozwala wprowadzić nam abstrakcję cache’a, czyli udostępnia API, dzięki któremu możemy korzystać z cache’a. Pozwala ona skonfigurować cache’a w elastyczny sposób poprzez dodanie odpowiednich zależności oraz adnotacji. Dodatkowo, jeśli chcemy korzystać z zewnętrznego providera, również wystarczy dołożyć odpowiednie zależności i konfigurację.

To, co charakteryzuje omawianą przeze mnie bibliotekę to możliwość korzystania z niej na poziomie metod w naszej aplikacji przy użyciu adnotacji. Twórcy Springa zadbali również o to, aby cache z którego możemy korzystać, mógł być wykorzystywany w aplikacjach wielowątkowych. W Spring Cache możemy korzystać z jednego CacheManagera (interfejsu do zarządzania cache’em), ale także mamy możliwość korzystania z kilku na raz. Mamy możliwość dodania konfiguracji przechowywania danych czy czasu życia cache’a.

Wspierane przez Springa CacheManagery możemy podzielić na:
– korzystające z wewnętrznych mechanizmów Springa np.: ConcurrentMapCacheManager, SimpleCacheManager.
umożliwiające konfigurację zewnętrznych providerów np.: CaffeineCacheManager, EhCacheCacheManager, JCacheCacheManager, RedisCacheManager.

Jak skonfigurować oraz używać Spring Cache?

Konfiguracja Spring Cache oraz korzystanie z niego jest łatwe i intuicyjne, więc przejdźmy teraz do tego zagadnienia i sami się o tym przekonajmy. Moja przykładowa aplikacja korzysta ze Spring Boota oraz z Mavena, dlatego konfigurację rozpoczynam od dodania odpowiednich zależności w pliku pom.xml.

<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-cache</artifactId> 
</dependency> 

W przypadku gdy nasza aplikacja korzysta z samego Springa powinniśmy użyć:

<dependency> 
    <groupId>org.springframework</groupId> 
    <artifactId>spring-context</artifactId> 
    <version>5.1.8.RELEASE</version> 
</dependency>

Tak jak wspomniałem wyżej, konfiguracja i używanie Spring Cache opiera się na adnotacjach. Oczywiście możemy również korzystać ze starego sposobu, czyli konfiguracji w pliku XML, ale według mnie korzystanie z adnotacji jest bardziej intuicyjne i łatwiejsze w zrozumieniu, niż dokładanie kolejnych linii w xml.

Pierwszą adnotacją, z której powinniśmy skorzystać jest @EnableCaching w naszej klasie konfiguracyjnej:

@EnableCaching 
public class CacheConfig { 

    @Bean 
    public CacheManager cacheManager() { 
    SimpleCacheManager cacheManager = new SimpleCacheManager(); 
    Cache postsCache = new ConcurrentMapCache("posts"); 
    cacheManager.setCaches(Arrays.asList(postsCache)); 
    return cacheManager; 
    }  
};

Dzięki tej adnotacji możemy przejść do cache’owania danych. W Spring Cache odbywa się zazwyczaj w warstwie serwisów aplikacyjnych, ale zdarza się również, że cache jest dodawany na poziomie warstwy dostępu do danych (np. jeśli kilka serwisów korzysta z tych samych metod). Naszą przygodę z dodaniem cache’a na poszczególnych metodach zaczynamy od adnotacji @Cacheable. Adnotacja ta wykorzystywana jest na metodach, które pobierają dane, ale nie modyfikują ich. Posiada ona również parametry, które możemy, a nawet musimy ustawić.

@Cacheable(cacheNames = "PostsWithComments", key = "#page") 
public List<Post> getPostsWithComments(int page,Sort.Direction sort){ 
        List<Post> allPosts = postRepository.findAllPosts( 
        PareRequest.of(page, PAGE_SIZE, Sort.by(sort, "id") 
        )); 
        List<Long> ids=allPosts.stream() 
        .map(Post::getId) 
        .collect(Collectors.toList()); 
        List<Comment> comments =commentRepository.findAllByPostIdIn(ids); 
        allPosts.forEach( 
        post->post.setComment(extractComments(comments,post.getId()))); 
        return allPosts; 
} 

@Cacheable(cacheNames = "SinglePost") 
public Post getSinglePost(long id) { 
    return postRepository.findById(id).orElseThrow(); 
}

Parametrem, który należy ustawić jest cacheName. Pozwala on nadać nam nazwę naszego cache’a, co może być przydatne w konfiguracji np. zewnętrznego providera lub konfiguracji kilku CacheManager’ów.

Kolejny parametr to key, czyli klucz dodawany do naszego cache’a. Domyślnym generatorem kluczy w cache’u jest SimpleKeyGenerator, gdzie kluczem są wszystkie parametry w danej metodzie, ale czasami nie potrzebujemy ustalać go na podstawie wszystkich parametrów, dlatego możemy zdefiniować konkretnie jeden, używając do tego specjalnej składni, jaką jest Spring Expression Language (SpEL) tak jak w tym przykładzie key = ”#page’’. Jako klucza możemy użyć również własnej metody, która jest zdefiniowana wewnątrz klasy np. hashCode(). Wśród parametrów, które dostarcza nam @Cacheable są również keyGenerator gdzie możemy zdefiniować własny generator kluczy, cacheManager, condition, którym możemy określić przy pomocy SpEL kiedy cache ma przechowywać dane (np. condition = “#name.lenght < 32”) i kilka innych dodatkowych opcji.

Jeśli chodzi o keyGenerator, to Spring Cache korzysta z domyślnego keyGenerator’a, co czasami może stwarzać pewne problemy, gdy np. dwie metody korzystają z tego samego cache’a i posiadają te same parametry, które są domyślnie brane jako klucz. Wtedy może dojść do kolizji lub dane w cache’u będą nadpisywane przez inne metody. Dlatego dobrą praktyką jest definiowanie klucza, lub dodanie własnego keyGeneratora. Aby tego dokonać, musimy stworzyć własną klasę, która będzie nadpisywać domyślny generator kluczy. Musi ona implementować interfejs KeyGenerator, który udostępnia nam metodę generate(). To właśnie w niej możemy zdefiniować, jak mają się nadawać nasze klucze.

public class CustomKeyGenerator implements KeyGenerator { 
 
    @Override 
    public Object generate(Object target, Method method, Object... params) { 
    return target.getClass().getSimpleName() + "_" 
    + method.getName() + "_" 
    + StringUtils.arrayToDelimitedString(params, "_"); 
    } 
}

Dzięki temu mamy dwie możliwości użycia naszego generatora, jedną z nich jest zadeklarowanie beana w naszej klasie konfiguracyjnej:

@Configuration 
public class CacheConfig extends CachingConfigurerSupport { 
 
    @Bean("customKeyGenerator") 
    public KeyGenerator keyGenerator() { 
    return new CustomKeyGenerator(); 
    } 
}

Należy zwrócić uwagę, że klasa konfiguracyjna dziedziczy po klasie CachingConfigurerSupport, ponieważ pozwala nam to na utworzenie beana właśnie dla keyGenerator, ale także możemy stworzyć go dla cacheManager czy cacheResolver.

Natomiast drugim sposobem użycia jest dodanie odpowiednich parametrów na metodzie, która korzysta z adnotacji @Cacheable:

@Override 
@Cacheable(value = "authors", keyGenerator = "customKeyGenerator") 
public List<AuthorDto> getAll() { 
    return authorRepository.findAll().stream() 
            .map(AuthorMapper::toDto) 
            .collect(Collectors.toList()); 
}

Dzięki własnemu keyGeneratorowi możemy korzystać zarówno z domyślnego generatora kluczy jak i z własnego. Każda z metod może korzystać z innych generatorów kluczy, więc nie jesteśmy ograniczeni tylko do jednego z nich. Odbywa się to na zasadzie keyGenerator per metoda.

Jak działa Spring Cache?

Może teraz przejdźmy do kilku słów o tym, jak w ogóle działa Spring Cache. Mechanizm Spring Cache działa w oparciu o aspekty (Aspect Oriented Programming). Mamy tutaj aspekt, który odpowiada za tworzenie cache’a. Reaguje on na adnotację, w tym przypadku na @Cacheable na danej metodzie i tworzy on cache dla niej. Za całą tą czynność odpowiada klasa CacheInterceptor. Rozszerza ona klasę CacheAspectSupport oraz implementuje MethodInterceptor. Cały proces i działanie tego mechanizmu nie są proste do wyjaśnienia, ale najważniejszą rzeczą, którą należy wiedzieć, jest to, że klasa CacheInterceptor po prostu wywołuje odpowiednie metody nadklas w odpowiedniej kolejności.

Jeśli ktoś jest zainteresowany dokładnymi szczegółami tego mechanizmu zachęcam do przeczytania dokumentacji Springa – myślę, że jest to najlepsze źródło informacji.

Wspomniałem już o tym, że domyślnym cache managerem w Spring Cache jest ConcurrentMapCacheManager. To właśnie ten manager zapisuje cache w ConcurrentHashMap i dla każdego naszego cache’a używana jest klasa ConcurrentMapCache. Klasa ta również zapisuje dane w ConcurrentHashMap, a w polu store zapisywane są poszczególne wpisy dla naszego cache’a.

public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderAware { 
    private final ConcurrentMap<String, Cache> cacheMap =  
                  new ConcurrentHashMap(16); 
    private boolean dynamic = true; 
    private boolean allowNullValues = true; 
    private boolean storeByValue = false; 
    @Nullable 
    private SerializationDelegate serialization; 
 
    public ConcurrentMapCacheManager() { 
    }

 

public class ConcurrentMapCache extends AbstractValueAdaptingCache { 
    private final String name; 
    private final ConcurrentMap<Object, Object> store; 
    @Nullable 
    private final SerializationDelegate serialization; 
 
    public ConcurrentMapCache(String name) { 
    this(name, new ConcurrentHashMap(256), true); 
    } 
 
    public ConcurrentMapCache(String name, boolean allowNullValues) { 
    this(name, new ConcurrentHashMap(256), allowNullValues); 
    }

Generalnie dzięki temu, nasz cache działa. Niestety, domyślny cache manager nie daje nam możliwości zarządzania naszym cache’em: nie możemy wyczyścić danego cache’a po określonym czasie, nie możemy ustalić limitu danych, które mają być zapisywane, więc wszystkie operacje do zarządzania cache’em są po naszej stronie, do wykonywania „ręcznie”.

W tym przypadku pomocne mogą się okazać dodatkowe adnotacje, które udostępnia nam Spring Cache.
Warto wspomnieć o adnotacji @CachePut. Adnotacja ta dodawana jest na metodach, które modyfikują dane. Pozwala ona na to, że gdy metoda z tą adnotacją jest wywoływana, to aktualizuje ona dany wpis w cache’u, dzięki czemu zawsze mamy najświeższe zmiany, z których możemy skorzystać. Ważne jest tutaj dodanie parametrów jak w adnotacji @Cacheable. Czyli musimy ustawić cacheName oraz key. W tym przykładzie chcemy, żeby naszym kluczem było id, dlatego musimy je wyciągnąć z result (jest to specyficzna nazwa w SpEL’u i jest to obiekt, który zwraca nam dana metoda, czyli postEdited = result):

@Transactional 
@CachePut(cacheNames = "SinglePost", key = "#result.id") 
public Post editPost(Post post) { 
   Post postEdited = postRepository.findById(post.getId()).orElseThrow(); 
   postEdited.setTitle(post.getTitle()); 
   postEdited.setContent(post.getContent()); 
   return postEdited; 
} 

Ostatnią adnotacją, o której chciałbym tutaj wspomnieć jest adnotacja @CacheEvict, która pozwala nam na czyszczenie cache’a. Dodajemy ją na metodach, które usuwają dane. Dzięki temu w przypadku wywołania metody usuwającej jakieś dane, nasz cache również będzie czyszczony z tego wpisu. Pozwala to zaoszczędzić miejsce w pamięci cache’a i jest go trudniej przepełnić, ponieważ nie posiada on niepotrzebnych danych, ale także pozwala zachować spójność pomiędzy głównym źródłem danych, a cache’em. Tradycyjnie obowiązkowe jest dodanie cacheName oraz key, ale w tym przypadku key możemy pominąć, ponieważ kluczem będzie id, które jest w parametrze metody:

@CacheEvict(cacheNames = "SinglePost") 
public void deletePost(long id) { 
    postRepository.deleteById(id); 
} 

Jak widzimy, domyślny cache manager pozwala nam kontrolować cache w minimalnym stopniu, ale wystarczającym do poprawnego jego działania. Dzięki zewnętrznym provider’om możemy nadać większą elastyczność cache’om np. zdefiniować ilości danych jaka może się zapisywać w cache’u, ustalić po jakim czasie nasz cache powinien się czyścić. Dodatkowym plusem zewnętrznych provider’ów jest to, że pozwalają one na dłuższe życie cache’a niż samej aplikacji. Taką możliwość daje nam np. Redis (o którym więcej informacji będzie niżej w tym artykule), który działa osobno niezależnie od aplikacji. Nasza aplikacja może zostać zrestartowana, a dane w cache’u będą nadal przechowywane, podczas gdy ConcurrentHashMap zostaje wyczyszczone po restarcie aplikacji. W Springu możemy skorzystać z provider’ów które są określone w klasie CacheConfiguration:

final class CacheConfigurations { 
    private static final Map<CacheType, Class<?>> MAPPINGS; 
 
    private CacheConfigurations() { 
    } 
    . 
    . 
    . 

static { 
Map<CacheType, Class<?>> mappings = new EnumMap(CacheType.class); 
    mappings.put(CacheType.GENERIC, GenericCacheConfiguration.class); 
    mappings.put(CacheType.EHCACHE, EhCacheCacheConfiguration.class); 
    mappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class); 
    mappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class); 
    mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class); 
    mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class); 
    mappings.put(CacheType.REDIS, RedisCacheConfiguration.class); 
    mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class); 
    mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class); 
    mappings.put(CacheType.NONE, NoOpCacheConfiguration.class); 
    MAPPINGS = Collections.unmodifiableMap(mappings); 
} 

Skoro domyślny cache manager nie pozwala nam na swobodną konfigurację naszego cache’a, użyjmy zewnętrznego providera i skonfigurujmy go tak, aby spełniał nasze potrzeby, oraz wykorzystajmy jego możliwości w celu łatwiejszego i lepszego sterowania przechowywanymi danymi.

Jak dodać zewnętrzny provider?

W tym przykładzie użyjemy EhCache, który daje nam trzy możliwości zapisywania danych:

– MemoryStore – czyli zapisywanie na heapie, tzn. że zapisujemy dane w stercie JVM, ale minusem tutaj jest to, że dane te obsługiwane są przez Garbage Collector

– OffHeapStore – czyli zapisywanie poza heapem, tutaj już Garbage Collector nie działa, ale też zapisywanie danych jest wolniejsze niż w przypadku zapisywania danych na heapie.

– DiskStore – czyli zapisywanie danych na dysku.

Dodatkowo EhCache korzysta z algorytmu Least Recently Used (LRU) co oznacza, że najstarsze elementy, najrzadziej używane są usuwane pierwsze z cache’a jeśli zostanie on przepełniony.

W takim razie przejdźmy do konfiguracji i podstawowych możliwości użycia go. Pierwszą rzeczą, którą musimy wykonać jest dodanie zależności w naszym pliku pom.xml:

<dependency> 
    <groupId>org.ehcache</groupId> 
    <artifactId>ehcache</artifactId> 
    <version>3.5.3</version> 
</dependency> 
<dependency> 
    <groupId>javax.cache</groupId> 
    <artifactId>cache-api</artifactId> 
    <version>1.1.1</version> 
</dependency>

Oraz od dodania nowego properties’a w pliku application.properties:

spring.cache.jcache.config=classpath:ehcache.xml 

Properties ten wskazuje nam plik konfiguracyjny dla EhCache’a, który w kolejnym kroku musimy dodać. W tym przykładzie plik nazywa się ehcache.xml i wygląda następująco:

<config xmlns="http://www.ehcache.org/v3" 
        xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:jsr107 ="http://www.ehcache.org/v3/jsr107" 
        xsi:schemaLocation ="http://www.ehcache.org/v3  
https://www.ehcache.org/schema/ehcache-core-3.0.xsd"> 
     
    <cache-template name="default"> 
        <expiry> 
            <ttl unit="hours">1</ttl> 
        </expiry> 
        <heap unit="entries">1000</heap> 
    </cache-template> 
     
    <cache alias="PostsWithComments" uses-template="default"/> 
     
    <cache alias="SinglePost"> 
        <expiry> 
            <ttl unit="hours">2</ttl> 
        </expiry> 
        <heap unit="entries">500</heap> 
    </cache> 
</config

Cała konfiguracja naszego cache’a odbywa się teraz właśnie tutaj. EhCache pozwala nam na utworzenie konkretnego template’a, z którego będziemy mogli korzystać w kilku cache’ach.

W przykładzie został utworzony template o nazwie default, w którym jednym z ustawień jest sekcja expiry, w której możemy ustalić czas, po jakim nasz wpis ma być usunięty z cache’a (ttl) lub czas, po jakim nasz cache ma być czyszczony w przypadku braku odpytywania go (tti). Kolejną rzeczą, jaką możemy ustawić jest heap, czyli ilość elementów, które mają być przechowywane w cache’u. Dostępnych jest znacznie więcej opcji konfiguracji – zachęcam do przeczytania dokumentacji, w której możemy poznać dodatkowe opcje, ale w tym przykładzie chciałem pokazać tylko podstawowe funkcje wykorzystania tego providera.

Kolejnym etapem jest wywołanie naszego template na konkretnym cache’u, czyli <cache alias…, gdzie podajemy nazwę cache’a dodanego przez nas (dlatego nadanie nazwy w adnotacji @Cacheable jest konieczne) i użycie danego template (uses-template). Możemy oczywiście też skonfigurować jednego konkretnego cache’a, co zostało pokazane wyżej dla SinglePost.

Jeśli nie EhCache, to co innego?

Do tematu dodawania zewnętrznego providera warto też wspomnieć o Redis. Od jakiegoś czasu staje się standardem, który uznawany jest jako default, jeżeli chodzi o bazę klucz – wartość do cache’owania danych. Jest on magazynem danych w pamięci, używanym jako baza danych i pamięć podręczna.

Żeby móc korzystać z Redis, możemy uruchomić go z wykorzystaniem obrazu Dockerowego lub zainstalować go bezpośrednio na naszym systemie. Na potrzeby tego artykułu zakładamy, że mamy to już zrobione i możemy skupić się tylko na wykorzystaniu cache’a.

Przed rozpoczęciem wykorzystania Redisa jako pamięć podręczną należy wspomnieć
o podstawowych parametrach konfiguracyjnych, takich jak maksymalna ilość pamięci, algorytmy czyszczenia i trwałość.

1. Maksymalna ilość pamięci – domyślnie Redis nie ma limitów pamięci w systemach 64-bitowych, natomiast w systemach 32-bitowych maksymalna pamięć wynosi 3 GB.

2. Algorytmy czyszczenia – gdy rozmiar pamięci podręcznej osiąga swój limit, stare dane są usuwane, aby zrobić miejsce na nowe. Tutaj wyróżniamy dwie strategię usuwania starych danych:
 – Least Recently Used (LRU) – gdy dojdzie do przepełnienia pamięci klucze, które były używane jako ostatnie (najstarsze), zostaną usunięte.
– Least Frequently Used (LFU) – Redis policzy, ile razy dany klucz był używany i na podstawie tego, klucze z większą ilością użyć zostaną dłużej przechowane niż klucze, które były użyte np. Raz.

3. Trwałość – na starcie cache jest zawsze pusty, czasami z niezależnych przyczyn możemy utracić połączenie, lub nastąpi restart Redis, dlatego warto korzystać ze snapshotów, które pomogą nam w odzyskaniu danych w cache’u.
Redis posiada dwa typy wykonywania snapshotów:
– RDB – wykonuje migawki w interwałach i w konfiguracji to my określamy, co ile (np. sekund), ma się wykonać zapis oraz gdy zmieni się ustalona przez nas ilość kluczy. Zapis ten odbywa się do pliku w formacie .rdb. W przypadku awarii lub wyłączenia Redisa, po ponownym uruchomieniu możemy posiadać dane ostatnio zapisane do pliku, które niekoniecznie mogą odzwierciedlać stan zaraz sprzed restartu.
– AOF – wykonuje migawkę po każdej operacji zapisu odebraną przez serwer. Dzięki temu dane są zawsze aktualne, a w przypadku uruchomienia od nowa Redisa, przywraca on stan cache’a do stanu sprzed awarii/wyłączenia.
Zachęcam do przeczytania dokumentacji Redisa, w której uwzględniono plusy i minusy każdego z tych typów snapshotów.

Konfiguracja samego cache’a w Redis polega na ustawieniu wyżej wspomnianych parametrów w pliku konfiguracyjnym redis.conf, który znajduje się po stronie Redis, a nie w naszym projekcie, tak jak było to w przypadku EhCache.

#memory limit up to 128MB 
maxmemory 128mb 
#remove the last recently used (LRU) keys first 
maxmemory-policy allkeys-lru 

Tutaj jako przykład dodałem konfigurację, gdzie maksymalna ilość przechowywanych danych nie może przekroczyć 128 MB, a dane z cache’a będą usuwane na podstawie strategii LRU.

Konfigurację rozpoczynamy oczywiście od dodania zależności do naszego pliku pom.xml:

<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-data-redis</artifactId> 
</dependency>

Kolejnym krokiem jest dodanie odpowiednich properties’ów w pliku application.properties:

spring.cache.type=redis 
spring.redis.host=localhost 
spring.redis.port=6379 

Ustawienia te definiują nam lokalizację usług cache’a.

Samo korzystanie z tego cache’a jest identyczne jak w przypadku korzystania z domyślnego cacheManager’a w Spring Cache. Czyli najprościej mówiąc, wykorzystujemy wspomniane już wyżej w tym artykule adnotacje: @EnableCaching – w naszej klasie konfiguracyjnej, @Cacheable, @CachePut, @CacheEvict. Różnicą może być tutaj to, że w każdej adnotacji musi być zdefiniowany parametr key przy użyciu SpEL:

@Cacheable(value = "author", key = "#id") 
@GetMapping(value = "/author/{id}") 
public ResponseEntity<AuthorDto> get(@PathVariable long id) throws NotFoundException { 
    log.info("User try to get author with id: {}", id); 
    AuthorDto authorDto = authorService.get(id); 
    return new ResponseEntity<>(authorDto, HttpStatus.OK); 
} 

@CachePut(value = "author", key = "#id") 
@PutMapping(value = "/author/{id}") 
public ResponseEntity<AuthorDto> update(@Valid @RequestBody AuthorDto authorDto, @PathVariable long id) throws NotFoundException { 
    log.info("User try to update author with id: {}", id); 
    authorService.update(id, authorDto); 
    return new ResponseEntity<>(authorDto, HttpStatus.OK); 
} 

Redis daje nam również możliwość śledzenia różnych statystyk, takich jak:
– hit/miss ratio – czyli stosunek trafionych zapytań o dany klucz, do nietrafionych
– latency – opóźnienie, czyli maksymalną długość pomiędzy żądaniem, a odpowiedzią
– evicted keys – czyli usunięte klucze po przepełnieniu maksymalnego rozmiaru pamięci

Podsumowanie

Jak widać, korzystanie z cache’a jest ważne w aplikacji, gdy chcemy, żeby była ona szybka i wydajna. Cache jest bardzo ważną częścią systemu i nie powinniśmy go pomijać. Wspólnie udało nam się dowiedzieć, co to jest Spring Cache, jakie daje on nam możliwości, jak go skonfigurować, jak działa on „w środku” oraz dodaliśmy zewnętrzne providery, które pozwalają nam na lepszą kontrolę i konfigurację pod nasze potrzeby przechowywania danych w cache’u. Okazuje się, że sama konfiguracja nie jest skomplikowana, a wnosi spore usprawnienie w kontekście działania aplikacji.

Marcin Dziedzic, Młodszy Programista Java
Altkom Software & Consulting

To Cię może również zainteresować:

For a long time, we have relied on Java 8 for most of our projects. But with recent announcements from […]

Building Microservices with Micronaut

04/09/2018
Technologie
Speed of feature delivery is the key property of microservice-based architectures. We use this architectural style to deliver solutions faster […]
Front-end aplikacji to przede wszystkim JavaScript, HTML i CSS. JavaScript i jego różne “wariacje” to podstawa przy pracy na “froncie”. […]

Zarejestruj się na webinar:

Wyrażam dobrowolnie zgodę na przetwarzanie moich danych osobowych dla potrzeb procesu realizacji zgłoszenia (pokaż więcej) przez Altkom Experts sp. z o.o. oraz Altkom Software & Consulting sp. z o.o. (ul. Chłodna 51, 00-867 Warszawa), zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych („RODO”). Mam świadomość, iż podanie powyższych danych osobowych jest dobrowolne, ale konieczne do obsługi zgłoszenia oraz że posiadam prawo dostępu do treści swoich danych i możliwość ich poprawiania a zgoda może być odwołana w każdym czasie. Kontakt do inspektora ochrony danych osobowych w Altkom: iodo@altkom.pl

Wyrażam dobrowolnie zgodę na przetwarzanie moich danych osobowych w celach marketingowych (pokaż więcej)przez Altkom Experts sp. z o.o. oraz Altkom Software & Consulting sp. z o.o. (ul. Chłodna 51, 00-867 Warszawa)oraz otrzymywanie informacji handlowych drogą elektroniczną na adres e-mail i numer telefonu podany przeze mnie, zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych („RODO”), oraz Ustawy z dnia 18 lipca 2002 r. o świadczeniu usług drogą elektroniczną. Mam świadomość, iż podanie powyższych danych osobowych jest dobrowolne oraz że posiadam prawo dostępu do treści swoich danych i możliwość ich poprawiania a zgoda może być odwołana w każdym czasie. Kontakt do inspektora ochrony danych osobowych w Altkom: iodo@altkom.pl

 

Watch for free

Enter your contact details to receive a link to the recording:

I voluntarily consent to the processing of my personal data for the purposes of the application process (show more) by Altkom Experts sp. z o.o. and Altkom Software & Consulting sp. z o.o. (51 Chłodna Street, 00-867 Warsaw), in accordance with Regulation 2016/679 of the European Parliament and of the Council of 27 April 2016 on the protection of individuals with regard to the processing of personal data and on the free movement of such data ("RoDO"). I am aware that providing the above personal data is voluntary, but necessary to handle the request, and that I have the right to access the content of my data and the possibility of correcting it, and that my consent may be revoked at any time. Please contact the Altkom Data Protection Officer: iodo@altkom.pl.

I voluntarily consent to the processing of my personal data for marketing purposes (show more)by Altkom Experts sp. z o.o. and Altkom Software & Consulting sp. z o.o. (ul. Chłodna 51, 00-867 Warsaw) and receiving commercial information by electronic means to the e-mail address and telephone number provided by me, in accordance with Regulation 2016/679 of the European Parliament and of the Council of 27 April 2016 on the protection of individuals with regard to the processing of personal data and on the free movement of such data ("RODO"), and the Act of 18 July 2002 on the provision of electronic services. I am aware that providing the above personal data is voluntary and that I have the right to access and correct my data and that my consent may be revoked at any time. Please contact the Altkom Data Protection Officer: iodo@altkom.pl.

 

Zarejestruj się na webinar:

Wyrażam dobrowolnie zgodę na przetwarzanie moich danych osobowych dla potrzeb procesu realizacji zgłoszenia (pokaż więcej) przez Altkom Experts sp. z o.o. oraz Altkom Software & Consulting sp. z o.o. (ul. Chłodna 51, 00-867 Warszawa), zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych („RODO”). Mam świadomość, iż podanie powyższych danych osobowych jest dobrowolne, ale konieczne do obsługi zgłoszenia oraz że posiadam prawo dostępu do treści swoich danych i możliwość ich poprawiania a zgoda może być odwołana w każdym czasie. Kontakt do inspektora ochrony danych osobowych w Altkom: iodo@altkom.pl

Wyrażam dobrowolnie zgodę na przetwarzanie moich danych osobowych w celach marketingowych (pokaż więcej)przez Altkom Experts sp. z o.o. oraz Altkom Software & Consulting sp. z o.o. (ul. Chłodna 51, 00-867 Warszawa)oraz otrzymywanie informacji handlowych drogą elektroniczną na adres e-mail i numer telefonu podany przeze mnie, zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych („RODO”), oraz Ustawy z dnia 18 lipca 2002 r. o świadczeniu usług drogą elektroniczną. Mam świadomość, iż podanie powyższych danych osobowych jest dobrowolne oraz że posiadam prawo dostępu do treści swoich danych i możliwość ich poprawiania a zgoda może być odwołana w każdym czasie. Kontakt do inspektora ochrony danych osobowych w Altkom: iodo@altkom.pl

 

Zarejestruj się na webinar:

Wyrażam dobrowolnie zgodę na przetwarzanie moich danych osobowych dla potrzeb procesu realizacji zgłoszenia (pokaż więcej) przez Altkom Experts sp. z o.o. oraz Altkom Software & Consulting sp. z o.o. (ul. Chłodna 51, 00-867 Warszawa), zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych („RODO”). Mam świadomość, iż podanie powyższych danych osobowych jest dobrowolne, ale konieczne do obsługi zgłoszenia oraz że posiadam prawo dostępu do treści swoich danych i możliwość ich poprawiania a zgoda może być odwołana w każdym czasie. Kontakt do inspektora ochrony danych osobowych w Altkom: iodo@altkom.pl

Wyrażam dobrowolnie zgodę na przetwarzanie moich danych osobowych w celach marketingowych (pokaż więcej)przez Altkom Experts sp. z o.o. oraz Altkom Software & Consulting sp. z o.o. (ul. Chłodna 51, 00-867 Warszawa)oraz otrzymywanie informacji handlowych drogą elektroniczną na adres e-mail i numer telefonu podany przeze mnie, zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych („RODO”), oraz Ustawy z dnia 18 lipca 2002 r. o świadczeniu usług drogą elektroniczną. Mam świadomość, iż podanie powyższych danych osobowych jest dobrowolne oraz że posiadam prawo dostępu do treści swoich danych i możliwość ich poprawiania a zgoda może być odwołana w każdym czasie. Kontakt do inspektora ochrony danych osobowych w Altkom: iodo@altkom.pl

 

Zarejestruj się na webinar:

Wyrażam dobrowolnie zgodę na przetwarzanie moich danych osobowych dla potrzeb procesu realizacji zgłoszenia (pokaż więcej) przez Altkom Experts sp. z o.o. oraz Altkom Software & Consulting sp. z o.o. (ul. Chłodna 51, 00-867 Warszawa), zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych („RODO”). Mam świadomość, iż podanie powyższych danych osobowych jest dobrowolne, ale konieczne do obsługi zgłoszenia oraz że posiadam prawo dostępu do treści swoich danych i możliwość ich poprawiania a zgoda może być odwołana w każdym czasie. Kontakt do inspektora ochrony danych osobowych w Altkom: iodo@altkom.pl

Wyrażam dobrowolnie zgodę na przetwarzanie moich danych osobowych w celach marketingowych (pokaż więcej)przez Altkom Experts sp. z o.o. oraz Altkom Software & Consulting sp. z o.o. (ul. Chłodna 51, 00-867 Warszawa)oraz otrzymywanie informacji handlowych drogą elektroniczną na adres e-mail i numer telefonu podany przeze mnie, zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych („RODO”), oraz Ustawy z dnia 18 lipca 2002 r. o świadczeniu usług drogą elektroniczną. Mam świadomość, iż podanie powyższych danych osobowych jest dobrowolne oraz że posiadam prawo dostępu do treści swoich danych i możliwość ich poprawiania a zgoda może być odwołana w każdym czasie. Kontakt do inspektora ochrony danych osobowych w Altkom: iodo@altkom.pl