0

I am trying to implement a distributed cache with spring-memcached. The docs suggest that to use an object as the key I need to have a method in my domain class with @CacheKeyMethod annotation on it.

But the problem is I am using the same domain class in different scenarios and the key to be generated in each case has different logic. For examples for a User class one of the scenarios requires the key to be unique in terms of city and gender and but in the other case it requires to be unique in terms of the user's email, it's essentially what your lookup is based on.

Although a user's email would determine the city and gender, so I can use email as the key in first case as well but that would mean separate cache entries for each user while the cached data would be same as long as the gender and city are same, which is expected to increase the hit ratio by a huge margin(just think how many users you can expect to be males from bangalore).

Is there a way I could define different keys. Also it would be great if the logic of generating the key could be externalised from the domain class itself.

I read the docs and figured out that something called CacheKeyBuilder and/or CacheKeyBuilderImpl could do the trick but I couldn't understand how to proceed.

Edit.. ok.. I got one clue! What CacheKeyBuliderImpl does is, it calls the generateKey method on defaultKeyProvider instance which looks for @cachekeyannotation on the provided domain class's methods and executes the method found to obtain the key.

So replacing either the CacheKeyBuilderImpl with custom Impl or replacing KeyProvider's default implementation within CacheKeyBuilderImpl with yours might do the trick... but the keyprovider reference is hardwired to DefaultKeyProvider.

Can anybody help me implement CacheKeyBuilder(with respect to what different methods do;the documentation doesn't clarify it) and also how do I inject it to be used instead of ususal CacheKeyBuilderImpl

ragnor
  • 2,498
  • 1
  • 22
  • 25
mickeymoon
  • 4,820
  • 5
  • 31
  • 56

1 Answers1

0

Simple Spring Memcached (SSM) hasn't be designed to allow such low level customization. As you wrote one of way is to replace CacheKeyBuilderImpl with own implementation. The default implementation is hardwired but it can be easily replaces using custom simplesm-context.xml configuration.

As I understand your question, you want to cache your User objects under different keys depends on use case. It's supported out of the box because by default SSM uses method argument to generate cache key not the result.

Example:

@ReadThroughMultiCache(namespace = "userslist.cityandgenre", expiration = 3600
public List<User> getByCityAndGenre(@ParameterValueKeyProvider(order = 0) String city, @ParameterValueKeyProvider(order = 1) String genre) {
  // implementation
}

@ReadThroughSingleCache(namespace = "users", expiration = 3600)
public User getByEmail(@ParameterValueKeyProvider String email) {
  // implementation
}

In general the @CacheKeyMethod is only used to generate cache key if object that contains the method is passed as a parameter to the method and the parameter is annotated by @ParameterValueKeyProvider

ragnor
  • 2,498
  • 1
  • 22
  • 25
  • My scenario is a little contrived. The first method is not about finding users for a city and gender.. rather finding relevant deals for a particular user.. the return type is List. The list of deal could be cached by email also but the relevance of deals depend on city and gender of user. So it is better to cache them on a key based on these rather than email so that a single entry can serve all same city and gender users. Currently the method accepts User as a parameter. One resort could be to delegate call to another method with city and gnder passd to method and using them as keys – mickeymoon Jul 17 '13 at 07:33
  • it's like `public List getDealsForUser(User user){ String city = user.getCity(); String gender = user.getGender(); //orm's call for fetching deals for user }` – mickeymoon Jul 17 '13 at 07:38
  • Can you change the method signature and instead of user parameter use city and gender? It will solve your problem and allow to cache list of deals by city and gender. You may also create a new bean with dedicated method getDealsByCityAndGender and invoke it from getDealsForUser (self invocations are not intercepted so cache doesn't work) – ragnor Jul 17 '13 at 11:47
  • that is what I did eventually but that makes me create a lot of code changes and which have relevance in this caching scenario only. moving to a different cache implementation might require undoing it.. as I did ultimately moving to SSM's integration using Spring Cache abstraction – mickeymoon Jul 17 '13 at 20:53