Daily Power Ups

Recent Posts Widget

Tuesday, August 27, 2013

ASM for bytecode analysis

In the not too distant past I was tasked with a project to increase up-time and performance by ensuring that a JVM did not have to be restarted when data was updated in the back-end DB.  As you can imagine this entails several different things, the top most of which is ensuring that all cache's within the Application running on the JVM are refreshed; this includes both managed and unmanaged caches.


During the exploration phase we had to identify all of the potential cache's, for that my friend Mark Petrovic came up with a great solution using ASM.  Here we explore his real-world example of using ASM to analyze bytecode in order to find the set of Java source files that contain anything that looks like it could be used as a cache - i.e. custom cache object or some java collection object.
ASM is a powerful Java bytecode analysis toolkit that lets you do pretty much anything you want with class files. It's how Hibernate and Spring take a POJO and synthesize a proxy object that let's you do aspect oriented programming and declarative transaction boundaries. It's how your IDE does breathtaking refactoring; how it tells you variable "foo" is never used, yet declared.
My problem is vastly simpler: read bytecode and look for ICache-like and Java Collection- or Map-like class fields that may be performing out of band business caching.
Here's how to do it with ASM with this quick and dirty; for the code click here.


This tool reads classfiles out of the classes directory, WEB-INF/classes, and records instances of cache-like fields it encounters in those class files. On exit, it writes what it finds.

The result for this use case was: 379 of our class files have cache-like fields that are candidates for dynamically updated caches. Now nowhere near 379 classes will need modification or refactoring for the project, because only a handful of these classes are doing the type of caching we care about. But at least we have reduced our scope of classes to review by creating this complete list of where to hunt.
Here is the filter logic, where aClass is the candidate:
boolean potentialCache = Collection.class.isAssignableFrom(aClass)
                        || Map.class.isAssignableFrom(aClass)
                        || iCacheClass.isAssignableFrom(aClass)
                        || iCacheManagerClass.isAssignableFrom(aClass)
                        || ehCacheClass.isAssignableFrom(aClass);
The output looks like this:
File: ~/site/trunk/deploy/site-app/WEB-INF/classes/com/foobar/entity/survey/SurveyCategory.class
   surveyCategoryLinks == java.util.Set
   childSurveyCategories == java.util.Set
File: ~/site//trunk/deploy/site-app/WEB-INF/classes/com/foobar/biz/search/indexmanager/LuceneIndexerListener.class
   storedListProducts == java.util.List
File: ~/site/trunk/deploy/site-app/WEB-INF/classes/com/foobar/system/email/AsynchronousEmailSender.class
   mailQueue == java.util.List
File: /~/site/trunk/deploy/site-app/WEB-INF/classes/com/foobar/entity/product/ProductInfoPage.class
   ATTRIBUTE_DEFINITIONS == java.util.Map
   topics == java.util.Map
File: ~/site/trunk/deploy/site-app/WEB-INF/classes/com/foobar/biz/abtest/ABTestManager.class
   siteURITestMap == java.util.Map
   siteConversionURIMap == java.util.Map
   siteElementTestMap == java.util.Map
   siteFeatureTestMap == java.util.Map
   pageTrafficMap == java.util.Map
   conversionTallyMap == java.util.Map
   conversionTallyResetMap == java.util.Map
   testUsageMap == java.util.Map
   testUsageResetMap == java.util.Map
   versionUsageMap == java.util.Map
   versionUsageResetMap == java.util.Map
   versionRequestsMap == java.util.Map
   versionRequestsResetMap == java.util.Map
...

The tool's entry point for processing is org.foobar.asmlab.App#main, and takes the absolute path to a WEB-INF directory as an argument.

No comments:

Post a Comment