当前位置:   article > 正文

JavaDemo——关于javaagent的使用_-javaagent参数

-javaagent参数

一、使用javaagent参数启动java程序

使用方法:

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代码:

  1. public class Hello {
  2. public static void main(String[] args) {
  3. System.out.println("HELLO");
  4. Count c = new Count();
  5. System.out.println(c.count(1));
  6. }
  7. }
  8. class Count{
  9. public int count(int x){
  10. return x + 1;
  11. };
  12. };

hello.MF文件:

  1. Manifest-Version: 1.0
  2. Created-By: FlyLikeButterfly
  3. Main-Class: Hello

hello.bat脚本:

  1. javac Hello.java
  2. jar cvfm hello.jar hello.MF Hello.class Count.class
  3. del Hello.class
  4. del Count.class
  5. pause

 

MyAgent.java代码:

  1. package test;
  2. import java.io.ByteArrayInputStream;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.lang.instrument.ClassFileTransformer;
  6. import java.lang.instrument.IllegalClassFormatException;
  7. import java.lang.instrument.Instrumentation;
  8. import java.security.ProtectionDomain;
  9. import javassist.ClassPool;
  10. import javassist.CtClass;
  11. import javassist.CtMethod;
  12. public class MyAgent {
  13. public static void premain(String args, Instrumentation instrumentation) {
  14. ClassFileTransformer mytransformer = new ClassFileTransformer() {
  15. @Override
  16. public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
  17. ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
  18. System.out.println("className:" + className);
  19. if("Count".equals(className)) {
  20. System.out.println("==find class.");
  21. ClassPool pool = ClassPool.getDefault();
  22. InputStream is = new ByteArrayInputStream(classfileBuffer);
  23. try {
  24. CtClass cls = pool.makeClass(is);
  25. CtMethod m = cls.getDeclaredMethod("count");
  26. m.setBody("{return $1 + 10;}");
  27. return cls.toBytecode();
  28. } catch (Exception e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. return classfileBuffer;
  33. }
  34. };
  35. instrumentation.addTransformer(mytransformer);
  36. }
  37. public static void premain(String args) {
  38. System.out.println("premain.");
  39. }
  40. }

myagent.MF文件:

  1. Manifest-Version: 1.0
  2. Created-By: FlyLikeButterfly
  3. Premain-Class: test.MyAgent
  4. Can-Redefine-Classes: true
  5. Can-Retransform-Classes: true

myagent.bat脚本:

  1. javac -cp agentcls -d agentcls MyAgent.java
  2. jar cvfm myagent.jar myagent.MF -C agentcls .
  3. pause

 

执行测试:

先生成测试需要的jar包:执行hello.bat生成hello.jar,执行myagent.bat生成myagent.jar;

先测试hello.jar包,再加入javaagent测试:

java -jar hello.jar

java -javaagent:myagent.jar -jar hello.jar

执行结果:

 

二、使用attach机制让运行中的java程序加载agent

使用方法:

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代码:

  1. package test;
  2. public class Hello {
  3. public static void main(String[] args) {
  4. System.out.println("HELLO");
  5. Count c = new Count();
  6. while(true){
  7. System.out.println(c.count(1));
  8. try {
  9. Thread.sleep(3000);
  10. }catch(Exception e) {
  11. }
  12. }
  13. }
  14. }
  15. class Count{
  16. public int count(int x){
  17. return x + 1;
  18. };
  19. };

hello.MF文件:

  1. Manifest-Version: 1.0
  2. Created-By: FlyLikeButterfly
  3. Main-Class: test.Hello

hello.bat脚本:

  1. javac -d hellocls Hello.java
  2. jar cvfm hello.jar hello.MF -C hellocls .
  3. pause

 

MyAgent.java代码:

  1. package test;
  2. import java.lang.instrument.ClassDefinition;
  3. import java.lang.instrument.Instrumentation;
  4. import java.lang.reflect.Method;
  5. import javassist.ClassClassPath;
  6. import javassist.ClassPool;
  7. import javassist.CtClass;
  8. import javassist.CtMethod;
  9. public class MyAgent {
  10. public static void agentmain(String args, Instrumentation instrumentation) {
  11. Class<?>[] clses = instrumentation.getAllLoadedClasses();
  12. for(Class<?> cls : clses) {
  13. if(cls.getName().equals("test.Count")) {
  14. System.out.println("----" + cls.getName());
  15. for(Method m : cls.getMethods()) {
  16. System.out.println("-" + m);
  17. }
  18. System.out.println("----");
  19. try {
  20. ClassPool pool = ClassPool.getDefault();
  21. ClassClassPath classPath = new ClassClassPath(cls);
  22. pool.insertClassPath(classPath);
  23. CtClass ccls = pool.get("test.Count");
  24. System.out.println(ccls);
  25. CtMethod cm = ccls.getDeclaredMethod("count");
  26. System.out.println(cm);
  27. cm.setBody("{return $1 * 10;}");
  28. ClassDefinition definitions = new ClassDefinition(cls, ccls.toBytecode());
  29. instrumentation.redefineClasses(definitions);
  30. } catch (Exception e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. }
  35. }
  36. public static void agentmain(String args) {
  37. System.out.println("agentmain.");
  38. }
  39. }

myagent.MF文件:

  1. Manifest-Version: 1.0
  2. Created-By: FlyLikeButterfly
  3. Agent-Class: test.MyAgent
  4. Can-Redefine-Classes: true
  5. Can-Retransform-Classes: true

myagent.bat脚本:

  1. javac -cp agentcls -d agentcls MyAgent.java
  2. jar cvfm myagent.jar myagent.MF -C agentcls .
  3. pause

 

StartAttach.java代码:

  1. import com.sun.tools.attach.VirtualMachine;
  2. import com.sun.tools.attach.VirtualMachineDescriptor;
  3. public class StartAttach {
  4. public static void main(String[] args) {
  5. for(VirtualMachineDescriptor v : VirtualMachine.list()) {
  6. System.out.println(v.id() + ":" + v.displayName());
  7. if(v.displayName().contains("hello")) {
  8. try {
  9. System.out.println("find hello VM and attach. VM_id=" + v.id());
  10. VirtualMachine vm = VirtualMachine.attach(v.id());
  11. vm.loadAgent("myagent.jar");
  12. vm.startLocalManagementAgent();
  13. vm.detach();
  14. System.out.println("detached VM.");
  15. } catch (Exception e) {
  16. e.printStackTrace();
  17. }
  18. }
  19. }
  20. }
  21. }

startAttach.bat脚本:

  1. javac StartAttach.java
  2. java StartAttach
  3. 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代码:

  1. package test;
  2. import java.lang.instrument.ClassDefinition;
  3. import java.lang.instrument.Instrumentation;
  4. import java.lang.reflect.Method;
  5. import javassist.ClassClassPath;
  6. import javassist.ClassPool;
  7. import javassist.CtClass;
  8. import javassist.CtMethod;
  9. import com.sun.tools.attach.VirtualMachine;
  10. import com.sun.tools.attach.VirtualMachineDescriptor;
  11. public class MyAgent {
  12. public static void main(String[] args) {
  13. for(VirtualMachineDescriptor v : VirtualMachine.list()) {
  14. System.out.println(v.id() + ":" + v.displayName());
  15. if(v.displayName().contains("hello")) {
  16. try {
  17. System.out.println("find hello VM and attach. VM_id=" + v.id());
  18. VirtualMachine vm = VirtualMachine.attach(v.id());
  19. vm.loadAgent("myagent.jar");
  20. vm.startLocalManagementAgent();
  21. vm.detach();
  22. System.out.println("detached VM.");
  23. } catch (Exception e) {
  24. e.printStackTrace();
  25. }
  26. }
  27. }
  28. }
  29. public static void agentmain(String args, Instrumentation instrumentation) {
  30. Class<?>[] clses = instrumentation.getAllLoadedClasses();
  31. for(Class<?> cls : clses) {
  32. if(cls.getName().equals("test.Count")) {
  33. System.out.println("----" + cls.getName());
  34. for(Method m : cls.getMethods()) {
  35. System.out.println("-" + m);
  36. }
  37. System.out.println("----");
  38. try {
  39. ClassPool pool = ClassPool.getDefault();
  40. ClassClassPath classPath = new ClassClassPath(cls);
  41. pool.insertClassPath(classPath);
  42. CtClass ccls = pool.get("test.Count");
  43. System.out.println(ccls);
  44. CtMethod cm = ccls.getDeclaredMethod("count");
  45. System.out.println(cm);
  46. cm.setBody("{return $1 * 10;}");
  47. ClassDefinition definitions = new ClassDefinition(cls, ccls.toBytecode());
  48. instrumentation.redefineClasses(definitions);
  49. } catch (Exception e) {
  50. e.printStackTrace();
  51. }
  52. }
  53. }
  54. }
  55. public static void agentmain(String args) {
  56. System.out.println("agentmain.");
  57. }
  58. }

myagnet.MF文件:

  1. Manifest-Version: 1.0
  2. Created-By: FlyLikeButterfly
  3. Main-Class: test.MyAgent
  4. Agent-Class: test.MyAgent
  5. Can-Redefine-Classes: true
  6. 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

https://blog.csdn.net/sun_tantan/article/details/105330517

https://segmentfault.com/a/1190000022359295

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/349181
推荐阅读
  

闽ICP备14008679号