freemarker是一个java的模板引擎,我通常用来做代码生成工具。 里面的源码有很多,所以我想有没有办法能把代码生成过程中的类名打印出来,这样我就能知道那些java文件是必须的。 找了找动态代理的AOP,还看了看CGlib,感觉都不太方便。 这时想起了以前看SwingSpy中用到的jdk1.5之后的一个东西, Instrument。很强大,也很好用。 GenCode.java //FreeMarker 代码生成 package cn.z; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.HashMap; import java.util.Map; import freemarker.core.Environment; import freemarker.template.Configuration; import freemarker.template.DefaultObjectWrapper; import freemarker.template.Template; import freemarker.template.TemplateException; import freemarker.template.TemplateExceptionHandler; public class GenCode { /** * @param args * @throws IOException * @throws TemplateException */ public static void main(String[] args) throws IOException, TemplateException { // 模板路径 String dir = "template"; Configuration cfg = new Configuration(); // 加载freemarker模板文件 cfg.setDirectoryForTemplateLoading(new File(dir)); // 设置对象包装器 cfg.setObjectWrapper(new DefaultObjectWrapper()); // 设计异常处理器 cfg.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER); // 定义并设置数据 Map<String, String> data = new HashMap<String, String>(); data.put("persion", "小吴"); // 获取指定模板文件 Template template = cfg.getTemplate("ex.ftl"); // 定义输入文件,默认生成在工程根目录 Writer out = new OutputStreamWriter(new FileOutputStream("test.html"), "GBK"); Environment env = template.createProcessingEnvironment(data, out); env.setOutputEncoding("GBK"); env.process(); System.out.println("successful"); } } PerfMonAgent.java //Instrument中的代理类 package cn.z; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.Instrumentation; public class PerfMonAgent { static private Instrumentation inst = null; /** * This method is called before the application’s main-method is called, * when this agent is specified to the Java VM. **/ public static void premain(String agentArgs, Instrumentation _inst) { System.out.println("PerfMonAgent.premain() was called."); // Initialize the static variables we use to track information. inst = _inst; // Set up the class-file transformer. ClassFileTransformer trans = new PerfMonXformer(); System.out.println("Adding a PerfMonXformer instance to the JVM."); inst.addTransformer(trans); } } PerfMonXformer.java //对类进行拦截,其中还可以对类方法之类的进行修改,跟Hook差不多。 package cn.z; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.security.ProtectionDomain; public class PerfMonXformer implements ClassFileTransformer { @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { byte[] transformed = null; if (className.startsWith("freemarker")) System.out.println(className); return transformed; //return null.不修改类 } } MANIFEST.MF //必须正确配置,否则不会执行PerfMonAgent的premain Manifest-Version: 1.0 Premain-Class: cn.z.PerfMonAgent 执行过程,打包上面的代码为PerfMonAgent.jar,记得 MANIFEST.MF要包含进去。 命令行 java -javaagent:PerfMonAgent.jar cn.z.GenCode 然后执行过程中我们就能看到 freemarker/template/ObjectWrapper freemarker/template/TemplateException freemarker/template/Configuration freemarker/core/Configurable freemarker/core/ArithmeticEngine freemarker/core/ArithmeticEngine freemarker/core/Configurable freemarker/core/ArithmeticEngine freemarker/core/ParseException freemarker/core/FMParserConstants freemarker/core/TemplateClassResolver freemarker/cache/CacheStorage freemarker/cache/TemplateLoader freemarker/template/TemplateExceptionHandler freemarker/template/TemplateExceptionHandler freemarker/template/TemplateExceptionHandler freemarker/template/TemplateExceptionHandler freemarker/template/TemplateExceptionHandler freemarker/ext/beans/BeansWrapper freemarker/template/TemplateModelException freemarker/ext/beans/SimpleMemberModel freemarker/ext/beans/MethodMap freemarker/ext/util/ModelFactory freemarker/ext/util/ModelCache freemarker/ext/beans/BeansModelCache freemarker/template/utility/UndeclaredThrowableException freemarker/template/TemplateHashModel freemarker/template/TemplateModel 。。。。。。 那些文件被调用了显而易见了。 如果监视到方法一级的调用,我们就可以做一个代码覆盖率的统计了。