Java字节码instrument研究

MyAgent项目



    4.0.0

    com.book.MyAgent
    MyAgent
    1.0

    
        
            javassist
            javassist
            3.12.1.GA
        
        
            org.ow2.asm
            asm-all
            5.1
        
        
            net.bytebuddy
            byte-buddy
            1.5.7
        
        
            net.bytebuddy
            byte-buddy-agent
            1.5.7
        
    
    
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                
                    1.8
                    1.8
                
            
            
                org.apache.maven.plugins
                maven-source-plugin
                3.0.1
                
                    
                        attach-sources
                        verify
                        
                            jar-no-fork
                        
                    
                
            
            
                org.apache.maven.plugins
                maven-assembly-plugin
                2.6
                
                    
                        jar-with-dependencies
                    
                    
                        src/main/resources/META-INF/MANIFEST.MF
                    
                
                
                    
                        assemble-all
                        package
                        
                            single
                        
                    
                
            
            
                org.apache.maven.plugins
                maven-shade-plugin
                
                    
                        package
                        
                            shade
                        
                    
                
                
                    
                        
                            javassist:javassist:jar:
                            net.bytebuddy:byte-buddy:jar:
                            net.bytebuddy:byte-buddy-agent:jar:
                        
                    
                
            
        
        
            
                ${basedir}/src/main/resources
            
            
                ${basedir}/src/main/java
            
        
    

 

AgentTime类

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;


public class AgentTime {
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("监控耗时 >>>");
        // 添加 Transformer
        ClassFileTransformer transformer = new PerformMonitorTransformer();
        inst.addTransformer(transformer);
        System.out.println("监控耗时 <<<");
    }
}

PerformMonitorTransformer类

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtBehavior;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;

public class PerformMonitorTransformer implements ClassFileTransformer {

    private static final Set classNameSet = new HashSet<>();

    static {
        classNameSet.add("com.book.test.TestTime");
    }

    @Override
    public byte[] transform(ClassLoader loader,
            String className,
            Class classBeingRedefined,
            ProtectionDomain protectionDomain,
            byte[] classfileBuffer) throws IllegalClassFormatException {
        //System.out.println("监控耗时 >>>1");
        try {
            String currentClassName = className.replaceAll("/", ".");
            if (!classNameSet.contains(currentClassName)) { // 仅仅提升Set中含有的类
                return null;
            }
            System.out.println("transform: [" + currentClassName + "]");

            CtClass ctClass = ClassPool.getDefault().get(currentClassName);

            CtBehavior[] methods = ctClass.getDeclaredBehaviors();

            for (CtBehavior method : methods) {
                System.out.println("method: [" + method + "]");
                enhanceMethod(method);
            }
            
            CtMethod m = ctClass.getDeclaredMethod("fun1");
            m.insertBefore("{ System.out.println($1); System.out.println($2); }");           
            return ctClass.toBytecode();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private void enhanceMethod(CtBehavior method) throws Exception {
        if (method.isEmpty()) {
            return;
        }
        
        String methodName = method.getName();
        if (methodName.equalsIgnoreCase("main")) { // 不提升main方法
            return;
        }
        
        CtClass[] prams = method.getParameterTypes();
        if (prams.length > 0) {
            method.insertBefore("{ System.out.println($1);System.out.println($2); }");
        }
        
        final StringBuilder source = new StringBuilder();
        if (methodName.equalsIgnoreCase("fun3")) { // 修改fun3方法
            source.append("{")
                    .append("System.out.println(\"方法三真的被替换了\");").append("\n")
                    .append("}");
        } else {
            source.append("{")
                    .append("long start = System.nanoTime();\n") // 前置增强: 打入时间戳
                    .append("$_ = $proceed($$);\n") // 保留原有的代码处理逻辑                  
                    .append("System.out.print(\"method:[" + methodName + ">>>]\");").append("\n")
                    .append("System.out.println(\" cost:[\" +(System.nanoTime() -start)+ \"ns]\");") // 后置增强
                    .append("}");
        }

        ExprEditor editor = new ExprEditor() {
            @Override
            public void edit(MethodCall methodCall) throws CannotCompileException {
                methodCall.replace(source.toString());
            }
        };
        method.instrument(editor);
    }
}

被增强的项目:

TestAgent



    4.0.0
    com.book
    TestAgent
    1.0-SNAPSHOT
    jar
    
        UTF-8
        1.8
        1.8
    
    
        
                
                maven-assembly-plugin    
                    
                    false    
                        
                        jar-with-dependencies    
                        
                        
                            
                            com.book.test.TestTime    
                            
                    
                    
                    
                        
                        make-assembly    
                        package    
                            
                            assembly    
                            
                        
                    
                        
        
    

 TestTime类

public class TestTime {
    private int fun1(int a,int b) {
        System.out.println("\n方法一开始>>>");
        return a+b;
    }

    private void fun2() {
        System.out.println("\n方法二开始>>>");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace(); 
        }
        System.out.println("方法二结束<<<");
    }

    private void fun3() {
        System.out.println("方法三会被干掉么?");        
    }
    
    public static void main(String[] args) {
        TestTime test = new TestTime();
        test.fun1(2,3);
        test.fun2();
        test.fun3();
    }
}

运行:

java  -javaagent:E:\worktest\MyAgent\target\MyAgent-1.0-jar-with-dependencies.jar -jar E:\worktest\TestAgent\target\TestAgent-1.0-SNAPSHOT.jar com.book.test.TestTime

 

Java字节码instrument研究_第1张图片

参考:https://blog.csdn.net/f59130/article/details/78481594

Javassist 使用指南(三)

你可能感兴趣的:(Java)