Google App Engine: Understanding Non-Invasive Caching

In the last post on understanding caching we talked about the general support of GAE for caching and how we could easily incorporate caching in our application. You would also recollect that we talked about the invasive form of caching in which the business layer was aware about the caching framework. In this post let us talk about the non-invasive way to cache. Since caching is one of the cross cutting concerns like security and logging, the non-invasive way to cache is best implemented by aspects.

Since we are using spring in our application, the solution is biased towards that however, you could use the aspectj framework and the concept remains the same.

A quick reference, a JoinPoint is any Method in your app’s code that you wrote whether you were using AOP or not. A Pointcut is telling AOP which Joinpoints you want your advice code to run with/on. An advice is code you want to run when that JoinPoint method is being called, without adding the code directly into your app’s method. An Aspect is the class that holds the advice code.

Normally, we would know the interesting points to apply the advise because there are the entities that we might be requesting again and again or these entities are expensive to create and hence are created and cached.

Let us see what our advise might look like

[sourcecode language=”java”]
public class CacheAspect {
private final static Logger logger = Logger.getLogger(CacheAspect.class);
public Object invoke(ProceedingJoinPoint pjp) throws Throwable {

String cacheKey = getCacheKey(pjp.getArgs(), className, methodName);
Object returnedValue;
if ((returnedValue = CacheController.get(cacheKey)) == null) {
logger.info(" CACHE MISS, starting cache process for = " + cacheKey);
returnedValue = pjp.proceed();
CacheController.put(cacheKey, returnedValue);
} else {
logger.info(" CACHE HIT! for key = " + cacheKey);
}
return returnedValue;
}
[/sourcecode]

As you would notice that this code is an around advice. This aspect is wrapped around a method. The aspect code checks if the value that we are interested in, identified by the key, exists in the cache or not. If not, then get the return value by invoking the method which is being advised.

returnedValue = pjp.proceed();
and put the value in the cache
CacheController.put(cacheKey, returnedValue);

If you would recall, this is very similar to the code that we wrote in the business layer of the last post. The difference here being that this code is non-invasive since it is not present in the business layer but would be applied as an aspect.

Let us look at what a typical method that this would advice would look like

[sourcecode language=”java”]
@SuppressWarnings("unchecked")
public List findAllActive() {
List<Customer> customers = new ArrayList<Customer>();
List resultList = getEntityManager().createQuery("SELECT FROM Customer customer WHERE active = true")
.getResultList();
customers.addAll(resultList);
return customers;
}
[/sourcecode]

Here we are getting a list of active customers and this does not change that frequently.

So how would our aspect work?

Once it is applied on the findAllActive method, it would check whether the list of customers is present in the cache. If yes, then return the value for the cache else, let the call to the datastore proceed and fetch the values from there. Also, set the values to the cache for subsequent requests.

The pointcut definition looks like this

[sourcecode language=”xml”]

<bean id="cacheAspect" class="com.bookmyhours.audit.CacheAspect">

<aop:config>
<aop:aspect id="asp2" ref="cacheAspect">
<aop:around
pointcut="execution(public * com.bookmyhours.*.dao.*ProjectAssignmentDao.*findAll*(..))"
method="invoke" />
aop:aspect>
aop:config>
[/sourcecode]

So we,

  1. Defined the aspect which had the advice.
  2. Next we identified the joinpoint which is nothing but any method in your class and
  3. Next we defined the bean for the aspect and the
  4. Pointcut definition which defines when the aspect should be applied.

The advantage as mentioned earlier is clean code and a non-invasive way to apply caching to your application.

Written by 

Vikas is the CEO and Co-Founder of Knoldus Inc. Knoldus does niche Reactive and Big Data product development on Scala, Spark, and Functional Java. Knoldus has a strong focus on software craftsmanship which ensures high-quality software development. It partners with the best in the industry like Lightbend (Scala Ecosystem), Databricks (Spark Ecosystem), Confluent (Kafka) and Datastax (Cassandra). Vikas has been working in the cutting edge tech industry for 20+ years. He was an ardent fan of Java with multiple high load enterprise systems to boast of till he met Scala. His current passions include utilizing the power of Scala, Akka and Play to make Reactive and Big Data systems for niche startups and enterprises who would like to change the way software is developed. To know more, send a mail to hello@knoldus.com or visit www.knoldus.com

1 thought on “Google App Engine: Understanding Non-Invasive Caching

Leave a Reply

%d bloggers like this: