<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>javatips's blog</title>
  <link rel="alternate" type="text/html" href="http://www.javaworld.com/community/blog/21645"/>
  <link rel="self" type="application/atom+xml" href="http://www.javaworld.com/community/blog/21645/atom/feed"/>
  <id>http://www.javaworld.com/community/blog/21645/atom/feed</id>
  <updated>2009-05-06T14:32:32-04:00</updated>
  <entry>
    <title>The Java serialization algorithm revealed</title>
    <link rel="alternate" type="text/html" href="http://www.javaworld.com/community/node/2915" />
    <id>http://www.javaworld.com/community/node/2915</id>
    <published>2009-05-07T15:28:54-04:00</published>
    <updated>2009-05-07T15:36:51-04:00</updated>
    <author>
      <name>javatips</name>
    </author>
    <category term="algorithm" />
    <category term="core java" />
    <category term="Java tips" />
    <category term="serialization" />
    <summary type="html"><![CDATA[<!--paging_filter--><!--paging_filter--><p><em>Serialization</em> is the process of saving an object's state to a sequence of bytes; <em>deserialization</em> is the process of rebuilding those bytes into a live object. The Java Serialization API provides a standard mechanism for developers to handle object serialization. In this tip, you will see how to serialize an object, and why serialization is sometimes necessary. You'll learn about the serialization algorithm used in Java, and see an example that illustrates the serialized format of an object.    ]]></summary>
    <content type="html"><![CDATA[<!--paging_filter--><p><em>Serialization</em> is the process of saving an object's state to a sequence of bytes; <em>deserialization</em> is the process of rebuilding those bytes into a live object. The Java Serialization API provides a standard mechanism for developers to handle object serialization. In this tip, you will see how to serialize an object, and why serialization is sometimes necessary. You'll learn about the serialization algorithm used in Java, and see an example that illustrates the serialized format of an object. By the time you're done, you should have a solid knowledge of how the serialization algorithm works and what entities are serialized as part of the object at a low level.</p>

<h2>Why is serialization required?</h2>

<p>In today's world, a typical enterprise application will have multiple components and will be distributed across various systems and networks. In Java, everything is represented as objects; if two Java components want to communicate with each other, there needs be a mechanism to exchange data. One way to achieve this is to define your own protocol and transfer an object. This means that the receiving end must know the protocol used by the sender to re-create the object, which would make it very difficult to talk to third-party components. Hence, there needs to be a generic and efficient protocol to transfer the object between components. Serialization is defined for this purpose, and Java components use this protocol to transfer objects.</p>

<p>Figure 1 shows a high-level view of client/server communication, where an object is transferred from the client to the server through serialization.</p>

<a href="http://www.javaworld.com/javaworld/jw-05-2009/images/jtip050709-fig1.gif"><img src="http://www.javaworld.com/javaworld/jw-05-2009/images/jtip050709-fig1_thumb.gif" height="156" width="350" alt="A high-level view of serialization in action" /></a>

<h4>Figure 1. A high-level view of serialization in action (click to enlarge)</h4>

<h2>How to serialize an object</h2>

<p>In order to serialize an object, you need to ensure that the class of the object implements the <code>java.io.Serializable</code> interface, as shown in Listing 1.</p>

<h4>Listing 1. Implementing Serializable</h4>

<pre>
<div class="codeblock"><code>import java.io.Serializable;<br /><br />class TestSerial implements Serializable {<br />	public byte version = 100;<br />	public byte count = 0;<br />}</code></div>
</pre>

<p>In Listing 1, the only thing you had to do differently from creating a normal class is implement the <code>java.io.Serializable</code> interface. The <code>Serializable</code> interface is a marker interface; it declares no methods at all. It tells the serialization mechanism that the class can be serialized.</p>

<p>Now that you have made the class eligible for serialization, the next step is to actually serialize the object. That is done by calling the <code>writeObject()</code> method of the <code>java.io.ObjectOutputStream</code> class, as shown in Listing 2.</p>

<h4>Listing 2. Calling writeObject()</h4>

<pre>
<div class="codeblock"><code>public static void main(String args[]) throws IOException {<br />	FileOutputStream fos = new FileOutputStream(&quot;temp.out&quot;);<br />	ObjectOutputStream oos = new ObjectOutputStream(fos);<br />	TestSerial ts = new TestSerial();<br />	oos.writeObject(ts);<br />	oos.flush();<br />	oos.close();<br />}</code></div>
</pre>

<p>Listing 2 stores the state of the <code>TestSerial</code> object in a file called <code>temp.out</code>.  <code>oos.writeObject(ts);</code> actually kicks off the serialization algorithm, which in turn writes the object to <code>temp.out</code>.</p>

<p>To re-create the object from the persistent file, you would employ the code in Listing 3.</p>

<h4>Listing 3. Recreating a serialized object</h4>

<pre>
<div class="codeblock"><code>public static void main(String args[]) throws IOException {<br />	FileInputStream fis = new FileInputStream(&quot;temp.out&quot;);<br />	ObjectInputStream oin = new ObjectInputStream(fis);<br />	TestSerial ts = (TestSerial) oin.readObject();<br />	System.out.println(&quot;version=&quot;+ts.version);<br />}</code></div>
</pre>

<p>In Listing 3, the object's restoration occurs with the <code>oin.readObject()</code> method call. This method call reads in the raw bytes that we previously persisted and creates a live object that is an exact replica of the original object graph. Because <code>readObject()</code> can read any serializable object, a cast to the correct type is required. </p>

<p>Executing this code will print <code>version=100</code> on the standard output.</p>

<h2>The serialized format of an object</h2>

<p>What does the serialized version of the object look like? Remember, the sample code in the previous section saved the serialized version of the <code>TestSerial</code> object into the file <code>temp.out</code>. Listing 4 shows the contents of <code>temp.out</code>,  displayed in hexadecimal. (You need a hexadecimal editor to see the output in hexadecimal format.)</p>

<h4>Listing 4. Hexadecimal form of TestSerial</h4>

<pre>
<div class="codeblock"><code>AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65<br />73 74 A0 0C 34 00 FE B1 DD F9 02 00 02 42 00 05<br />63 6F 75 6E 74 42 00 07 76 65 72 73 69 6F 6E 78<br />70 00 64</code></div>
</pre>

<p>If you look again at the actual <code>TestSerial</code> object, you'll see that it has only two byte members, as shown in Listing 5.</p>

<h4>Listing 5. TestSerial's byte members</h4>

<pre>
<div class="codeblock"><code>	public byte version = 100;<br />	public byte count = 0;</code></div>
</pre>

<p>The size of a byte variable is one byte, and hence the total size of the object (without the header) is two bytes. But if you look at the size of the serialized object in Listing 4, you'll see 51 bytes. Surprise! Where did the extra bytes come from, and what is their significance? They are introduced by the serialization algorithm, and are required in order to to re-create the object. In the next section, you'll explore this algorithm in detail.</p>

<h2>Java's serialization algorithm</h2>

<p>By now, you should have a pretty good knowledge of how to serialize an object. But how does the process work under the hood? In general the serialization algorithm does the following:</p>

<ul>
<li>It writes out the metadata of the class associated with an instance.</li>
<li>It recursively writes out the description of the superclass until it finds <code>java.lang.object</code>.</li>
<li>Once it finishes writing the metadata information, it then starts with the actual data associated with the instance. But this time, it starts from the topmost superclass.</li>
<li>It recursively writes the data associated with the instance, starting from the least superclass to the most-derived class. </li>
</ul>

<p>I've written a different example object for this section that will cover all possible cases. The new sample object to be serialized is shown in Listing 6.</p>

<h4>Listing 6. Sample serialized object</h4>

<pre>
<div class="codeblock"><code>class parent implements Serializable {<br />	int parentVersion = 10;<br />}<br /><br />class contain implements Serializable{<br />	int containVersion = 11;<br />}<br />public class SerialTest extends parent implements Serializable {<br />	int version = 66;<br />	contain con = new contain();<br /><br />	public int getVersion() {<br />		return version;<br />	}<br />	public static void main(String args[]) throws IOException {<br />		FileOutputStream fos = new FileOutputStream(&quot;temp.out&quot;);<br />		ObjectOutputStream oos = new ObjectOutputStream(fos);<br />		SerialTest st = new SerialTest();<br />		oos.writeObject(st);<br />		oos.flush();<br />		oos.close();<br />	}<br />}</code></div>
</pre>

<p>This example is a straightforward one. It serializes an object of type <code>SerialTest</code>, which is derived from <code>parent</code> and has a container object, <code>contain</code>. The serialized format of this object is shown in Listing 7.</p>

<h4>Listing 7. Serialized form of sample object</h4>

<pre>
<div class="codeblock"><code>AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65<br />73 74 05 52 81 5A AC 66 02 F6 02 00 02 49 00 07<br />76 65 72 73 69 6F 6E 4C 00 03 63 6F 6E 74 00 09<br />4C 63 6F 6E 74 61 69 6E 3B 78 72 00 06 70 61 72<br />65 6E 74 0E DB D2 BD 85 EE 63 7A 02 00 01 49 00<br />0D 70 61 72 65 6E 74 56 65 72 73 69 6F 6E 78 70<br />00 00 00 0A 00 00 00 42 73 72 00 07 63 6F 6E 74<br />61 69 6E FC BB E6 0E FB CB 60 C7 02 00 01 49 00<br />0E 63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E 78<br />70 00 00 00 0B</code></div>
</pre>

<p>Figure 2 offers a high-level look at the serialization algorithm for this scenario.</p>

<img src="http://www.javaworld.com/javaworld/jw-05-2009/images/jtip050709-fig2.gif" height="711" width="350" alt="An outline of the serialization algorithm" />

<h4>Figure 2. An outline of the serialization algorithm</h4>

<p>Let's go through the serialized format of the object in detail and see what each byte represents.  Begin with the serialization protocol information:</p>

<ul>
<li><code>AC ED</code>:  <code>STREAM_MAGIC</code>. Specifies that this is a serialization protocol.</li>
<li><code>00 05</code>: <code>STREAM_VERSION</code>. The serialization version.</li>
<li><code>0x73</code>: <code>TC_OBJECT</code>. Specifies that this is a new <code>Object</code>.</li>
</ul>

<p>The first step of the serialization algorithm is to write the description of the class associated with an instance. The example serializes an object of type <code>SerialTest</code>, so the  algorithm starts by writing the description of the <code>SerialTest</code> class.</p>

<ul>
<li><code>0x72</code>: <code>TC_CLASSDESC</code>. Specifies that this is a new class.</li>
<li><code>00 0A</code>: Length of the class name.</li>
<li><code>53 65 72 69 61 6c 54 65 73 74</code>: <code>SerialTest</code>, the name of the class.</li>
<li><code>05 52 81 5A AC 66 02 F6</code>: <code>SerialVersionUID</code>, the serial version identifier of this class.</li>
<li><code>0x02</code>: Various flags. This particular flag says that the object supports serialization.</li>
<li><code>00 02</code>: Number of fields in this class.</li>
</ul>

<p>Next, the algorithm writes the field <code>int version = 66;</code>.</p>

<ul>
<li><code>0x49</code>: Field type code. 49 represents "I", which stands for <code>Int</code>.</li>
<li><code>00 07</code>: Length of the field name.</li>
<li><code>76 65 72 73 69 6F 6E</code>: <code>version</code>, the name of the field.</li>
</ul>

<p>And then the algorithm writes the next field, <code>contain con = new contain();</code>. This is an object, so it will write the canonical JVM signature of this field.</p>

<ul>
<li><code>0x74</code>: <code>TC_STRING</code>. Represents a new string.</li>
<li><code>00 09</code>: Length of the string.</li>
<li><code>4C 63 6F 6E 74 61 69 6E 3B</code>: <code>Lcontain;</code>, the canonical JVM signature.</li>
<li><code>0x78</code>: <code>TC_ENDBLOCKDATA</code>, the end of the optional block data for an object.</li>
</ul>

<p>The next step of the algorithm is to write the description of the <code>parent</code> class, which is the immediate superclass of <code>SerialTest</code>.</p>

<ul>
<li><code>0x72</code>: <code>TC_CLASSDESC</code>. Specifies that this is a new class.</li>
<li><code>00 06</code>: Length of the class name.</li>
<li><code>70 61 72 65 6E 74</code>: <code>SerialTest</code>, the name of the class</li>
<li><code>0E DB D2 BD 85 EE 63 7A</code>: <code>SerialVersionUID</code>, the serial version identifier of this class.</li>
<li><code>0x02</code>: Various flags. This flag notes that the object supports serialization.</li>
<li><code>00 01</code>: Number of fields in this class.</li>
</ul>

<p>Now the algorithm will write the field description for the <code>parent</code> class. <code>parent</code> has one field, <code>int parentVersion = 100;</code>.</p>

<ul>
<li><code>0x49</code>: Field type code. 49 represents "I", which stands for <code>Int</code>.</li>
<li><code>00 0D</code>: Length of the field name.</li>
<li><code>70 61 72 65 6E 74 56 65 72 73 69 6F 6E</code>: <code>parentVersion</code>, the name of the field.</li>
<li><code>0x78</code>: <code>TC_ENDBLOCKDATA</code>, the end of block data for this object.</li>
<li><code>0x70</code>: <code>TC_NULL</code>, which represents the fact that there are no more superclasses because we have reached the top of the class hierarchy.</li>
</ul>

<p>So far, the serialization algorithm has written the description of the class associated with the instance and all its superclasses. Next, it will write the actual data associated with the instance. It writes the parent class members first:</p>

<ul>
<li><code>00 00 00 0A</code>: 10, the value of <code>parentVersion</code>.</li>
</ul>

<p>Then it moves on to <code>SerialTest</code>.</p>

<ul>
<li><code>00 00 00 42</code>: 66, the value of <code>version</code>.
</li>
</ul>

<p>The next few bytes are interesting. The algorithm needs to write the information about the <code>contain</code> object, shown in Listing 8.</p>

<h4>Listing 8. The contain object</h4>

<pre>
<div class="codeblock"><code>contain con = new contain();</code></div>
</pre>

<p>Remember, the serialization algorithm hasn't written the class description for the <code>contain</code> class yet. This is the opportunity to write this description.</p>

<ul>
<li><code>0x73</code>: <code>TC_OBJECT</code>, designating a new object.</li>
<li><code>0x72</code>: <code>TC_CLASSDESC</code>.</li>
<li><code>00 07</code>: Length of the class name.</li>
<li><code>63 6F 6E 74 61 69 6E</code>: <code>contain</code>, the name of the class.</li>
<li><code>FC BB E6 0E FB CB 60 C7</code>: <code>SerialVersionUID</code>, the serial version identifier of this class.</li>
<li><code>0x02</code>: Various flags. This flag indicates that this class supports serialization.</li>
<li><code>00 01</code>: Number of fields in this class.</li>
</ul>

<p>Next, the algorithm must write the description for <code>contain</code>'s only field, <code>int containVersion = 11;</code>.</p>

<ul>
<li><code>0x49</code>: Field type code. 49 represents "I", which stands for <code>Int</code>.</li>
<li><code>00 0E</code>: Length of the field name.</li>
<li><code>63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E</code>:  <code>containVersion</code>, the name of the field.</li>
<li><code>0x78</code>: <code>TC_ENDBLOCKDATA</code>.</li>
</ul>

<p>Next, the serialization algorithm checks to see if <code>contain</code> has any parent classes. If it did, the algorithm would start writing that class; but in this case there is no superclass for <code>contain</code>, so the algorithm writes <code>TC_NULL</code>.</p>

<ul>
<li><code>0x70</code>: <code>TC_NULL</code>.</li>
</ul>

<p>Finally, the algorithm writes the actual data associated with <code>contain</code>.</p>

<ul>
<li><code>00 00 00 0B</code>: 11, the value of <code>containVersion</code>.</li>
</ul>

<h2>Conclusion</h2>

<p>In this tip, you have seen how to serialize an object, and learned how the serialization algorithm works in detail. I hope this article gives you more detail on what happens when you actually serialize an object.</p>

<h4>About the author</h4>

<p><a href="mailto:sathipal@in.ibm.com">Sathiskumar Palaniappan</a> has more than four years of experience in the IT industry, and has been working with Java-related technologies for more than three years. Currently, he is working as a system software engineer at the Java Technology Center, IBM Labs. He also has experience in the telecom industry.</p>

<h4>Resources</h4>

<ul>
<li>Read the <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java object serialization specification</a>. (Spec is a PDF.)</li>
<li>"<a href="http://www.javaworld.com/javaworld/jw-07-2000/jw-0714-flatten.html">Flatten your objects: Discover the secrets of the Java Serialization API</a>" (Todd M. Greanier, JavaWorld, July 2000) offers a look into the nuts and bolts of the serialization process.</li>
<li><a href="http://oreilly.com/catalog/javarmi/chapter/ch10.html">Chapter 10</a> of <em>Java RMI</em> (William Grosso, O'Reilly, October 2001) is also a useful reference.</li>    ]]></content>
  </entry>
  <entry>
    <title>Extending declarative caching services for Spring</title>
    <link rel="alternate" type="text/html" href="http://www.javaworld.com/community/node/2821" />
    <id>http://www.javaworld.com/community/node/2821</id>
    <published>2009-04-23T13:58:06-04:00</published>
    <updated>2009-05-06T14:32:32-04:00</updated>
    <author>
      <name>javatips</name>
    </author>
    <category term="cache" />
    <category term="declarative caching" />
    <category term="Spring AOP" />
    <category term="Spring modules" />
    <summary type="html"><![CDATA[<!--paging_filter--><!--paging_filter--><p>Caching is a vital cross-cutting concern for improving the performance of enterprise applications. If you're building an application with the Spring framework, declarative caching services using <a href="https://springmodules.dev.java.net/">Spring Modules</a> offer an easy way to add and tune caching functionality without touching an application's code. Fundamentally, the approach works very well in achieving its intent; however, it falls short when scaled in real-world scenarios.    ]]></summary>
    <content type="html"><![CDATA[<!--paging_filter--><p>Caching is a vital cross-cutting concern for improving the performance of enterprise applications. If you're building an application with the Spring framework, declarative caching services using <a href="https://springmodules.dev.java.net/">Spring Modules</a> offer an easy way to add and tune caching functionality without touching an application's code. Fundamentally, the approach works very well in achieving its intent; however, it falls short when scaled in real-world scenarios. This tip explains real-world problems faced when using such an approach, and extends the existing declarative model to address them.</p>

<h2>Typical Spring declarative caching</h2>

<p>In enterprise applications, there is often a need to load reference and lookup data into a cache. This is very easily achievable using any of the the approaches mentioned in the Spring Module specification and in Alex Ruiz's article "<a href="http://www.oracle.com/technology/pub/articles/dev2arch/2006/05/declarative-caching.html">Declarative caching services for Spring</a>." These approaches use Spring AOP to identify the target method call and store the returned Java object in the cache. The cache itself is a glorified Java <code>Map</code> object, the key for which is created using the vendor's cache key generation process. The cache can be viewed as a collection of cache entries; each entry represents a key-value pair of a <code>Map</code> object, as illustrated in Figure 1.</p>

<img src="http://www.javaworld.com/javaworld/jw-04-2009/images/jtip042209-fig1.gif" hight="354" width="350" alt="Block diagram of declarative caching approach" />

<h4>Figure 1. Block diagram of declarative caching approach</h4>

<h2>Potential problems with declarative caching</h2>

<p>One problem scenario arises on application startup, and immediately afterwards.  At startup, there is often a need to load reference and lookup data into a cache. This typically involves multiple back-to-back I/O operations to retrieve different datasets. Each I/O operation results in a cache event.</p>

<p>In a cache event scenario, a key is generated using the cache key generation process, and then the cache is checked for the existence of the key. If the key is not found, the underlying method is invoked, resulting in an I/O operation -- a call to a stored procedure, for instance, or to a SQL query. On exit, the object that the method call returns is stored in the cache using the generated key. From the user's perspective, there is a lockout period from the time just before the I/O call is made to the time just after it completes. The caching operation overhead is negligible compared to the time required for the I/O operation, as you can see in Figure 2.</p>

<a href="http://www.javaworld.com/javaworld/jw-04-2009/images/jtip042209-fig2.gif"><img src="http://www.javaworld.com/javaworld/jw-04-2009/images/jtip042209-fig2_thumb.gif" height="102" width="350" alt="Base case timeline diagram of a caching event"/ ></a>

<h4>Figure 2. Base case timeline diagram of a caching event (click to enlarge)</h4>

<p>In practical scenarios, this base case is extended when a number of caching events are called back-to-back, resulting in extended lockout periods. Although it might be acceptable to wait for the application to start up after all of the reference data is loaded, it becomes a huge overhead in cases where almost all datasets are candidates for preloading. This problem could be dealt with by starting the loading process in a separate thread following startup. This thread would then trigger the loading process and the cache building.</p>

<p>Another situation where potential problems might arise comes with cache refresh.  After all, what good is cache if the data remains static? In practical scenarios, there is almost always a need to refresh the cache when the underlying data gets stale. In the declarative caching methodology, this would typically be achieved using a flush, followed by a cache event. A cache refresh event would be triggered by a polling- or interrupt-based mechanism that would result in a cache refresh at any time that the application is in use by end users. A lockout period may result in timeouts -- definitely not acceptable.</p>

<h2>The solution</h2>

<p>Caching on application startup poses no problems -- the application is not accessible until it has started, after all. However, if the caching is done post-startup and in a back-to-back scenario, the application does suffer from a lockout period, as it would in a cache refresh scenario. The way to solve the problem is by splitting the cache into two components -- a <em>serving cache</em> and a <em>reload cache</em> -- and using a synchronization mechanism between the two. The purpose of the reload cache is to perform a refresh -- that is, to flush and reload the data, based on an appropriate trigger that indicates that the data in cache is dirty. The serving cache always serves the client requests and does not depend on the I/O operation. It uses a poll- or interrupt-based synchronization mechanism that helps it copy the data from the reload cache; this is done in memory.  From the user perspective, the serving cache is always available. The relationship between the two is illustrated in Figure 3.</p>

<a href="http://www.javaworld.com/javaworld/jw-04-2009/images/jtip042209-fig3.gif"><img src="http://www.javaworld.com/javaworld/jw-04-2009/images/jtip042209-fig3_thumb.gif" height="245" width="350" alt="Block diagram of extended declarative cache approach"/ ></a>


<h4>Figure 3. Block diagram of extended declarative cache approach (click to enlarge)</h4>

<p>If you use this approach, the lockout period is limited to the reload side of the cache, as described above. The time required to perform in-memory synchronization is negligible even in clustered environments, and hence the lockout period is negligible. The timeline diagram in Figure 4 depicts the flow of events.</p>

<a href="http://www.javaworld.com/javaworld/jw-04-2009/images/jtip042209-fig4.gif"><img src="http://www.javaworld.com/javaworld/jw-04-2009/images/jtip042209-fig4_thumb.gif" height="201" width="350" alt="Timeline diagram of a caching event with extended declarative caching approach."/ ></a>

<h4>Figure 4. Timeline diagram of a caching event with extended declarative caching approach (click to enlarge)</h4>

<h2>How it's done</h2>

<p>Alex Ruiz's article explains the use of Spring Modules to achieve caching in enterprise applications. There are three approaches to do so, as described in the Spring Module specification:</p>

<ul>
<li>Per-bean configuration</li>
<li>Source-level metadata attributes</li>
<li><code>BeanNameAutoProxyCreator</code></li>
</ul>

<p>I will demonstrate an implementation of the extended caching concept using the per-bean configuration approach, and compare it with standard declarative caching as I explain how the extended version works. (You could also implement this extended caching model with source-level metadata attributes or <code>BeanNameAutoProxyCreator</code>, as there are no changes in the underlying Spring Modules.)</p>

<p>You begin by defining the service interface. Listing 1 illustrates how this would be done with declarative caching; Listing 2 shows you how it would work with extended declarative caching. Notice that the <code>RC</code> postfix has been defined for refresh/reload operations.</p>

<h4>Listing 1. Defining the service interface with declarative caching</h4>

<pre>
<div class="codeblock"><code>public interface CacheService {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataMap getXXXMap(String region,Long tradeDate);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void flushXXXMap(String region,Long tradeDate);<br />}</code></div>
</pre>

<h4>Listing 2. Defining the service interface with extended declarative caching</h4>

<pre>
<div class="codeblock"><code>public interface CacheService {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataMap getXXXMap(String region,Long tradeDate);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataMap getXXXMapRC(String region,Long tradeDate);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void flushXXXMapRC(String region,Long tradeDate);<br />}</code></div>
</pre>

<p>Next, you need to implement the cache service. Listing 3 shows how this would be done in traditional declarative caching; Listing 4 illustrates our new extended declarative caching model.</p>

<h4>Listing 3. Implementing the cache service with declarative caching</h4>

<pre>
<div class="codeblock"><code>public class CacheServiceImpl implements CacheService {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private XXXDao XXXDao;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void setXXXDao(XXXDao dao) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XXXDao = dao;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void setXXXDao(XXXDao dao) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XXXDao = dao;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public DataMap getXXXMap(String region, Long tradeDate) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(&quot;getXXXMap: region=[&quot; + region<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + &quot;] tradeDate=[&quot; + tradeDate + &quot;]&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return XXXDao.getXXXMap(region, tradeDate);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void flushXXXMap(String region, Long tradeDate) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(&quot;flushXXXMap:region=[&quot; + region<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + &quot;] tradeDate=[&quot; + tradeDate + &quot;]&quot;);<br />...<br />}</code></div>
</pre>

<h4>Listing 4. Implementing the cache service with extended declarative caching</h4>

<pre>
<div class="codeblock"><code>public class CacheServiceImpl implements CacheService {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private XXXDao XXXDao;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void setXXXDao(XXXDao dao) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XXXDao = dao;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void setXXXDao(XXXDao dao) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XXXDao = dao;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public DataMap getXXXMap(String region, Long tradeDate) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(&quot;getXXXMap: region=[&quot; + region<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + &quot;] tradeDate=[&quot; + tradeDate + &quot;]&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return XXXDao.getXXXMap(region, tradeDate);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public DataMap getXXXMapRC(String region, Long tradeDate) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(&quot;getXXXMapRC: region=[&quot; + region<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + &quot;] tradeDate=[&quot; + tradeDate + &quot;]&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return XXXDao.getXXXMap(region, tradeDate);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void flushXXXMapRC(String region, Long tradeDate) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(&quot;flushXXXMapRC:region=[&quot; + region<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + &quot;] tradeDate=[&quot; + tradeDate + &quot;]&quot;);<br />...<br />}</code></div>
</pre>

<p>Now you need to define the per-bean configuration, as shown in Listings 5 and 6 (again, the first listing shows how it would work under traditional declarative caching, the second under extended declarative caching). Notice that the names of the serving and reload caches are different.</p>

<h4>Listing 5. Defining per-bean configuration with declarative caching</h4>

<pre>
<div class="codeblock"><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br />&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlns:coherence=&quot;http://www.springmodules.org/schema/coherence&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans <a href="http://www.springframework.org/schema/beans/spring-beans-2.0.xsd" title="http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">http://www.springframework.org/schema/beans/spring-beans-2.0.xsd</a><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.springmodules.org/schema/coherence" title="http://www.springmodules.org/schema/coherence">http://www.springmodules.org/schema/coherence</a> <a href="http://www.springmodules.org/schema/cache/springmodules-tangosol.xsd&quot;&gt;" title="http://www.springmodules.org/schema/cache/springmodules-tangosol.xsd&quot;&gt;">http://www.springmodules.org/schema/cache/springmodules-tangosol.xsd&quot;&gt;</a><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;coherence:config failquietly=&quot;false&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;coherence:proxy id=&quot;cacheServiceTarget&quot; refid=&quot;cacheServiceImpl&quot;&amp;gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- CACHING &amp;amp; PARTIAL FLUSHING --&gt;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;coherence:caching methodname=&quot;getXXXMap&quot; cachename=&quot;repl-XXXCache&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- FLUSHING --&gt;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;coherence:flushing methodname=&quot;flushXXXMap&quot; cachenames=&quot;repl-XXXCache&quot; when=&quot;before&quot;&gt;<br />...<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/coherence:proxy&gt;<br />&lt;/beans&gt;</code></div>
</pre>

<h4>Listing 6. Defining per-bean configuration with extended declarative caching</h4>

<pre>
<div class="codeblock"><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br />&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlns:coherence=&quot;http://www.springmodules.org/schema/coherence&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans <a href="http://www.springframework.org/schema/beans/spring-beans-2.0.xsd" title="http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">http://www.springframework.org/schema/beans/spring-beans-2.0.xsd</a><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.springmodules.org/schema/coherence" title="http://www.springmodules.org/schema/coherence">http://www.springmodules.org/schema/coherence</a> <a href="http://www.springmodules.org/schema/cache/springmodules-tangosol.xsd&quot;&gt;" title="http://www.springmodules.org/schema/cache/springmodules-tangosol.xsd&quot;&gt;">http://www.springmodules.org/schema/cache/springmodules-tangosol.xsd&quot;&gt;</a><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;coherence:config failquietly=&quot;false&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;coherence:proxy id=&quot;cacheServiceTarget&quot; refid=&quot;cacheServiceImpl&quot;&amp;gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;lt;!-- CACHING &amp;amp; PARTIAL FLUSHING --&gt;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;coherence:caching methodname=&quot;getXXXMap&quot; cachename=&quot;repl-XXXCache&quot;&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;coherence:caching methodname=&quot;getXXXMapRC&quot; cachename=&quot;repl-XXXCacheRC&quot;&gt;<br />...<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- FLUSHING --&gt;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;coherence:flushing methodname=&quot;flushXXXMapRC&quot; cachenames=&quot;repl-XXXCacheRC&quot; when=&quot;before&quot;&gt;<br />...<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/coherence:proxy&gt;<br />&lt;/beans&gt;</code></div>
</pre>

<p>Next, under extended declarative caching, you need to reload the cache, as illustrated in Listing 7. (Note that this would be unnecessary with ordinary declarative caching.)</p>

<h4>Listing 7. Reloading the cache</h4>

<pre>
<div class="codeblock"><code>this.cacheService.flushXXXMap(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataBlockConstants.GLOBAL_REGION, null);<br />this.cacheService.getXXXMap(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataBlockConstants.GLOBAL_REGION, null);<br />this.cacheService.flushXXXMapRC(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataBlockConstants.GLOBAL_REGION, null);<br />this.cacheService.getXXXMapRC(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataBlockConstants.GLOBAL_REGION, null);</code></div>
</pre>

<p>Finally, in extended declarative caching, you need a mechanism for synching the reload and serving caches. This is illustrated in Listing 8.</p>

<h4>Listing 8. Synching the declarative and serving caches</h4>

<pre>
<div class="codeblock"><code>NamedCache XXXReloadCache = CacheFactory<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getCache(&quot;repl-XXXCacheRC&quot;);<br />NamedCache XXXServingCache = CacheFactory<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getCache(&quot;repl-XXXCache&quot;);<br />Map XXXServingCacheBuffer = new HashMap();<br />for (Iterator _i = XXXServingCache.keySet().iterator(); _i<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .hasNext();) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object _key = _i.next();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object _value = XXXServingCache.get(_key);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XXXServingCacheBuffer.put(_key, _value);<br />}<br /><br />// System.out.println(&quot;XXXServingCacheBuffer=&quot;<br />// + XXXServingCacheBuffer);<br />Map XXXReloadCacheBuffer = new HashMap();<br />for (Iterator _i = XXXReloadCache.keySet().iterator(); _i<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .hasNext();) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object _key = _i.next();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object _value = XXXReloadCache.get(_key);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XXXReloadCacheBuffer.put(_key, _value);<br />}<br />// System.out.println(&quot;XXXReloadCacheBuffer=&quot;<br />// + XXXReloadCacheBuffer);<br />XXXServingCache.clear();<br />XXXServingCache.putAll(XXXReloadCacheBuffer);</code></div>
</pre>

<p>The above steps help to implement the design approach. The client's only interface is with the serving cache, which does not depend on the I/O operations to finish. This gives the perception that the cache is available at all times.</p>

<h2>Conclusion</h2>

<p>Declarative caching services for Spring are a non-intrusive approach that addresses the caching aspect in enterprise applications. The design outlined in this tip attempts to provide a practical, real-world solution to problems that emerge with this caching approach as applications scale in cache size, leaving the underlying caching concepts as is. It definitely opens up a door for improvements in the next version of Spring Modules around ideas of cache refresh.</p>

<h4>About the author</h4>

<p><a href="mailto:sameerpadwal@yahoo.com">Sameer Padwal</a> has a background as a system and software architect, with more than 13 years of experience in the finance services, banking, and insurance industries. Sameer holds several Sun Java Certifications, as well as an M.S. in computer science from the Stevens Institute of Technology.</p>

<h4>Resources</h4>

<ul>
<li>Read "<a href="http://www.oracle.com/technology/pub/articles/dev2arch/2006/05/declarative-caching.html">Declarative caching services for Spring</a>" (Alex Ruiz, Oracle Technical Network, May 2006).</li>

<li>Check out the <a href="https://springmodules.dev.java.net/">Spring Modules</a> home page.</li>

<li>Take a look at these cache systems:
<ul>
<li><a href="http://ehcache.sourceforge.net/">EHCache</a></li>
<li><a href="http://www.jboss.com/products/jbosscache">JBoss Cache</a></li>
<li><a href="http://jakarta.apache.org/jcs/">Java Caching System (JCS)</a></li>
<li><a href="http://www.opensymphony.com/oscache">OSCache</a></li>
<li><a href="http://www.tangosol.com/">Tangosol Coherence</a></li>
</ul>
</li>

</body>
</html>
    ]]></content>
  </entry>
</feed>

