赞
踩
使用方法:
1、agent类需要实现特定方法,实现
public static void premain(String args, Instrumentation instrumentation) 或者 public static void premain(String args)
(优先两个参数的方法,找不到则执行一个参数的方法)
2、jar包里的MF文件需要指定Premain-Class为agent类(Can-Redefine-Classes和Can-Retransform-Classes通常也指定为true)
3、将agent类和MF文件打成jar包
4、启动java程序时使用-javaagent参数指定代理jar包(java程序可以用java直接启动主类class也可以-jar启动jar包,-javaagent位置放-jar前面,多个javaagent按序执行)
Demo:
Hello.java、hello.MF是用来测试的java程序,hello.bat脚本用来编译打包;
MyAgent.java、myagent.MF、myagent.bat用来编译打包代理类的;
agentcls文件夹用来放置agent类的class文件并用作打包目录,并且提前将javassist.jar解压进去(我的agent类使用了javassist修改类内容,并且我想打成一个jar包);
Hello.java代码:
- public class Hello {
-
- public static void main(String[] args) {
- System.out.println("HELLO");
- Count c = new Count();
- System.out.println(c.count(1));
- }
-
- }
- class Count{
- public int count(int x){
- return x + 1;
- };
- };
hello.MF文件:
- Manifest-Version: 1.0
- Created-By: FlyLikeButterfly
- Main-Class: Hello
-
hello.bat脚本:
- javac Hello.java
- jar cvfm hello.jar hello.MF Hello.class Count.class
- del Hello.class
- del Count.class
- pause
MyAgent.java代码:
- package test;
- import java.io.ByteArrayInputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.lang.instrument.ClassFileTransformer;
- import java.lang.instrument.IllegalClassFormatException;
- import java.lang.instrument.Instrumentation;
- import java.security.ProtectionDomain;
-
- import javassist.ClassPool;
- import javassist.CtClass;
- import javassist.CtMethod;
-
-
- public class MyAgent {
-
- public static void premain(String args, Instrumentation instrumentation) {
- ClassFileTransformer mytransformer = new ClassFileTransformer() {
- @Override
- public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
- ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
- System.out.println("className:" + className);
- if("Count".equals(className)) {
- System.out.println("==find class.");
- ClassPool pool = ClassPool.getDefault();
- InputStream is = new ByteArrayInputStream(classfileBuffer);
- try {
- CtClass cls = pool.makeClass(is);
- CtMethod m = cls.getDeclaredMethod("count");
- m.setBody("{return $1 + 10;}");
- return cls.toBytecode();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- return classfileBuffer;
- }
- };
- instrumentation.addTransformer(mytransformer);
- }
-
- public static void premain(String args) {
- System.out.println("premain.");
- }
-
- }
myagent.MF文件:
- Manifest-Version: 1.0
- Created-By: FlyLikeButterfly
- Premain-Class: test.MyAgent
- Can-Redefine-Classes: true
- Can-Retransform-Classes: true
-
myagent.bat脚本:
- javac -cp agentcls -d agentcls MyAgent.java
- jar cvfm myagent.jar myagent.MF -C agentcls .
- pause
执行测试:
先生成测试需要的jar包:执行hello.bat生成hello.jar,执行myagent.bat生成myagent.jar;
先测试hello.jar包,再加入javaagent测试:
java -jar hello.jar
java -javaagent:myagent.jar -jar hello.jar
执行结果:
使用方法:
1、agent需要实现特定方法,实现
public static void agentmain(String args, Instrumentation instrumentation) 或者 public static void agentmain(String args)
(跟premain一样优先两个参数的)
2、MF文件指定Agent-Class参数(Can-Redefine-Classes和Can-Retransform-Classes)
3、将agent类和MF打包
4、正常启动java测试程序
5、使用一个带main方法的java程序attach到java测试程序vm的id,将agent.jar加载到vm里
Demo:
hello.bat、Hello.java、hello.MF用来生成测试jar;
myagent.bat、MyAgent.java、myagent.MF和agentcls文件夹用来生成agent的jar;
startAttach.bat、StartAttach.jar用来将agent.jar加载到目标vm里;
Hello.java代码:
- package test;
-
- public class Hello {
-
- public static void main(String[] args) {
- System.out.println("HELLO");
- Count c = new Count();
- while(true){
- System.out.println(c.count(1));
- try {
- Thread.sleep(3000);
- }catch(Exception e) {
- }
- }
- }
-
- }
- class Count{
- public int count(int x){
- return x + 1;
- };
- };
hello.MF文件:
- Manifest-Version: 1.0
- Created-By: FlyLikeButterfly
- Main-Class: test.Hello
-
hello.bat脚本:
- javac -d hellocls Hello.java
- jar cvfm hello.jar hello.MF -C hellocls .
- pause
MyAgent.java代码:
- package test;
- import java.lang.instrument.ClassDefinition;
- import java.lang.instrument.Instrumentation;
- import java.lang.reflect.Method;
-
- import javassist.ClassClassPath;
- import javassist.ClassPool;
- import javassist.CtClass;
- import javassist.CtMethod;
-
-
- public class MyAgent {
-
- public static void agentmain(String args, Instrumentation instrumentation) {
- Class<?>[] clses = instrumentation.getAllLoadedClasses();
- for(Class<?> cls : clses) {
- if(cls.getName().equals("test.Count")) {
- System.out.println("----" + cls.getName());
- for(Method m : cls.getMethods()) {
- System.out.println("-" + m);
- }
- System.out.println("----");
-
- try {
- ClassPool pool = ClassPool.getDefault();
- ClassClassPath classPath = new ClassClassPath(cls);
- pool.insertClassPath(classPath);
- CtClass ccls = pool.get("test.Count");
- System.out.println(ccls);
- CtMethod cm = ccls.getDeclaredMethod("count");
- System.out.println(cm);
- cm.setBody("{return $1 * 10;}");
- ClassDefinition definitions = new ClassDefinition(cls, ccls.toBytecode());
- instrumentation.redefineClasses(definitions);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-
- }
-
- public static void agentmain(String args) {
- System.out.println("agentmain.");
- }
-
- }
myagent.MF文件:
- Manifest-Version: 1.0
- Created-By: FlyLikeButterfly
- Agent-Class: test.MyAgent
- Can-Redefine-Classes: true
- Can-Retransform-Classes: true
-
myagent.bat脚本:
- javac -cp agentcls -d agentcls MyAgent.java
- jar cvfm myagent.jar myagent.MF -C agentcls .
- pause
StartAttach.java代码:
- import com.sun.tools.attach.VirtualMachine;
- import com.sun.tools.attach.VirtualMachineDescriptor;
-
- public class StartAttach {
-
- public static void main(String[] args) {
- for(VirtualMachineDescriptor v : VirtualMachine.list()) {
- System.out.println(v.id() + ":" + v.displayName());
- if(v.displayName().contains("hello")) {
- try {
- System.out.println("find hello VM and attach. VM_id=" + v.id());
- VirtualMachine vm = VirtualMachine.attach(v.id());
- vm.loadAgent("myagent.jar");
- vm.startLocalManagementAgent();
- vm.detach();
- System.out.println("detached VM.");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
-
- }
startAttach.bat脚本:
- javac StartAttach.java
- java StartAttach
- pause
执行测试:
先执行hello.bat和myagent.bat生成测试jar包和代理jar包
先正常执行测试jar包:
java -jar hello.jar
然后执行startAttach.bat脚本将代理jar加载到测试vm里:
另外,执行attach的java程序可以跟agent合成到一个jar里:
将main方法挪到myagent.java里,并且修改myagent.MF文件添加Main-Class
MyAgent.java代码:
- package test;
- import java.lang.instrument.ClassDefinition;
- import java.lang.instrument.Instrumentation;
- import java.lang.reflect.Method;
-
- import javassist.ClassClassPath;
- import javassist.ClassPool;
- import javassist.CtClass;
- import javassist.CtMethod;
-
- import com.sun.tools.attach.VirtualMachine;
- import com.sun.tools.attach.VirtualMachineDescriptor;
-
- public class MyAgent {
-
- public static void main(String[] args) {
- for(VirtualMachineDescriptor v : VirtualMachine.list()) {
- System.out.println(v.id() + ":" + v.displayName());
- if(v.displayName().contains("hello")) {
- try {
- System.out.println("find hello VM and attach. VM_id=" + v.id());
- VirtualMachine vm = VirtualMachine.attach(v.id());
- vm.loadAgent("myagent.jar");
- vm.startLocalManagementAgent();
- vm.detach();
- System.out.println("detached VM.");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
-
- public static void agentmain(String args, Instrumentation instrumentation) {
- Class<?>[] clses = instrumentation.getAllLoadedClasses();
- for(Class<?> cls : clses) {
- if(cls.getName().equals("test.Count")) {
- System.out.println("----" + cls.getName());
- for(Method m : cls.getMethods()) {
- System.out.println("-" + m);
- }
- System.out.println("----");
-
- try {
- ClassPool pool = ClassPool.getDefault();
- ClassClassPath classPath = new ClassClassPath(cls);
- pool.insertClassPath(classPath);
- CtClass ccls = pool.get("test.Count");
- System.out.println(ccls);
- CtMethod cm = ccls.getDeclaredMethod("count");
- System.out.println(cm);
- cm.setBody("{return $1 * 10;}");
- ClassDefinition definitions = new ClassDefinition(cls, ccls.toBytecode());
- instrumentation.redefineClasses(definitions);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-
- }
-
- public static void agentmain(String args) {
- System.out.println("agentmain.");
- }
-
- }
myagnet.MF文件:
- Manifest-Version: 1.0
- Created-By: FlyLikeButterfly
- Main-Class: test.MyAgent
- Agent-Class: test.MyAgent
- Can-Redefine-Classes: true
- Can-Retransform-Classes: true
-
执行hello.bat和myagent.bat生成jar包
命令行分别执行测试jar和代理jar:
修改类最好使用原来加载的类修改,不然很容易出现异常(修饰词不一致,方法名不一致,参数返回值不一致等等)
测试使用attach的时候javassist找不到Object,加了pool.insertClassPath(classPath)解决;
参考:https://www.cnblogs.com/rickiyang/p/11368932.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。