The goal of this project is to explore how caching works. For it, we are going to implement a simple Spring Boot application called restaurant-api. We are using Neo4j for storage and, for caching, we can pick one of the following providers: Simple, Caffeine or Redis.
On ivangfr.github.io, I have compiled my Proof-of-Concepts (PoCs) and articles. You can easily search for the technology you are interested in by using the filter. Who knows, perhaps I have already implemented a PoC or written an article about what you are looking for.
The application uses 3 caches: CITIES, RESTAURANTS and DISHES.
Caching is applied at controller level. For instance, if you call GET /api/restaurants/123 for the first time, the application will check whether the key 123 is present in the RESTAURANTS cache; if not, it must go to DB to get the information about the restaurant (payload). Let’s say that the payload is:
{ "name": "Happy Pizza", "city": {"id": 1, "name": "Berlin"}, "dishes": [] }Before the endpoint finishes and returns the result, the key and its payload are saved in RESTAURANTS cache:
{ "123" = {"name": "Happy Pizza", "city": {"id": 1, "name": "Berlin"}, "dishes": []} }On subsequent calls to GET /api/restaurants/123 (and as far as the data is not evicted), the application just needs to go to the cache and get the value.
By the way, we have implemented more advanced caching logic than the one presented above. For example, imagine that you have a city cached in the CITIES cache and a new restaurant is created in that city. In this case, the cache of the city is evicted from CITIES (because the list of restaurants in the city changed) and a new cache for the restaurant is put in the RESTAURANTS cache. The same happens when a restaurant is deleted/updated or a restaurant dish is added/deleted/updated.
Open a terminal and, inside the springboot-caching-neo4j root folder, run:
docker compose up -d-
In a terminal, make sure you are inside the
springboot-caching-neo4jroot folder; -
Start the application by picking one of the following cache providers:
-
Simplecache provider./mvnw clean spring-boot:run --projects restaurant-api -
Caffeinecache provider./mvnw clean spring-boot:run --projects restaurant-api -Dspring-boot.run.profiles=caffeine -
Rediscache provider./mvnw clean spring-boot:run --projects restaurant-api -Dspring-boot.run.profiles=redis
-
-
Build Docker Image
In a terminal, make sure you are in the
springboot-caching-neo4jroot folder;-
JVM
./build-docker-images.sh -
Native
./build-docker-images native
-
-
Environment Variables
Environment Variable Description SPRING_PROFILES_ACTIVESpecify the type of profile to run the application. To use
Redisprovider for caching setredis. To useCaffeinefor caching setcaffeine. The default profile will useSimplecaching.NEO4J_HOSTSpecify host of the
Neo4jto use (defaultlocalhost)NEO4J_PORTSpecify port of the
Neo4jto use (default7687)REDIS_HOSTSpecify host of the
Redisto use (defaultlocalhost)REDIS_PORTSpecify port of the
Redisto use (default6379) -
Run Docker Container (for instance, using
redisprofile)docker run --rm --name restaurant-api \ -p 8080:8080 \ -e SPRING_PROFILES_ACTIVE=redis \ -e NEO4J_HOST=neo4j \ -e REDIS_HOST=redis \ --network=springboot-caching-neo4j_default \ ivanfranchin/restaurant-api:1.0.0
| Application | URL |
|---|---|
restaurant-api |
Open a terminal and run the following commands:
-
Create a city
CITY_ID=$(curl -s -X POST http://localhost:8080/api/cities -H "Content-Type: application/json" -d '{"name":"Berlin"}' | jq -r .id) curl -i http://localhost:8080/api/cities/$CITY_ID -
Create a restaurant in the city
RESTAURANT_ID=$(curl -s -X POST http://localhost:8080/api/restaurants -H "Content-Type: application/json" -d '{"cityId":"'$CITY_ID'", "name":"Happy Burger"}' | jq -r .id) curl -i http://localhost:8080/api/restaurants/$RESTAURANT_ID -
Create a dish for the restaurant
DISH_ID=$(curl -s -X POST http://localhost:8080/api/restaurants/$RESTAURANT_ID/dishes -H "Content-Type: application/json" -d '{"name":"Cheese Burger", "price":9.99}' | jq -r .id) curl -i http://localhost:8080/api/restaurants/$RESTAURANT_ID/dishes/$DISH_ID
Caching statistics can be obtained by calling /actuator/prometheus endpoint:
curl -s http://localhost:8080/actuator/prometheus | grep cacheManager-
Neo4j
Neo4jUI can be accessed at http://localhost:7474/browser.No authentication is needed, just click
Connectbutton -
redis-commander
redis-commanderUI can be accessed at http://localhost:8081.
-
To stop
restaurant-apiapplication, go to the terminal where it is running and pressCtrl+C; -
To stop and remove Docker Compose containers, network, and volumes, go to a terminal and inside the
springboot-caching-neo4jroot folder, run the following command:docker compose down -v
-
In a terminal, make sure you are inside the
springboot-caching-neo4jroot folder; -
Start the tests by picking one on the following cache providers:
-
Simplecache provider./mvnw clean verify --projects restaurant-api -
Caffeinecache provider./mvnw clean verify --projects restaurant-api -DargLine="-Dspring.profiles.active=caffeine" -
Rediscache provider./mvnw clean verify --projects restaurant-api -DargLine="-Dspring.profiles.active=redis"
-
To remove the Docker image created by this project, go to a terminal and, inside the springboot-caching-neo4j root folder, run the following script:
./remove-docker-images.sh-
Add AOP to log whenever the endpoint is called;
-
Create a bash script that uses Neo4j API to insert some data.



