A Java cache example with Guava
Last week I showed you how to increase the performance of multiple java calls by making them asynchronous and parallel. This week we take a look at another potential performance booster, you should always keep in mind - caching.
Let’s imagine a scenario where you call a REST service and you know the returned values don’t change very often. In this case you really need to consider caching the response. We will use Guava’s provided caching capabilities to implement such a cache for this example.
Here is the piece of code that might do just that:
import org.codingpedia.example;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import javax.inject.Inject;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.MediaType;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
public class GuavaCacheDemoService {
static LoadingCache<String, ToDo> toDosCache = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterAccess(60, TimeUnit.SECONDS)
.build(
new CacheLoader<String, ToDo>() {
public ToDo load(String id) {
final ToDo toDo = restApiClient.getToDo(id);
return toDo;
}
}
);
@Inject
RestApiClient restApiClient;
ToDo getToDo(String toDoId) throws ExecutionException {
final ToDO toDo = toDosCache.get(toDoId);
return toDo;
}
}
Notes:
- you obtain a
Cache
by using theCacheBuilder
builder pattern - our cache should not grow beyound 1000 entries -
CacheBuilder.maximumSize(1000)
CacheBuilder.expireAfterAccess(60, TimeUnit.SECONDS)
only expire entries after the 60 seconds have passed since the entry was last accessed by a read or a write- we use for caching a
LoadingCache
, which is a Cache built with an attachedCacheLoader
- to create a
CacheLoader
you just need to implementing the methodV load(K key) throws Exception
- inside the method’s body you would put the expensive method - here the REST call
- to create a
- to return the value associated with the key in the cache you need to use the
V get(K key) throws ExecutionException
method; in our casetoDosCache.get(toDoId)
- your ToDos might change every night - then you want to evict all entries from
the cache by using
Cache.invalidateAll()
- Guava caches are local to a single run of your application. They do not store data in files, or on outside servers. If this does not fit your needs, consider a tool like Memcached.
I encourage you to read the Guava Caches Explained Guide to learn about other caching capabilities like writing to cache, using other eviction methods, explicit removals and so on.