package org.googlecode.perftrace.javaagent; import java.io.IOException; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.security.ProtectionDomain; import java.util.logging.Level; import java.util.logging.Logger; import org.googlecode.perftrace.javaagent.util.ClassFactoryClassPool; import org.googlecode.perftrace.javassist.CannotCompileException; import org.googlecode.perftrace.javassist.ClassPool; import org.googlecode.perftrace.javassist.CtClass; import org.googlecode.perftrace.javassist.CtMethod; import org.googlecode.perftrace.javassist.CtNewMethod; import org.googlecode.perftrace.javassist.NotFoundException; import org.googlecode.perftrace.schema.BootstrapPerftrace; import org.googlecode.perftrace.util.StringUtils; /** * @author zhongfeng * */ public abstract class AbstractClassFileTransformer implements ClassFileTransformer { private final static Logger logger = Logger .getLogger(AbstractClassFileTransformer.class.getName()); private BootstrapPerftrace bootstrapPerftrace; /** * @param bootstrapPerftrace */ public AbstractClassFileTransformer(BootstrapPerftrace bootstrapPerftrace) { this.bootstrapPerftrace = bootstrapPerftrace; } @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if (className != null && className.indexOf("/") != -1) { className = className.replaceAll("/", "."); }// // || if (StringUtils.startsWith(className, "org.googlecode.perftrace.") || StringUtils.startsWith(className, "java.") || StringUtils.startsWith(className, "javax.") || StringUtils.startsWith(className, "sun.") || StringUtils.startsWith(className, "com.sun.")) return classfileBuffer; return doClass(loader, className, classBeingRedefined, classfileBuffer); } protected byte[] doClass(ClassLoader loader, String className, Class<?> clazz, byte[] b) { // add loaderclasspath ClassPool pool = new ClassFactoryClassPool(loader); logger.log(Level.INFO, "RawClassLoader:" + loader.getClass().getName() + "-ClassName:" + className + "-PoolClassLoader:" + pool.getClassLoader()); CtClass ctClass = null; byte[] ret = null; try { ctClass = pool.makeClass(new java.io.ByteArrayInputStream(b)); if (ctClass.isInterface() == false) { CtMethod[] methods = ctClass.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { if (isMatcher(methods[i], ctClass)) { doMethod(methods[i], ctClass, clazz); } } ret = ctClass.toBytecode(); } } catch (Exception e) { if (logger.isLoggable(Level.SEVERE)) { logger.log(Level.SEVERE, "Could not instrument className:" + className, e); } ret = b; } finally { if (ctClass != null) { ctClass.detach(); } } return ret; } /** * @param loader * @param pool * @throws IOException * @throws NotFoundException */ protected void addClassPath(ClassLoader loader, ClassPool pool) { } protected void doMethod(CtMethod ctMethod, CtClass ctClass, Class<?> javaClazz) throws NotFoundException, CannotCompileException { logger.log(Level.FINE, "TransForm MethodName:{},ClassName:{}", new Object[] { ctMethod.getName(), ctClass.getName() }); String mname = ctMethod.getName(); String rename = buildMethodName(mname, ctClass); ctMethod.setName(rename); CtMethod mnew = CtNewMethod.copy(ctMethod, mname, ctClass, null); // build body text of method to wrap call with perftrace String body = createNewMethodBody(mnew, ctClass, rename); mnew.setBody(body); ctClass.addMethod(mnew); } // 解决public boolean doSomeThing() { super.doSomeThing() …… …… ; private String buildMethodName(String methodName, CtClass ctClass) { String[] nameSegs = StringUtils.split(ctClass.getName(), "."); String classShortName = nameSegs[nameSegs.length - 1]; return methodName + "$impl" + "_" + classShortName; } /** * @param method * @param javaClazz * @param mname * @return * @throws NotFoundException */ protected abstract String createNewMethodBody(CtMethod ctMethod, CtClass ctClass, String orgiName) throws NotFoundException; private boolean isMatcher(CtMethod ctMethod, CtClass ctClass) { if (ctMethod.isEmpty()) { return false; } return getBootstrapPerftrace().getMethodMatcherHandler().matches( ctMethod, ctClass); } public BootstrapPerftrace getBootstrapPerftrace() { return bootstrapPerftrace; } public void setBootstrapPerftrace(BootstrapPerftrace bootstrapPerftrace) { this.bootstrapPerftrace = bootstrapPerftrace; } }