Spring uses a default key generation strategy to derive the key for the cache entry from the caching-enabled (@Cacheable
or @CachePut
annotated) service or repository methods based on the arguments to the method.
Of course, you can customize key generation used by any cache-enabled bean methods by 1) implementing the KeyGenerator
interface and 2) declaring the KeyGenerator
bean in your caching annotations, like so:
class ListKeyGenerator implements KeyGenerator {
public Object generate(Object target, Method method, Object... params) {
List<?> list = params[0];
// use the list to generate a (unique) key for the cache entry
Object generatedKey = ...;
return generatedKey;
}
}
NOTE: The target
is the Spring managed bean containing your updateAll(..)
and findByIds(..)
methods. The Method
ref is the cache-enabled method invoked, such as updateAll(..)
. And, the array of Object params are the arguments (e.g. the List
) to the cache-enabled methods.
TIP: For simplicity and clarity (recommended), you may want to have 2 independent List
-based KeyGenerators
since 1 is a List
of IDs (Long
-typed; in the finder/query method) and the other is a List
of ProjectTeam
instances (in the update).
In configuration, you would declare:
@Configuration
class ApplicationCacheConfiguration {
@Bean
KeyGenerator listKeyGenerator() {
return new ListKeyGenerator();
}
}
You would apply the custom KeyGenerator
using:
@Service
class ProjectTeamService {
@CachePut(cacheNames = "projectTeams" keyGenerator = "listKeyGenerator")
public List<ProjectTeam> updateAll(List<ProjectTeam> projectTeams) {
// perform any preprocessing steps as necessary
return this.projectTeamRepository.saveAll(projectTeams);
}
}
NOTE: See corresponding Javadoc for @Cacheable
and Javadoc for @CachePut
.
However, you do not necessarily need a custom KeyGenerator
if you simply rely on Spring's default key generation strategy as I mentioned to begin with.
Regarding the approach you chose, this will not work since it is trying to use a Spring SpEL expression to access a single element/item (i.e. a single ProjectTeam
instance) in a List
of ProjectTeam
objects. Same applies for the List
of IDs.
Which element from the List
do you use? Do you use all elements (which would be difficult to aggregate using SpEL)? What happens if the List
argument to the cache-enabled method is empty, or worse, null
?
TIP: You should review Spring's SpEL capabilities for more details.
These sort of concerns are more appropriately handled in your custom KeyGenerator
implementation.
You should also be aware that the cached entries for the cache-enabled methods of your Spring managed bean will be (using "default key generation"):
cache-enabled method | cache key | cache value
----------------------------------------------------------------------
findByIds(:List<Long>) | List<Long> | List<ProjectTeam>
updateAll(:List<ProjectTeam>) | List<ProjectTeam> | List<ProjectTeam>
If you are expecting the individual elements/items (e.g. either Long
IDs or ProjectTeam
instances) of the Lists
to be broken out and cached individually in separate cache entries, then you are mistaken because this is NOT how Spring's Cache Abstraction works by default.
The reason I mention this is because it is sort of implied by your (attempted) caching configuration as declared in the annotations.
Spring takes the argument(s) to the cache-enabled method (e.g. @Cacheable
annotated method) and uses that as a key for the cache entry. The return value of the method is used as the value. Since the cache-enabled methods take a List
and return a List
then the cache entry key is the List
argument and the List
return value is the cache entry value.
As you might imagine, with each different List
of IDs or List
of ProjectTeam
instances requested, your cache memory space is going to fill up fast! That is because if the List
in each request (cache-enable method) just differs by 1 element, then that is going to constitute a new cache entry in the cache. Depending on how many (different) requests (invocations) your application processes, and the frequency, this could lead to a serious problem (e.g. OOME)!
If you need individual cache entries for individually requested items, then you should have a look at this SO post from earlier.
Good luck!