Given these entities and the repository to access their data in DDBB:
@Entity
public class Customer {
Long id;
}
@Entity
public class Purchase {
Long customerId;
}
@Repository
public lass PurchaseDAO {
public void insert(Purchase insert);
public void deleteCustomerPurchases(Long customerId);
public long getTotalPurchasesAmount(Long customerId);
public long getTotalPurchasesAmountPerMonth(Long customerId, int month);
}
I want to add cache for method getTotalPurchaseAmounts(Long customerId), in such way that, when adding some purchase for a customer, only purchasesd of that customer are evicted.
The related dependance entries are:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.2</version>
</dependency>
Related configuration:
@EnableCaching
@Configuration
public class CommonConfig {
@Bean
public CacheManager cacheManager() {
EhCacheCacheManager cacheManager = new EhCacheCacheManager();
cacheManager.setCacheManager( ehCacheManager().getObject() );
return cacheManager;
}
@Bean
public EhCacheManagerFactoryBean ehCacheManager() {
EhCacheManagerFactoryBean ehcache = new EhCacheManagerFactoryBean();
ehcache.setConfigLocation( new ClassPathResource( "ehcache.xml" ) );
return ehcache;
}
}
As spring cache (and ehcache) evicts are limited as per element or all entries, the solution I have developed is creating caches dinamically (one for each customer) so I can evict those.
The extension point I thinks is the best for this is implementing a custom CacheResolver:
@Component("CustomerPurchasesCacheResolver")
public class CustomerPurchasesCacheResolver implements CacheResolver {
@Autowired
private EhCacheCacheManager cacheManager;
@Override
public Collection<? extends Cache> resolveCaches( CacheOperationInvocationContext<?> context ) {
String cacheName = "customerPurchases_" + getCustomerId( context );
// Add cache to cacheManager if it does not exists
cacheManager.getCacheManager().addCacheIfAbsent( cacheName );
Set<Cache> caches = new HashSet<>();
caches.add( cacheManager.getCache( cacheName ) );
return caches;
}
// Retrieves customerId from cache operation invocation context;
private Long getCustomerId( CacheOperationInvocationContext<?> context ) {
String key = ( (CacheOperation) context.getOperation() ).getKey();
// TODO Evaluate key
// HOW CAN I DO THIS????????????
return null;
}
}
and adding Spring cache to my repository methods:
@Repository
public lass PurchaseDAO {
@CacheEvict(cacheResolver="CustomerPurchasesCacheResolver", key="#purchase.customerId")
public void insert(Purchase purchase);
@CacheEvict(cacheResolver="CustomerPurchasesCacheResolver", key="#customerId")
public void deleteCustomerPurchases(Long customerId);
@Cacheable(cacheResolver="CustomerPurchasesCacheResolver")
public long getTotalPurchasesAmount(Long customerId);
@Cacheable(cacheResolver="CustomerPurchasesCacheResolver")
public long getTotalPurchasesAmountPerMonth(Long customerId, int month);
}
The only problem I get using this aproach is to get the key evaluated using Spring Expresions.
Is there any way to get that or a different aproach that could work?