Building the Sample Application
The sample application for this article is based on an earlier object caching framework described in my article
Object Caching With AOP. It's a simple loan processing application where the interest rates for a specified product type (Mortgages or HELOC) are required to process the loan application information. It stores these interest rates in an object cache to reduce database calls and improve application performance. This article enhances the
LoanApp module from the original project to add monitoring and management functionality.
You'll find that different aspects tackle the object caching and JMX monitoring functions. These aspects are called
ObjectCache.java, which defines the base cache methods,
JBossCache.java, which defines caching logic using JBossCache API, and finally,
CacheMonitor.java which implements the monitoring logic.
In
Listing 1, the method called
getInterestRates in the LoanAppHelper class retrieves interest rates from the database using JDBC calls. This is the method you want to intercept using an aspect to check if the data is already in the cache, retrieving it from the database only if the rates are not already cached.
Around advice intercepts any call to the
getInterestRates method to check if the requested data is already present in the cache.
Listing 2 shows the pointcut and
around advice that handles the object caching functionality.
The following code sample shows how to add the MBean functionality to a plain Java object using the
introduction advice. First, define an interface called CacheMonitorMBean and then write
introduction advice to inject the JMX code into the InterestRates object. Here's the interface code.
public interface CacheMonitorMBean {
public CacheStats getCacheStats();
public void setCacheStats(CacheStats cacheStats);
}
And here's the
introduction advice.
declare parents: InterestRates implements
CacheMonitorMBean;
public CacheStats getCacheStats() {
}
public void setCacheStats(CacheStats cacheStats) {
// Populate cache details
}
You also need a monitoring aspect (with
around advice) to update the cache statistics whenever
getInterestRates() method gets called. Here's an excerpt of the monitoring aspect code. The
around advice populates the cache monitor bean with the cache details.
@Pointcut("execution(List
LoanAppHelper.getInterestRates(String)) &&
args(productGroup)")
void pcPrintCacheStatistics(String productGroup){};
@Around("pcPrintCacheStatistics(productGroup)")
public List aroundPcPrintCacheStatistics(
ProceedingJoinPoint thisJoinPoint, String
productGroup) {
System.out.println(
"aroundPcPrintCacheStatistics");
long start = System.currentTimeMillis();
try {
printCacheStatistics();
} catch (Exception e) {
e.printStackTrace();
} catch (Throwable t) {
t.printStackTrace();
}
return null;
}
Testing the Application
 | |
| Figure 2. Eclipse Window: This screenshot of the Eclipse window shows the AJDT build configuration. |
You can compile and build the LoanProc application using an Ant build file (Refer to the
build.xml file located in CacheMonitorAOP project's main directory). The AJDT build configuration file injects the caching and monitoring logic. You can also run the AJDT build from the command line using parameters to specify which aspects can be woven into the application code.
Figure 2 shows the AJDT build properties file (
ajdt.properties) which you can use to enable or disable the Aspectsto weave or unweave those functions into the application code.
I've included a few JUnit test scripts in the sample code that you can use to test different object cache management scenarios. I also ran a performance test using JMeter to monitor the cache trends. After running the tests, you can view the cache monitor details using the JConsole program.
Using code like that in the sample application along with Aspects and JMX, you can introduce instrumentation into an object cache in a Java enterprise application without modifying any existing application logic. Although not implemented here, another feature of the framework that you should explore is
cache invalidation, letting you invalidate cached objects on demand. For example, you might want to include cache invalidation capabilities as part of a Web-based administration tool.