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.
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