Is there any reason you want to, or need to, cache all Foos
in your application collectively rather than individually?
Keep in mind, it is by design that Spring's Cache Abstraction uses the method parameter(s) (if any) as the key and the return value as the value of the cache entry. If the method has no parameters then Spring will generate an id for you.
I have written about how to customize Spring's CacheManager
implementation to cache a Collection of values returned by a @Cacheable
method, individually.
However, for the moment, let's assume you do need/want to cache the entire List of Foos
.
Then, to create a method that pulls an individual Foo
by ID from the "cached" List of Foos
, you could, given your original cached method in a service class, do, for example...
@Sevice
class MyFooService {
private final FooRepository<Foo, Long> fooRepository;
@Cacheable(cacheNames = "foos")
public List<FooDto> getAllFoos() {
return this.fooRepository.findAll().stream()
.map(FooEntityDomainToDtoMapper::mapDomainToDto) // mapping entity to dto
.collect(Collectors.toList());
}
}
Then, in another application component, you could...
@Component
class MyFooAccessor {
private final MyFooService fooService;
MyFooAccessor(MyFooService fooService) {
this.fooService = fooService;
}
Optional<FooDto> getById(Long id) {
this.fooService.getAllFoos().stream()
.filter(fooDto -> fooDto.getId().equals(id))
.findFirst();
}
...
}
The MyFooAccessor
makes sure you do not circumvent the caching proxy (i.e. the AOP Proxy + Caching Advice around the MyFooService
applied by Spring). If the getById(..)
method were a member of the MyFooService
class, and called the getAllFoos()
method directly, you would circumvent the proxy and caching advice resulting in a database access each time.
NOTE: You could use Spring AOP Load Time Weaving (LTW) (see doc) to avoid circumventing the caching proxy if you want to keep the getById(:Long)
method in the MyFooService
class with the getAllFoos()
, @Cacheable
method. However...
Typically, you can solve these sort of problems by (re-)structuring your code appropriately, using the proper design pattern. This is not the only solution here, either. That is the beautiful thing about Spring is that it gives you many choices. This is just but 1 choice.
Hope this helps give you more ideas.