package com.mcg.demo.jvm.javaagent;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by mcg on 2018/1/31.
 */
public class APP {

    private int i=0;
    public static void main(String args [])  throws InterruptedException{

        APP app=new APP();
        app.helloproxy();

    }

    public void helloproxy() throws InterruptedException {

        while(true) {
            Demo demo=new Demo();
            demo.helloproxy();
            hello();
            Thread.sleep(1000);
        }

    }

    public  void hello() throws InterruptedException {

                 i = 1 + i;
             Thread.sleep(1000);

    }


}
package com.mcg.demo.jvm.javaagent;

/**
 * Created by mcg on 2018/2/2.
 */
public class Demo {

    public void helloproxy()  {

        System.out.println("hello world");
    }

    public void hello()  {


    }
}
package com.mcg.demo.jvm.javaagent;

import javassist.*;

import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;

/**
 * Created by mcg on 2018/1/31.
 */
public class Agent {

    public static void premain(String agentOps, Instrumentation inst) {

        System.out.println("premain.....");

        inst.addTransformer(new AgentClassFileTransformer()) ;

    }

    public static void agentmain(String args, Instrumentation inst) throws Exception {

        System.out.println("agentmain.....");
        String className="com.mcg.demo.jvm.javaagent.Demo";

        CtClass ctclass = ClassPool.getDefault().get(className);;

        String methodName="helloproxy";

        CtMethod ctmethod = ctclass.getDeclaredMethod(methodName);// 得到这方法实例
        String newMethodName = methodName;// 新定义一个方法叫做比如sayHello$old
        ctmethod.setName(newMethodName);// 将原来的方法名字修改
        ctmethod.insertAt(9,"System.out.println(\"hello agent\");");
            // 创建新的方法,复制原来的方法,名字为原来的名字

        inst.redefineClasses(new ClassDefinition(Demo.class,ctclass.toBytecode()));

    }

}

package com.mcg.demo.jvm.javaagent;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by mcg on 2018/1/31.
 */
public class AgentClassFileTransformer implements ClassFileTransformer {

    final static String prefix = "\nlong startTime = System.currentTimeMillis();\n";
    final static String postfix = "\nlong endTime = System.currentTimeMillis();\n";

    // 被处理的方法列表
    final static Map<String, List<String>> methodMap = new HashMap<String, List<String>>();

    public AgentClassFileTransformer() {
        add("com.mcg.demo.jvm.javaagent.APP.hello");
    }

    private void add(String methodString) {
        String className = methodString.substring(0, methodString.lastIndexOf("."));
        String methodName = methodString.substring(methodString.lastIndexOf(".") + 1);
        List<String> list = methodMap.get(className);
        if (list == null) {
            list = new ArrayList<String>();
            methodMap.put(className, list);
        }
        list.add(methodName);
    }


    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {

        className = className.replace("/", ".");

        if(className.equals("com.mcg.demo.jvm.javaagent.APP")) {

            try {

                CtClass ctclass =ClassPool.getDefault().get(className);;

                for (String methodName : methodMap.get(className)) {

                    String outputStr = "\nSystem.out.println(\"this method " + methodName
                            + " cost:\" +(endTime - startTime) +\"ms.\");";

                    CtMethod ctmethod = ctclass.getDeclaredMethod(methodName);// 得到这方法实例
                    String newMethodName = methodName + "$old";// 新定义一个方法叫做比如sayHello$old
                    ctmethod.setName(newMethodName);// 将原来的方法名字修改

                    // 创建新的方法,复制原来的方法,名字为原来的名字
                    CtMethod newMethod = CtNewMethod.copy(ctmethod, methodName, ctclass, null);

                    // 构建新的方法体
                    StringBuilder bodyStr = new StringBuilder();
                    bodyStr.append("{");
                    bodyStr.append(prefix);
                    bodyStr.append(newMethodName + "($$);\n");// 调用原有代码,类似于method();($$)表示所有的参数
                    bodyStr.append("\nSystem.out.println(\"i:\"+i);\n");
                    bodyStr.append(postfix);
                    bodyStr.append(outputStr);
                    bodyStr.append("}");
                    newMethod.setBody(bodyStr.toString());// 替换新方法
                    ctclass.addMethod(newMethod);// 增加新方法
                }
                return ctclass.toBytecode();
            } catch (Exception e) {
                System.out.println(e.getMessage());
                System.out.println("exception");
            }

        }


        return null;
    }
}


package com.mcg.demo.jvm.javaagent;

import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;

import java.util.List;

/**
 * Created by mcg on 2018/2/1.
 */
public class AttachThread extends Thread {

    private final List<VirtualMachineDescriptor> listBefore;

    private final String jar;

    AttachThread(String attachJar, List<VirtualMachineDescriptor> vms) {
        listBefore = vms;  // 记录程序启动时的 VM 集合
        jar = attachJar;
    }

    public void run() {
        VirtualMachine vm = null;
        List<VirtualMachineDescriptor> listAfter = null;
        try {
            int count = 0;
            while (true) {
                listAfter = VirtualMachine.list();
                for (VirtualMachineDescriptor vmd : listAfter) {
                    if (vmd.displayName().equals("app.jar")) {
                        // 如果 VM 有增加,我们就认为是被监控的 VM 启动了
                        // 这时,我们开始监控这个 VM
                        vm = VirtualMachine.attach(vmd);
                        System.out.println("start....");
                        break;
                    }
                }
                Thread.sleep(5000);
                count++;
                if (null != vm || count >= 10) {
                    break;
                }
            }
            vm.loadAgent(jar);
            vm.detach();
        } catch (Exception e) {
            System.out.println(e);
        }
    }


    public static void main(String[] args) throws InterruptedException {
        new AttachThread("agent.jar", VirtualMachine.list()).start();

    }
}

Manifest-Version: 1.0
Premain-Class: com.mcg.demo.jvm.javaagent.Agent
Agent-Class: com.mcg.demo.jvm.javaagent.Agent
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Boot-Class-Path: lib/javassist-3.1RC1.jar
main-Class: com.mcg.demo.jvm.javaagent.Agent

results matching ""

    No results matching ""