Archive for February, 2009

Spring and Caching

Tuesday, February 3rd, 2009

Caching is one of the most efficient approaches in case performance needs to be optimized; especially in a scenario with persistence layer. In such a kind of software,  because expensive objects can be passed during the communication with the repository, each request means increased time complexity. In this case, to minimize the time complexity, most of the time the best thing is to minimize the number of calls to the repository.

Caching can simply be considered as moving data from one place to another. However, the most important condition is, the destination should be more easily accessible. If we move data to a place which could be the  more expensively accessible, then this would not be a sensible approach at all.

Caching in Java could be done in numerous ways. In fact, technologies such as AOP make caching even more easier to design and maintain.

In this article, you will find a simple example of caching using one of the caching frameworks, EHCache, and Spring Framework. Spring Framework also uses its own AOP support for injecting caching behaviour to objects and procedures.

In order to demonstrate the technology, I had to pick up a straightforward scenario. In fact, I am aware that this example is too simple for caching to increase efficiency.

Suppose we need to read data from a file and print the content of it. The design is really simple. However, if we also need the same data multiple times in a small period, such as 1.000 times in a minute, then it could be a point where we might start worrying about the performance. In order to improve the performance we may choose the caching approach and use Spring to achieve our goal.

What we need to do is injecting caching behaviour using Spring and we will do that without doing any extras to the code that is being executed. This is important since our task in fact is to refactor the code in such a way that it will have a better performance. One important thing here is, the refactoring should not interfere with the previous work.

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class Bar {

public String read() throws FileNotFoundException
{
System.out.println(“read() is executed.”);

Scanner scan = new Scanner(new File(“a.txt”));
String str = “”;
while(scan.hasNextLine())
{
str += scan.nextLine();
}

return str;
}

}

public static void processBar(Bar b) throws FileNotFoundException
{
for(int i = 0; i < 1000; i++)
{
System.out.println(b.read());
}
}

Assume that this part was written before considering some improvements regarding to the performance were needed. In order to improve this using Spring, we need to create a configuration file to define caching behaviour and inject this behaviour to class Bar.

ehcache.xml file:

<ehcache>
<cache name=”barCache” maxElementsInMemory=”500″
eternal=”true”
memoryStoreEvictionPolicy=”LFU” timeToLiveSeconds=”0″ />

</ehcache>

We also need an applicationContext.xml file to configure the beans.

<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:p=”http://www.springframework.org/schema/p”
xmlns:context=”http://www.springframework.org/schema/context”
xmlns:aop=”http://www.springframework.org/schema/aop”
xmlns:tx=”http://www.springframework.org/schema/tx”
xmlns:jee=”http://www.springframework.org/schema/jee”
xmlns:ehcache=”http://www.springmodules.org/schema/ehcache”
xsi:schemaLocation=”
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springmodules.org/schema/ehcache http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd”>

<ehcache:config configLocation=”classpath:ehcache.xml” />

<ehcache:proxy id=”barBean”>
<bean class=”Bar” />
<ehcache:caching methodName=”read” cacheName=”barCache” />
</ehcache:proxy>

</beans>

Now, to test the code,

public static void main(String[] args) throws InterruptedException, FileNotFoundException
{
ApplicationContext ctx = new ClassPathXmlApplicationContext(“applicationContext.xml”);

Bar b = (Bar)ctx.getBean(“barBean”);

processBar(b);
}

As it is clearly indicated, without modifying any java code at all, caching behaviour has been injected. The properties and preferences related to the caching could be modified any time by just altering the xml file. For instance, by changing timeToLiveSeconds property, one could alter the time limit.
In order to keep things simple, nothing related to flushing have been added. In fact, flushing is essential in real caching examples. Flushing is simply to remove all or some part of cache at some point.

For instance, what if a method that writes to the file in Bar class has been invoked in somewhere during the caching period? It certainly wouldn’t make sense to keep that cache anymore, since it is certain that the content of the text file is modified.

To illustrate this, suppose class Bar has the following method:

public void write(String str) throws IOException
{
BufferedWriter out = new BufferedWriter(new FileWriter(“a.txt”));
out.write(str);
out.close();

}

It is not difficult to add flushing using Spring. In fact, it could even be configured by adding just one line to the xml file in most cases.

<ehcache:proxy id=”barBean”>
<bean class=”Bar” />
<ehcache:caching methodName=”read” cacheName=”barCache” />

<ehcache:flushing methodName=”write” cacheNames=”barCache” />

</ehcache:proxy>

As you might have noticed, the bold line has been added to the XML file. Please also notice that ehcache:flushing tag has cacheNames attribute rather than having cacheName.

Now, Bar class’ caching behaviour is configured in such a way that it will be flushed whenever write method is called. Unless write(str) is called, the cache will be used instead of connecting to the text file each time.