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
.
The 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 subsequents 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 as the one presented above. For example, imagine that you have a city cached in CITIES
cache and a new restaurant is created in that city. In this case, the cache of the city is evicted of CITIES
(because the list of restaurants in the city changed) and a new cache for the restaurant is put in RESTAURANTS
cache. The same happens when a restaurant is deleted/update or a restaurant dish is added/deleted/updated.
Open a terminal and, inside springboot-caching-neo4j
root folder, run:
docker compose up -d
-
In a terminal, make sure you are inside
springboot-caching-neo4j
root folder; -
Start the application by picking one of the following cache providers:
-
Simple
cache provider./mvnw clean spring-boot:run --projects restaurant-api
-
Caffeine
cache provider./mvnw clean spring-boot:run --projects restaurant-api -Dspring-boot.run.profiles=caffeine
-
Redis
cache 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
springboot-caching-neo4j
root folder;-
JVM
./docker-build.sh
-
Native
./docker-build.sh native
-
-
Environment Variables
Environment Variable Description SPRING_PROFILES_ACTIVE
Specify the type of profile to run the application. To use
Redis
provider for caching setredis
. To useCaffeine
for caching setcaffeine
. The default profile will useSimple
caching.NEO4J_HOST
Specify host of the
Neo4j
to use (defaultlocalhost
)NEO4J_PORT
Specify port of the
Neo4j
to use (default7687
)REDIS_HOST
Specify host of the
Redis
to use (defaultlocalhost
)REDIS_PORT
Specify port of the
Redis
to use (default6379
) -
Run Docker Container (for instance, using
redis
profile)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
Neo4j
UI can be accessed at http://localhost:7474/browser.No authentication is needed, just click
Connect
button -
redis-commander
redis-commander
UI can be accessed at http://localhost:8081.
-
To stop
restaurant-api
application, 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
springboot-caching-neo4j
root folder, run the following command:docker compose down -v
-
In a terminal, make sure you are inside
springboot-caching-neo4j
root folder; -
Start the tests by picking one on the following cache providers:
-
Simple
cache provider./mvnw clean verify --projects restaurant-api
-
Caffeine
cache provider./mvnw clean verify --projects restaurant-api -DargLine="-Dspring.profiles.active=caffeine"
-
Redis
cache 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 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.