{"id":5513,"date":"2019-06-11T12:48:08","date_gmt":"2019-06-11T16:48:08","guid":{"rendered":"http:\/\/springframework.guru\/?p=5513"},"modified":"2024-10-21T09:49:12","modified_gmt":"2024-10-21T13:49:12","slug":"using-ehcache-3-in-spring-boot","status":"publish","type":"post","link":"https:\/\/springframework.guru\/using-ehcache-3-in-spring-boot\/","title":{"rendered":"How to Use Ehcache 3 With Spring Boot"},"content":{"rendered":"<h2>1. Introduction<\/h2>\n<p>In today&#8217;s blog post we will look at how we can use the caching provider <a href=\"https:\/\/www.ehcache.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">Ehcache<\/a> in Spring Boot. Ehcache is an open source library implemented in Java for implementing caches in Java programs, especially local and distributed caches in main memory or on the hard disk. Thanks to the implementation of JSR-107, Ehcache is fully compatible with the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">javax.cache<\/code> API. Due to this compatibility, integration into Spring or Hibernate is very easy.<\/p>\n<p>Before we start, we will have a quick look at what a cache is and in which scenarios a cache makes sense. Then we&#8217;ll take a quick look at how caching works in Spring. For the main part of the post, I brought along a demo project with some code.<\/p>\n<h2>2. Caching<\/h2>\n<p>Caching is a technique that involves the intermediate storage of data in very fast memory, usually. This means that this data can be made available much more quickly for subsequent requests since it does not have to be retrieved or recalculated from the primary and usually slower memory first.<\/p>\n<p>Caching is particularly useful for the following scenarios:<\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul style=\"list-style-type: square;\">\n<li>The same data is requested again and again (so-called hot spots), which have to be loaded from the database anew with each request. This data can be cached in the main memory of the server application (RAM) or on the client (browser cache). This reduces access times and the number of data transfers since the server does not have to repeatedly request data from the database and send it to the client.<\/li>\n<li>Long-term or resource-intensive operations are often performed with specific parameters. Depending on the parameters, the result of the operation can be stored temporarily so that the server can send the result to the client without executing the operation.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>3. Caching in Spring<\/h2>\n<p>In Spring or Spring Boot it is very easy to add caching to an application. All you need to do is activate caching support via Annotation <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@EnableCaching<\/code>. As we are used to from Spring Boot, the entire caching infrastructure is configured for us.<\/p>\n<p>Springs Caching Service is an abstraction and not an implementation. Therefore it is necessary to use a cache provider or cache implementation for caching. Spring supports a wide range of cache providers:<\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul style=\"list-style-type: square;\">\n<li><a href=\"https:\/\/www.ehcache.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">Ehcache 3<\/a> (we will have a look at this today)<\/li>\n<li><a href=\"https:\/\/hazelcast.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">Hazelcast<\/a><\/li>\n<li><a href=\"https:\/\/infinispan.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">Infinispan<\/a><\/li>\n<li><a href=\"https:\/\/www.couchbase.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">Couchbase<\/a><\/li>\n<li><a href=\"https:\/\/redis.io\/\" target=\"_blank\" rel=\"noopener noreferrer\">Redis<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/ben-manes\/caffeine\" target=\"_blank\" rel=\"noopener noreferrer\">Caffeine<\/a><\/li>\n<li><a href=\"https:\/\/pivotal.io\/en\/pivotal-gemfire\" target=\"_blank\" rel=\"noopener noreferrer\">Pivotal GemFire<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>A change of the cache provider has no effect on the existing code, as the developer only gets in touch with the abstract concepts.<\/p>\n<p>If no cache provider is added, Spring Boot configures a very simple provider that caches in main memory using maps. This is sufficient for testing, but for applications in production, you should choose one of the above cache providers.<\/p>\n<h2>4. Ehcache Caching Tiers<\/h2>\n<p>Ehcache can be configured in such a way that the caching layer can consist of more than one memory area. When using more than one memory area, the areas are arranged as hierarchical tiers. The lowest tier is called the <em>Authority Tier<\/em> and the other tiers are called the <em>Near Cache<\/em>.<\/p>\n<p>The most frequently used data is stored in the fastest caching tier (top layer). The authority tier basically contains all cache entries.<\/p>\n<p>The memory areas supported by Ehcache include:<\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul style=\"list-style-type: square;\">\n<li><strong>On-Heap Store<\/strong>: Uses the Java heap memory to store cache entries and shares the memory with the application. The cache is also scanned by the garbage collection. This memory is very fast, but also very limited.<\/li>\n<li><strong>Off-Heap Store<\/strong>: Uses the RAM to store cache entries. This memory is not subject to garbage collection. Still quite fast memory, but slower than the on-heap memory, because the cache entries have to be moved to the on-heap memory before they can be used.<\/li>\n<li><strong>Disk Store<\/strong>: Uses the hard disk to store cache entries. Much slower than RAM. It is recommended to use a dedicated SSD that is only used for caching.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>In our demo project, we will use a three-tier cache with a disk store as an authority tier.<\/p>\n<h2>5. Ehcache Demo<\/h2>\n<h3>5.1 Used Dependencies<\/h3>\n<p>For the Ehcache demo project we need the following dependencies in our Spring Boot based application:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\">&lt;dependency&gt;\n    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n    &lt;artifactId&gt;spring-boot-starter-web&lt;\/artifactId&gt;\n&lt;\/dependency&gt;\n&lt;dependency&gt;\n    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n    &lt;artifactId&gt;spring-boot-starter-cache&lt;\/artifactId&gt;\n&lt;\/dependency&gt;\n&lt;dependency&gt;\n    &lt;groupId&gt;javax.cache&lt;\/groupId&gt;\n    &lt;artifactId&gt;cache-api&lt;\/artifactId&gt;\n&lt;\/dependency&gt;\n&lt;dependency&gt;\n    &lt;groupId&gt;org.ehcache&lt;\/groupId&gt;\n    &lt;artifactId&gt;ehcache&lt;\/artifactId&gt;\n    &lt;version&gt;3.7.1&lt;\/version&gt;\n&lt;\/dependency&gt;<\/pre>\n<p>The dependency <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">spring-boot-starter-web<\/code>is a starter for building web applications. In our example, we will build a simple service that performs a calculation for us. The calculation can be triggered by using a REST endpoint.<\/p>\n<p>For caching we need <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">spring-boot-starter-cache<\/code>\u00a0and <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">cache-api<\/code> dependency as well as the dependency <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">ehcache<\/code> as a cache provider.<\/p>\n<h3>5.2 Enable Caching<\/h3>\n<p>To enable caching support in Spring Boot, we need a simple configuration class that must be annotated with <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@EnableCaching<\/code>. Up to this point, we don&#8217;t need to do anything more as the following code shows:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Configuration\n@EnableCaching\npublic class EhcacheConfig {\n}<\/pre>\n<h3>5.3 Cacheable Operation<\/h3>\n<p>We start our example with a simple service that calculates the area of a circle. The formula <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">A = PI * radius\u00b2 <\/code> is used to calculate the area. The code is as follows:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Service\npublic class CalculationService {\n\n  private final Logger LOG = LoggerFactory.getLogger(CalculationService.class);\n\n  public double areaOfCircle(int radius) {\n    LOG.info(\"calculate the area of a circle with a radius of {}\", radius);\n    return Math.PI * Math.pow(radius, 2);\n  }\n}<\/pre>\n<p>Caching in Spring is basically applied to methods so that especially the calls of very costly operations can be reduced. We now want to add the result of this calculation to a cache depending on the radius passed by parameter, so that the calculation does not have to be repeated every time. To do this, we annotate the method with the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Cachable<\/code> annotation:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Cacheable(value = \"areaOfCircleCache\", key = \"#radius\", condition = \"#radius &gt; 5\")\npublic double areaOfCircle(int radius) {\n  LOG.info(\"calculate the area of a circle with a radius of {}\", radius);\n  return Math.PI * Math.pow(radius, 2);\n}<\/pre>\n<p>Each time this method is called with a radius greater than 5, the caching behavior is applied. This checks whether the method has already been called once for the specified parameter. If so, the result is returned from the cache and the method is not executed. If no, then the method is executed and the result is returned and stored in the cache.<\/p>\n<p>The following parameters, among others, are available for annotation:<\/p>\n<table style=\"border-collapse: collapse; width: 100%;\">\n<tbody>\n<tr>\n<td style=\"width: 23.3535%;\"><strong>Annotation parameter<\/strong><\/td>\n<td style=\"width: 76.6465%;\"><strong>Description<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 23.3535%;\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">value \/ cacheNames<\/code><\/td>\n<td style=\"width: 76.6465%;\">Name of the cache in which the results of the method execution are to be stored.<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 23.3535%;\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">key<\/code><\/td>\n<td style=\"width: 76.6465%;\">The key for the cache entries as <a href=\"http:\/\/springframework.guru\/introduction-spring-expression-language-spel\/\" target=\"_blank\" rel=\"noopener noreferrer\">Spring Expression Language (SpEL)<\/a>. If the parameter is not specified, a key is created for all method parameters by default.<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 23.3535%;\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">keyGenerator<\/code><\/td>\n<td style=\"width: 76.6465%;\">Name of a bean that implements the KeyGenerator interface and thus allows the creation of a user-defined cache key.<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 23.3535%;\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">condition<\/code><\/td>\n<td style=\"width: 76.6465%;\">Condition as Spring Expression Language (SpEL) that specifies when a result is to be cached.<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 23.3535%;\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">unless<\/code><\/td>\n<td style=\"width: 76.6465%;\">Condition as Spring Expression Language (SpEL) that specifies when a result should not be cached.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>5.4 Ehcache Cache Configuration<\/h3>\n<p>Now the configuration of the Ehcache cache has to be done. The configuration is XML-based. We create the XML file <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">ehcache.xml<\/code> in the resource folder of our application.<\/p>\n<h4>5.4.1 Cache Template<\/h4>\n<p>First, we will define a cache template. This is especially advantageous if the application is to have more than one cache, but the configuration of the caches is largely the same. For our demo application it is conceivable, for example, that we want to cache the results of the circle area calculation and in another cache the results of a power calculation. For the cache template we use the following XML code:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\">&lt;config\n        xmlns:xsi='http:\/\/www.w3.org\/2001\/XMLSchema-instance'\n        xmlns='http:\/\/www.ehcache.org\/v3'\n        xsi:schemaLocation=\"\n            http:\/\/www.ehcache.org\/v3 \n            http:\/\/www.ehcache.org\/schema\/ehcache-core-3.7.xsd\"&gt;\n\n    &lt;!-- Persistent cache directory --&gt;\n    &lt;persistence directory=\"spring-boot-ehcache\/cache\" \/&gt;\n\n    &lt;!-- Default cache template --&gt;\n    &lt;cache-template name=\"default\"&gt;\n        &lt;expiry&gt;\n            &lt;ttl unit=\"seconds\"&gt;30&lt;\/ttl&gt;\n        &lt;\/expiry&gt;\n\n        &lt;listeners&gt;\n            &lt;listener&gt;\n                &lt;class&gt;guru.springframework.ehcache.config.CacheLogger&lt;\/class&gt;\n                &lt;event-firing-mode&gt;ASYNCHRONOUS&lt;\/event-firing-mode&gt;\n                &lt;event-ordering-mode&gt;UNORDERED&lt;\/event-ordering-mode&gt;\n                &lt;events-to-fire-on&gt;CREATED&lt;\/events-to-fire-on&gt;\n                &lt;events-to-fire-on&gt;EXPIRED&lt;\/events-to-fire-on&gt;\n                &lt;events-to-fire-on&gt;EVICTED&lt;\/events-to-fire-on&gt;\n            &lt;\/listener&gt;\n        &lt;\/listeners&gt;\n\n        &lt;resources&gt;\n            &lt;heap&gt;1000&lt;\/heap&gt;\n            &lt;offheap unit=\"MB\"&gt;10&lt;\/offheap&gt;\n            &lt;disk persistent=\"true\" unit=\"MB\"&gt;20&lt;\/disk&gt;\n        &lt;\/resources&gt;\n    &lt;\/cache-template&gt;\n\n&lt;\/config&gt;<\/pre>\n<h5>persistence Tag<\/h5>\n<p>In the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">persistence<\/code> tag, we define the directory for a file-based cache on the hard disk (disk store). This is only the definition of the folder. Whether we really want to use a disk store or not will be configured later.<\/p>\n<h5>expiry Tag<\/h5>\n<p>In the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">expiry<\/code> tag, we define a <em>time to live<\/em> (ttl) of 30 seconds. The time to live specifies how long a cache entry may remain in the cache independently of access. After the specified time has expired, the value is removed from the cache.<\/p>\n<p>It is also possible to define a <em>time to idle<\/em> (tti). The time to idle specifies how long the cache entry may exist in the cache without access. For example, if a value is not requested for more than 30 seconds, it is removed from the cache.<\/p>\n<h5>listeners Tag<\/h5>\n<p>In the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">listeners<\/code> tag, we configure a <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">CacheEventListener<\/code>. The listener reacts to the following events:<\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul style=\"list-style-type: square;\">\n<li>A cache entry is placed in the cache (<code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">CREATED<\/code>).<\/li>\n<li>The validity of a cache entry has expired (<code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">EXPIRED<\/code>).<\/li>\n<li>A cache entry is evicted from the cache (<code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">EVICTED<\/code>).<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>The specified <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">CacheLogger<\/code> class only logs the occurred cache event on the console:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">public class CacheLogger implements CacheEventListener&lt;Object, Object&gt; {\n\n  private final Logger LOG = LoggerFactory.getLogger(CacheLogger.class);\n\n  @Override\n  public void onEvent(CacheEvent&lt;?, ?&gt; cacheEvent) {\n    LOG.info(\"Key: {} | EventType: {} | Old value: {} | New value: {}\",\n             cacheEvent.getKey(), cacheEvent.getType(), cacheEvent.getOldValue(), \n             cacheEvent.getNewValue());\n  }\n\n}<\/pre>\n<h5>resources Tag<\/h5>\n<p>In the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">resources<\/code> tag, we configure the tiers and capacities of our cache. We use a three-tier cache with a disk store as authority tier:<\/p>\n<ul style=\"list-style-type: square;\">\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">heap<\/code>: For the on heap store we configure a capacity of 1,000 cache entries. This is the maximum number of entries before eviction starts.<\/li>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">offheap<\/code>: For the off-heap store we configure a capacity of 10 MB.<\/li>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">disk<\/code>: As disk cache, we configure 20 MB. <strong>Important<\/strong>: The disk cache must always have a higher memory capacity than the heap cache, otherwise the application throws an exception during application startup when parsing the XML file.<\/li>\n<\/ul>\n<p>Ehcache uses <a href=\"https:\/\/www.ehcache.org\/documentation\/2.8\/apis\/cache-eviction-algorithms.html\" target=\"_blank\" rel=\"noopener noreferrer\"><em>Last Recently Used (LRU)<\/em><\/a> as the default eviction strategy for the memory stores. The eviction strategy determines which cache entry is to be evicted when the cache is full. The cache entries are always evicted to the next lower tier, for example, from the on-heap store to the off-heap store.<\/p>\n<p>If a disk store is used and this is full, another cache entry is removed when a cache entry is added. The disk store uses <em>Last Frequently Used (LFU)<\/em> as the eviction strategy.<\/p>\n<h4>5.4.2 Cache configuration<\/h4>\n<p>Using the cache template we just created, we can now configure our cache. Thanks to the template we only have to define a name (<code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">alias<\/code>) as well as the type of the cache key (<code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">key-type<\/code>) and the type of the cached value (<code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">value-type<\/code>):<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\">&lt;config ...&gt;\n\n    &lt;!-- Persistent cache directory --&gt;\n    ...\n    &lt;!-- Default cache template --&gt;\n    ...\n\n    &lt;!-- Cache configuration --&gt;\n    &lt;cache alias=\"areaOfCircleCache\" uses-template=\"default\"&gt;\n        &lt;key-type&gt;java.lang.Integer&lt;\/key-type&gt;\n        &lt;value-type&gt;java.lang.Double&lt;\/value-type&gt;\n    &lt;\/cache&gt;\n\n&lt;\/config&gt;<\/pre>\n<p>I would like to point out that we could have configured the cache without the cache template. All settings made in the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">cache-template<\/code> tag can also be used directly within the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">cache<\/code> tag.<\/p>\n<p><strong>Note<\/strong>: If the cache key consists of more than one method parameter, the type <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">java.util.ArrayList<\/code> must be used as the key-type.<\/p>\n<h4>5.4.3 Wiring of ehcache.xml with application.properties<\/h4>\n<p>Finally, we tell the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">application.properties<\/code> file where our configuration file for Ehcache is located:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">spring.cache.jcache.config=classpath:ehcache.xml<\/pre>\n<h3>5.5 Simple RestController<\/h3>\n<p>We now use our <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">CalculationService<\/code> within the class <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">CalculationRestController<\/code> and implement a simple REST endpoint, which gives us the result for the calculation of a circular area:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@RestController\n@RequestMapping(\"\/rest\/calculate\")\npublic class CalculationRestController {\n\n  private final CalculationService calculationService;\n\n  @Autowired\n  public CalculationRestController(CalculationService calculationService) {\n    this.calculationService = calculationService;\n  }\n\n  @GetMapping(path = \"\/areaOfCircle\", produces = MediaType.APPLICATION_JSON_VALUE)\n  public ResponseEntity&lt;Double&gt; areaOfCircle(@RequestParam int radius) {\n    double result = calculationService.areaOfCircle(radius);\n\n    return ResponseEntity.ok(result);\n  }\n\n}<\/pre>\n<p>If, for example, we call the URL <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">http:\/\/localhost:8080\/rest\/calculate\/areaOfCircle?radius=6<\/code> after starting our application, the area of a circle with a radius of 6 is calculated and the result is displayed in the browser or in Postman.<\/p>\n<p>For the first call of the URL, the calculation of the circle area is still carried out. For all further calls, we get the result from the cache. Our built-in log output shows that the method is actually entered only once.<\/p>\n<p>If we calculate the circular area for a radius of 3, then the method is always executed, because the specified radius does not meet the cache condition <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">#radius &gt; 5<\/code>. A possible log output could be as follows (for a better overview I have omitted the output of the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">CacheLogger<\/code>):<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">2019-06-10 16:13:20.605 INFO (...) : calculate the area of a circle with a radius of 6\n2019-06-10 16:13:29.787 INFO (...) : calculate the area of a circle with a radius of 3\n2019-06-10 16:13:30.433 INFO (...) : calculate the area of a circle with a radius of 3\n2019-06-10 16:13:30.820 INFO (...) : calculate the area of a circle with a radius of 3\n2019-06-10 16:13:30.980 INFO (...) : calculate the area of a circle with a radius of 3\n2019-06-10 16:13:31.265 INFO (...) : calculate the area of a circle with a radius of 3<\/pre>\n<h2>6. Further examples<\/h2>\n<h3>6.1 Key Generator<\/h3>\n<p>If the possibilities of the SpEL for the generation of the cache key are not enough, the annotation <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Cacheable<\/code> offers the possibility to use its own <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">KeyGenerator<\/code> bean. The bean must implement the functional interface <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">KeyGenerator<\/code>. The name of the bean must be specified as the value for the annotation parameter <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">keyGenerator<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Cacheable(value = \"multiplyCache\", keyGenerator = \"multiplyKeyGenerator\")\npublic double multiply(int factor1, int factor2) {\n  LOG.info(\"Multiply {} with {}\", factor1, factor2);\n  return factor1 * factor2;\n}<\/pre>\n<p>We define the associated bean in the class <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">EhcacheConfig<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Configuration\n@EnableCaching\npublic class EhcacheConfig {\n\n  @Bean\n  public KeyGenerator multiplyKeyGenerator() {\n    return (Object target, Method method, Object... params) -&gt; \n           method.getName() + \"_\" + Arrays.toString(params);\n  }\n\n}<\/pre>\n<h3>6.2 @CacheEvict<\/h3>\n<p>A cache can become very large very quickly. The problem with large caches is that they occupy a lot of important main memory and mostly consist of stale data that is no longer needed.<\/p>\n<p>To avoid inflated caches, you should, of course, have configured a meaningful eviction strategy. On the other hand, it is also possible to empty the cache based on requests. The following example shows how to remove all entries from the caches <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">areaOfCircleCache<\/code> and <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">multiplyCache<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@CacheEvict(cacheNames = {\"areaOfCircleCache\", \"multiplyCache\"}, allEntries = true)\npublic void evictCache() {\n  LOG.info(\"Evict all cache entries...\");\n}<\/pre>\n<h3>6.3 @CacheConfig<\/h3>\n<p>The <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@CacheConfig<\/code> annotation allows us to define certain cache configurations at the class level. This is especially useful if certain cache settings are the same for all methods to be cached:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Service\n@CacheConfig(cacheNames = \"studentCache\")\npublic class StudentService {\n\n  \/\/ ...\n\n  @Cacheable\n  public Optional&lt;Student&gt; find(Long id) {\n    \/\/ ...   \n  }\n\n  @CachePut(key = \"#result.id\")\n  public Student create(String firstName, String lastName, String courseOfStudies) {\n    \/\/ ...\n  }\n\n}<\/pre>\n<p>Both the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">find()<\/code> and <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">create()<\/code> methods use the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">studentCache<\/code> cache in this example.<\/p>\n<h3>6.4 @CachePut<\/h3>\n<p>In the previous chapter of this post, we got to know <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Cacheable<\/code>. Methods annotated with <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Cacheable<\/code> are not executed again if a value already exists in the cache for the cache key. If the value does not exist in the cache, then the method is executed and places its value in the cache.<\/p>\n<p>Now there is also the use case that we always want the method to be executed and its result to be placed in the cache. This is done using the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@CachePut<\/code> annotation, which has the same annotation parameters as <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Cachable<\/code>.<\/p>\n<p>A possible scenario for using <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@CachePut<\/code> is, for example, creating an entity object, as the following example shows:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@CachePut(cacheNames = \"studentCache\", key = \"#result.id\")\npublic Student create(String firstName, String lastName, String courseOfStudies) {\n  LOG.info(\"Creating student with firstName={}, lastName={} and courseOfStudies={}\", \n           firstName, lastName, courseOfStudies);\n  \n  long newId = ID_CREATOR.incrementAndGet();\n  Student newStudent = new Student(newId, firstName, lastName, courseOfStudies);      \n  \n  \/\/ persist in database\n\n  return newStudent;\n}<\/pre>\n<p>The key <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">#result<\/code> is a placeholder provided by Spring and refers to the return value of the method. The ID of the student is, therefore, the cache key. The cache entry is the return value of the method, the student in our example.<\/p>\n<p>The method now creates a student object and stores it in the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">studentCache<\/code> at the end. The next time this object is requested, it can be retrieved directly from the cache.<\/p>\n<h2>7. JSR 107 Annotations vs. Spring Cache Annotations<\/h2>\n<p>Since Ehcache is fully JSR 107 compliant, JSR 107 annotations can be used instead of Spring Cache annotations. Spring recommends to choose one side and not to mix the annotations at all. The following table shows a comparison of the available cache annotations:<\/p>\n<table style=\"border-collapse: collapse; width: 100%;\">\n<tbody>\n<tr>\n<td style=\"width: 50%;\"><strong>JSR 107 \/ JCache Annotations<\/strong><\/td>\n<td style=\"width: 50%;\"><strong>Spring Cache Annotations<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 50%;\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@CacheResult<\/code><\/td>\n<td style=\"width: 50%;\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Cacheable<\/code><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 50%;\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@CacheRemove<\/code><\/td>\n<td style=\"width: 50%;\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@CacheEvict<\/code><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 50%;\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@CacheRemoveAll<\/code><\/td>\n<td style=\"width: 50%;\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@CacheEvict(allEntries=true)<\/code><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 50%;\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@CachePut<\/code><\/td>\n<td style=\"width: 50%;\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@CachePut<\/code><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 50%;\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@CacheDefaults<\/code><\/td>\n<td style=\"width: 50%;\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@CacheConfig<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>8. Summary<\/h2>\n<p>In this blog post, we looked at how to configure and use the cache provider Ehcache in Spring Boot. We looked at the following:<\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul style=\"list-style-type: square;\">\n<li>What are caches and what are they good for?<\/li>\n<li>How does caching work in Spring?<\/li>\n<li>Using Spring Cache Annotations\n<ul style=\"list-style-type: square;\">\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@EnableCaching<\/code><\/li>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Cacheable<\/code><\/li>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@CacheEvict<\/code><\/li>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@CachePut<\/code><\/li>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@CacheConfig<\/code><\/li>\n<\/ul>\n<\/li>\n<li>Configuration of Ehcache caches<\/li>\n<li>Custom cache keys<\/li>\n<li>Comparison JSR 107 Annotations and Spring Cache Annotations<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Also, like to check out the <a href=\"https:\/\/github.com\/spring-framework-guru\/sfg-blog-posts\/tree\/master\/spring-boot-ehcache\" target=\"_blank\" rel=\"noopener noreferrer\">project repository at GitHub<\/a>. It contains a fully functional Spring Boot application with Ehcache as the cache provider.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>1. Introduction In today&#8217;s blog post we will look at how we can use the caching provider Ehcache in Spring Boot. Ehcache is an open source library implemented in Java for implementing caches in Java programs, especially local and distributed caches in main memory or on the hard disk. Thanks to the implementation of JSR-107, [&hellip;]<a href=\"https:\/\/springframework.guru\/using-ehcache-3-in-spring-boot\/\" class=\"df-link-excerpt\">Continue reading<\/a><\/p>\n","protected":false},"author":117,"featured_media":4575,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_lmt_disableupdate":"","_lmt_disable":"","_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[104],"tags":[236,237,29],"class_list":["post-5513","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-spring-boot","tag-cache","tag-ehcache","tag-spring-boot"],"jetpack_publicize_connections":[],"aioseo_notices":[],"modified_by":"jt","jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/springframework.guru\/wp-content\/uploads\/2018\/06\/NewBannerBOOTSWeb.jpg","jetpack_shortlink":"https:\/\/wp.me\/p5BZrZ-1qV","_links":{"self":[{"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/posts\/5513"}],"collection":[{"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/users\/117"}],"replies":[{"embeddable":true,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/comments?post=5513"}],"version-history":[{"count":11,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/posts\/5513\/revisions"}],"predecessor-version":[{"id":8287,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/posts\/5513\/revisions\/8287"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/media\/4575"}],"wp:attachment":[{"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/media?parent=5513"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/categories?post=5513"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/tags?post=5513"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}