Kotlin – SpringCache

Performance is a big problem in software development. And Caching is one solution to speed up system. The tutorial will show you how to start with Spring Cache using Kotlin Spring Boot.

I. Technologies

– Java 1.8
– Kotlin 1.2.20
– Spring Tool Suite – Version 3.9.2.RELEASE
– Spring Boot – 1.5.10.RELEASE
– Apache Maven 3.5.2

II. Goal

1. Project Structure

We build a Kotlin SpringBoot project that uses SpringCache annotations to cache data for enhancing performance.

kotlin spring cache - project structure

2. Caching

We define 3 restAPIs {‘/cacheput’, ‘/cachable’, ‘/cacheevict’}.


@RestController
public class RestAPIs {
     
    @Autowired
    lateinit var service: CacheService
     
    @RequestMapping("/cacheput")
    fun put(...){
        service.put(firstName, id)
        ...
    }
	
    @RequestMapping("/cachable")
    fun get(...){
        return service.getById(id)
    }
     
    @RequestMapping("/cacheevict")
    fun evict(...){
        service.evict(id);
        ...
    }
}

With a CacheService component that builds on Spring Cache annotations {@CachePut, @Cacheable, @CacheEvict}.


@Component
class CacheService {
    
	...
	 
    @CachePut(value="customers", key="#id")
    fun put(firstName: String, id: Long): Customer?{
		...
	}
	
    @Cacheable(value="customers", key="#id")
    fun getById(id: Long): Customer?{
	    ...
	}
     
    @CacheEvict(value = "customers", key = "#id")
    fun evict(id: Long){}
}

@Cacheable is one of the most important and common annotation for caching the requests.
If the application sends multiple requests, this annotation will not execute the method which is Cachable multiple times, instead it will return the result from the cached storage.
+ value is a cache name to store the caches, in this case, it’s customers.
+ key is a Spring Expression Language for computing the key dynamically.
+ input parameter ID is used as a key to find Customer object in the cache if it exists, if the customer with that id doesn’t exist, Spring Framework will execute command inside method (including Sleep function – for simulation purpose) and cache current customer object that is returned in this method.

@CachePut updates the cache which is stored and execute the method.
+ the method putCustomer is used to modify customer instance in the cache.
+ input parameter ID is used as a key to find customer object in the cache. If the id exists, the function will modify the firstName the same as the input string parameter.

@CacheEvict is used for removing a single cache or clearing the entire cache from the cache storage. The method evict uses the input parameter id as a key to find the object that has the same id and removes it from the cache.

3. Result

Request 1
-> http://localhost:8080/cachable?id=1
-> Service process slowly and result:

kotlin spring cache - request 1

Server has displayed a text on console:


Service processing...

Now a customer with Customer(1, “Jack”, “Smith”) has been cached.

Request 2
-> http://localhost:8080/cachable?id=1
Now the response is faster because Customer with id = 1 has been cached before, the application just get data from cache storage.

kotlin spring cache - request 2

Request 3
-> http://localhost:8080/cacheput?id=1&firstname=Peter
Message is returned on Browser -> Done
Now customer with id=1 is modified: firstname=”Peter”, not “Jack”.

Request 4
-> http://localhost:8080/cachable?id=1
Response is faster BUT the result is difference from first request:

kotlin spring cache - request 4

Request 5
Make a cache-evict request: http://localhost:8080/cacheevict?id=1
Browser displays: -> Done
Now customer with id=1 was evicted from cache storage.

Request 6
-> http://localhost:8080/cachable?id=1
Now the behavior of the browser is the same as the first request because customer with id=1 was evicted to cache, and the method under @Cachable is executed.
Service process slowly and result:

kotlin spring cache - request 6

Server, of course, displays a text on console:


Service processing...

III. Implementation

1. Data Model


package com.javasampleapproach.kotlin.springcache.model

class Customer(
	var id: Long,
    var firstName: String,
    var lastName: String
)

2. Rest APIs


package com.javasampleapproach.kotlin.springcache.controller

import org.springframework.beans.factory.annotation.Autowired

import org.springframework.web.bind.annotation.RestController
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RequestMapping

import com.javasampleapproach.kotlin.springcache.model.Customer
import com.javasampleapproach.kotlin.springcache.service.CacheService

@RestController
public class RestAPIs {
     
    @Autowired
    lateinit var service: CacheService
     
    @RequestMapping("/cacheput")
    fun put(@RequestParam("firstname") firstName: String, @RequestParam("id") id: Long): String{
        service.put(firstName, id)
        return "Done"
    }
	
    @RequestMapping("/cachable")
    fun get(@RequestParam("id") id: Long): Customer?{
        return service.getById(id)
    }
     
    @RequestMapping("/cacheevict")
    fun evict(@RequestParam("id") id: Long): String{
        service.evict(id);
        return "Done"
    }
}

3. Cache Service


package com.javasampleapproach.kotlin.springcache.service

import javax.annotation.PostConstruct
import org.springframework.cache.annotation.CacheEvict
import org.springframework.cache.annotation.CachePut
import org.springframework.cache.annotation.Cacheable
import org.springframework.cache.annotation.CacheConfig
import org.springframework.stereotype.Component

import com.javasampleapproach.kotlin.springcache.model.Customer

@Component
class CacheService {
     
    val store = mutableMapOf()
	
	@PostConstruct
    fun init(){
		store.put(1L, Customer(1, "Jack", "Smith"))
        store.put(2L, Customer(2, "Adam", "Johnson"))
    }
     
    @CachePut(value="customers", key="#id")
    fun put(firstName: String, id: Long): Customer?{
        var cust = store.get(id)
		
		if(cust != null)
			cust.firstName = firstName	
        
        return cust
    }
     
    @Cacheable(value="customers", key="#id")
    fun getById(id: Long): Customer?{
        println("Service processing...")
		
        Thread.sleep(3000)
		 
        return store.get(id)
    }
     
    @CacheEvict(value = "customers", key = "#id")
    fun evict(id: Long){}
}

4. TurnOn Caching


package com.javasampleapproach.kotlin.springcache

import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.cache.annotation.EnableCaching

@SpringBootApplication
@EnableCaching
class KotlinSpringCacheApplication

fun main(args: Array) {
    SpringApplication.run(KotlinSpringCacheApplication::class.java, *args)
}

IV. SourceCode

KotlinSpringCache



By grokonez | February 20, 2018.

Last updated on April 17, 2021.



Related Posts


Got Something To Say:

Your email address will not be published. Required fields are marked *

*