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