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
。。。。。。
那些文件被调用了显而易见了。
如果监视到方法一级的调用,我们就可以做一个代码覆盖率的统计了。