This guide will help you get started with the Firefly Common Cache Library in just a few minutes.
- Java 21 or higher
- Maven 3.6+ or Gradle 7+
- Spring Boot 3.5+
Add the following dependency to your pom.xml:
<dependency>
<groupId>org.fireflyframework</groupId>
<artifactId>fireflyframework-cache</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>Add the following to your build.gradle:
implementation 'org.fireflyframework:fireflyframework-cache:1.0.0-SNAPSHOT'Add the @EnableCaching annotation to your Spring Boot application:
package com.example.myapp;
import org.fireflyframework.cache.annotation.EnableCaching;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}Create or update your application.yml with basic cache configuration:
firefly:
cache:
enabled: true
default-cache-type: CAFFEINE # Start with in-memory cache
default-cache-name: default
# Caffeine (in-memory) configuration
caffeine:
default:
enabled: true
maximum-size: 1000
expire-after-write: PT1H # 1 hour
record-stats: trueInject FireflyCacheManager and use it directly:
package com.example.myapp.service;
import org.fireflyframework.cache.manager.FireflyCacheManager;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import java.time.Duration;
@Service
@RequiredArgsConstructor
@Slf4j
public class UserService {
private final FireflyCacheManager cacheManager;
private final UserRepository userRepository;
public Mono<User> getUser(String userId) {
// Try to get from cache first
return cacheManager.get(userId, User.class)
.flatMap(cachedUser -> {
if (cachedUser.isPresent()) {
log.info("Cache hit for user: {}", userId);
return Mono.just(cachedUser.get());
}
// Cache miss - load from database
log.info("Cache miss for user: {}", userId);
return loadUserFromDatabase(userId)
.flatMap(user ->
// Store in cache with 30 minute TTL
cacheManager.put(userId, user, Duration.ofMinutes(30))
.thenReturn(user)
);
});
}
public Mono<User> updateUser(User user) {
return userRepository.save(user)
.flatMap(savedUser ->
// Evict old cache entry
cacheManager.evict(savedUser.getId())
.thenReturn(savedUser)
);
}
private Mono<User> loadUserFromDatabase(String userId) {
return userRepository.findById(userId);
}
}Note: Annotation support is defined but not yet fully implemented. Use the programmatic API for now.
@Service
public class ProductService {
@Cacheable(value = "products", key = "#productId", ttl = "PT2H")
public Mono<Product> getProduct(String productId) {
return productRepository.findById(productId);
}
@CacheEvict(value = "products", key = "#product.id")
public Mono<Product> updateProduct(Product product) {
return productRepository.save(product);
}
}When your application starts, you should see logs like:
INFO c.f.c.c.config.CacheAutoConfiguration - Firefly Cache Auto-Configuration - Starting initialization
INFO c.f.c.c.config.CacheAutoConfiguration - Cache adapters will be auto-discovered: Caffeine, Redis
INFO c.f.c.manager.FireflyCacheManager - Created Firefly Cache Manager with strategy: AutoCacheSelectionStrategy, default cache: default
INFO c.f.c.manager.FireflyCacheManager - Registered cache 'default' of type CAFFEINE
Create a simple test:
package com.example.myapp;
import org.fireflyframework.cache.manager.FireflyCacheManager;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import reactor.test.StepVerifier;
import java.time.Duration;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
class CacheQuickStartTest {
@Autowired
private FireflyCacheManager cacheManager;
@Test
void shouldCacheAndRetrieveValue() {
String key = "test-key";
String value = "test-value";
// Put value in cache
StepVerifier.create(cacheManager.put(key, value))
.verifyComplete();
// Retrieve value from cache
StepVerifier.create(cacheManager.get(key, String.class))
.assertNext(result -> {
assertThat(result).isPresent();
assertThat(result.get()).isEqualTo(value);
})
.verifyComplete();
}
@Test
void shouldRespectTTL() throws InterruptedException {
String key = "ttl-key";
String value = "ttl-value";
Duration ttl = Duration.ofMillis(100);
// Put with short TTL
StepVerifier.create(cacheManager.put(key, value, ttl))
.verifyComplete();
// Should exist immediately
StepVerifier.create(cacheManager.exists(key))
.expectNext(true)
.verifyComplete();
// Wait for expiration
Thread.sleep(150);
// Should be gone
StepVerifier.create(cacheManager.get(key, String.class))
.assertNext(result -> assertThat(result).isEmpty())
.verifyComplete();
}
}If you have Spring Boot Actuator enabled, you can check cache health:
curl http://localhost:8080/actuator/health/cacheResponse:
{
"status": "UP",
"details": {
"totalCaches": 1,
"healthyCaches": 1,
"unhealthyCaches": 0,
"caches": {
"default": {
"type": "caffeine",
"status": "UP",
"available": true,
"configured": true,
"responseTimeMs": 1
}
}
}
}Now that you have the basics working, you can:
- Configure Redis - Add distributed caching
- Explore Advanced Features - Learn about advanced patterns
- Set Up Monitoring - Configure metrics and dashboards
- Understand the Architecture - Learn how it works under the hood
Problem: Cache operations don't seem to work.
Solution:
- Verify
@EnableCachingis present on your configuration class - Check that
firefly.cache.enabled=truein your properties - Look for error messages in the logs
Problem: Maven/Gradle dependency resolution errors.
Solution:
- Ensure you're using Spring Boot 3.5+
- Check that Java 21 is configured
- Run
mvn dependency:treeorgradle dependenciesto identify conflicts
Problem: Error message "No caches registered" or "No available cache found".
Solution:
- Verify Caffeine dependency is on the classpath (it should be transitive)
- Check cache configuration in
application.yml - Ensure
firefly.cache.caffeine.default.enabled=true
- Check the Troubleshooting Guide
- Review the Configuration Reference
- Look at Examples for common patterns