Spring Cache Tags is a lightweight library for managing Spring Cache using tags.
It allows you to group cached methods by tags and evict cache entries by one or multiple tags at once.
- π·οΈ Tag your cacheable methods with
@CacheTagsand evict tagged cache entries with@EvictTags - π― Support for Spring Expression Language (SpEL) in tags for dynamic tag generation
- π Transparent integration with Spring Cache - no code changes needed
- πΎ Multiple storage backends: In-Memory and Redis
- π Works with Spring Boot and standard Spring Framework
- π Thread-safe operations with concurrent access support
- π¦ Automatic Spring Boot auto-configuration
<dependency>
<groupId>io.github.intellinside</groupId>
<artifactId>spring-boot-starter-cache-tags</artifactId>
<version>0.3.0</version>
</dependency>implementation 'io.github.intellinside:spring-boot-starter-cache-tags:0.3.0'@Service
public class UserService {
@Cacheable("users")
@CacheTags("'user:' + #id")
public User getUserById(Long id) {
return userRepository.findById(id).orElse(null);
}
@CacheEvict(value = "users", key = "#id")
@EvictTags("'user:' + #id")
public void updateUser(Long id, UserDTO dto) {
userRepository.save(convertToEntity(dto));
}
}The @CacheTags annotation is used to associate one or more tags with cached method results. Tags support SpEL expressions.
Supported variables in SpEL:
#id,#name, etc. - method parameter values (requires-parameterscompiler flag)#result- method return value#args- array of all method arguments#method- method metadata
Example:
@Cacheable("products")
@CacheTags({
"'product:' + #productId",
"'category:' + #result.category",
"price-range:#{#result.priceRange}"
})
public Product getProduct(Long productId) {
return productRepository.findById(productId).orElse(null);
}The @EvictTags annotation evicts all cache entries associated with specified tags. Eviction happens after successful method execution.
Example:
@EvictTags({
"'product:' + #productId",
"'category:' + #category",
"price-range:#{#result.priceRange}"
})
public Product updateProduct(Long productId, String category) {
// Update product in database
return productRepository.updateCategory(productId, category);
}The default implementation stores tag mappings in application memory using ConcurrentHashMap.
Advantages:
- No external dependencies
- Very fast access
- Simple setup
Disadvantages:
- Mappings are lost on application restart
- Not suitable for distributed systems
- Memory usage grows with cache size
For distributed systems and production environments, use Redis as the storage backend.
Setup:
- Add Spring Data Redis to your project:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>- Configure Redis in your
application.properties:
spring.cache.type=redis
spring.redis.host=localhost
spring.redis.port=6379Advantages:
- Distributed tag mappings
- Persistent storage
- Shared across multiple instances
- High performance
Data Structure:
- Keys:
tag:{tagName}(Redis Set) - Values:
{cacheName}:{key}(serialized cache references)
Use SpEL to create sophisticated tag expressions:
@Service
public class OrderService {
@Cacheable("orders")
@CacheTags({
"'order:' + #orderId",
"'customer:' + #customerId",
"status:#{#result.status}"
})
public Order getOrder(Long orderId, Long customerId) {
return orderRepository.findById(orderId).orElse(null);
}
@EvictTags({
"'order:' + #orderId",
"'customer:' + #customerId"
})
public void cancelOrder(Long orderId, Long customerId) {
orderRepository.updateStatus(orderId, "CANCELLED");
}
}Evict multiple entries with a single tag:
@Service
public class ProductService {
@EvictTags("'category:' + #categoryId")
public void updateCategory(Long categoryId, CategoryDTO dto) {
// All products in this category are evicted
categoryRepository.update(categoryId, dto);
}
}Generate tags based on result properties:
@Cacheable("users")
@CacheTags({
"'user:' + #id",
"'role:' + #result.role",
"department:#{#result.department}"
})
public User getUserWithRoleAndDepartment(Long id) {
return userRepository.findByIdWithRelations(id).orElse(null);
}The library automatically configures itself with Spring Boot. No additional configuration is needed for basic functionality.
- Best for: Single-instance applications, development
- Memory overhead: Minimal - one entry per cached item
- Access time: O(1) average case
- Best for: Distributed systems, production
- Network overhead: Minimal with pipelining
- Persistence: Data survives application restarts
- Keep tag expressions simple and lightweight
- Use specific tags rather than broad patterns
- Consider cache key design to minimize tag entries
- Monitor memory usage in in-memory mode
- Use Redis for production distributed systems
Check:
- Ensure
-parameterscompiler flag is set (for named parameter access) - Verify that
@CacheTagsis used together with@Cacheable - Check that
@CacheTagsis on the same method as@Cacheable - Enable debug logging:
logging.level.io.github.intellinside.cache.tags=DEBUG
Check:
- Ensure
@EvictTagsmethod completes successfully (exceptions prevent eviction) - Verify that the evaluated tag matches the tags used in
@CacheTags - Check that cache manager is properly configured
- Verify Redis connection (if using Redis backend)
Solutions:
- Review tag cardinality - ensure tags aren't too unique
- Consider using Redis backend for better memory management
- Monitor and clean up unused cache entries
- Review SpEL expressions for correctness
- Java: 21 or higher
- Spring Framework: 6.x
- Spring Boot: 3.x (optional, for auto-configuration)
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License. See the LICENSE file for details.
- π API Documentation
- π Issue Tracker
- Using proxies instead of wrappers for the cache manager and caches.
- Fixed TTL support for the Redis backend when configured with Spring Boot
- Added TTL support for Redis backend
- Added support for Spring Template Expression syntax (#{...})
- Initial release
- Support for @CacheTags and @EvictTags annotations
- In-Memory and Redis storage backends
- Full Spring Boot auto-configuration
- Complete JavaDoc documentation