JavaAgent学习笔记

1. 什么是javaagent?

是java命令的参数, 该参数可以指定一个jar包 ,cmd命令格式如下: (javaagent的个数没有限制)

java -javaagent:<jar包路径> [-javaagent:<jar包路径>] -cp <要运行的jar包路径> <运行的类> [该类参数]... 

2. 配置内容

main之前添加手脚:

​ META-INF/MANIFEST.MF文件需要指定Premain-Class字段, 并让该类实现premain方法 JDK1.5

main运行之后添加手脚:

​ META-INF/MANIFEST.MF文件需要指定Agent-Class字段, 并让该类实现agentmain方法 JDK1.6

2.1. Premain-Class的premain方法

  1. 当JVM虚拟机启动时, 在执行自己的jar包的main方法之前, 会先运行premain方法

  2. premain方法有两种实现, 如果都实现了, JVM会优先使用带Instrumentation inst参数的

public static void premain(String agentArgs, Instrumentation inst)
public static void premain(String agentArgs)
  1. Instrumentation接口定义如下:

    public interface Instrumentation {
        
        //增加一个Class 文件的转换器,转换器用于改变 Class 二进制流的数据,参数 canRetransform 设置是否允许重新转换。
        void addTransformer(ClassFileTransformer transformer, boolean canRetransform);
    
        //在类加载之前,重新定义 Class 文件,ClassDefinition 表示对一个类新的定义,如果在类加载之后,需要使用 retransformClasses 方法重新定义。addTransformer方法配置之后,后续的类加载都会被Transformer拦截。对于已经加载过的类,可以执行retransformClasses来重新触发这个Transformer的拦截。类加载的字节码被修改后,除非再次被retransform,否则不会恢复。
        void addTransformer(ClassFileTransformer transformer);
    
        //删除一个类转换器
        boolean removeTransformer(ClassFileTransformer transformer);
    
        //在类加载之后,重新定义 Class。这个很重要,该方法是1.6 之后加入的,事实上,该方法是 update 了一个类。
        void retransformClasses(Class<?>... classes) throws UnmodifiableClassException;
    
        //获取一个对象的大小
        long getObjectSize(Object objectToSize);
        
        ........
            ........
    
    }
    
    
  2. premain方法会在大部分类的main方法之前执行(因为有一些系统类是需要先执行的). 因此 , 用户类的加载都可以被拦截的, 这样我们就可以做一些像重写类,或者监控等操作了

  3. 可以结合第三方的字节码编译工具 , 比如ASM , javaassist , cglib , bytebuddy 等等来改写class文件

2. 2. Agent-Class的agentmain方法

  1. 在Java SE 6的Instrumentation当中,提供了一个新的代理操作方法:agentmain,可以在main函数开始运行之后再运行。

  2. 优先运行带Instrumentation inst参数的方法

    // 采用attach机制,被代理的目标程序VM有可能很早之前已经启动,当然其所有类已经被加载完成,这个时候需要借助Instrumentation#retransformClasses(Class<?>... classes)让对应的类可以重新转换,从而激活重新转换的类执行ClassFileTransformer列表中的回调
    public static void agentmain (String agentArgs, Instrumentation inst)
    
    public static void agentmain (String agentArgs)
    
    
  3. 用Attach来实现此功能 : com.sun.tools.attach包下 有两个主要的类

VirtualMachine字面意义表示一个Java 虚拟机,也就是程序需要监控的目标虚拟机,提供了获取系统信息(比如获取内存dump、线程dump,类信息统计(比如已加载的类以及实例个数等), loadAgent,Attach 和 Detach (Attach 动作的相反行为,从 JVM 上面解除一个代理)等方法,可以实现的功能可以说非常之强大 。该类允许我们通过给attach方法传入一个jvm的pid(进程id),远程连接到jvm上 。

代理类注入操作只是它众多功能中的一个,通过loadAgent方法向jvm注册一个代理程序agent,在该agent的代理程序中会得到一个Instrumentation实例,该实例可以 在class加载前改变class的字节码,也可以在class加载后重新加载。在调用Instrumentation实例的方法时,这些方法会使用ClassFileTransformer接口中提供的方法进行处理。

VirtualMachineDescriptor则是一个描述虚拟机的容器类,配合VirtualMachine类完成各种功能。

  1. attach实现动态注入的原理:

通过VirtualMachine类的attach(pid)方法,便可以attach到一个运行中的java进程上,之后便可以通过loadAgent(agentJarPath)来将agent的jar包注入到对应的进程,然后对应的进程会调用agentmain方法。

因此可知, 这里会有两个进程之间的连接

既然是两个进程之间通信那肯定的建立起连接,VirtualMachine.attach动作类似TCP创建连接的三次握手,目的就是搭建attach通信的连接。而后面执行的操作,例如vm.loadAgent,其实就是向这个socket写入数据流,接收方target VM会针对不同的传入数据来做不同的处理。

com.sun.tools.attach包 不能在JDK中直接提示的话, 可以手动从JAVA_HOME/lib下找到

参考资料: https://blog.csdn.net/qq_31279701/article/details/120710892

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值