首页 > 编程语言 >Java Agent有什么作用?

Java Agent有什么作用?

时间:2023-12-08 14:15:35浏览次数:25  
标签:java 字节 代码 Agent Java public 作用

 

Java Agent概述

Java Agent是一种特殊类型的软件组件,它允许在Java虚拟机(JVM)运行时修改应用程序的字节码。这种技术通常用于性能监控、日志记录、系统调试等。Java Agent主要分为两类:

1. 启动时加载的Agent(Pre-Main Agent)

这种类型的Agent在应用程序的主方法(main)执行之前加载。它们通常用于在应用程序启动时进行一些预处理,例如初始化日志框架、植入一些监控代码等。

如何实现:

  • 在Agent代码中,你需要实现一个带有特定签名的premain方法。这个方法是由JVM在启动时自动调用的。
  • premain方法的签名必须是:public static void premain(String agentArgs, Instrumentation inst)
  • agentArgs是传递给Agent的任何参数。
  • inst是一个java.lang.instrument.Instrumentation实例,它提供了操作字节码的接口。

代码示例:

  java 复制代码
import java.lang.instrument.Instrumentation;

public class MyAgent {
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("Executing premain.........");
        // 这里可以进行字节码操纵或其他初始化任务
    }
}

如何使用:

  • 将上述Agent编译成JAR文件,并在JAR的MANIFEST.MF文件中指定Premain-Class属性。
  • 使用-javaagent标志启动你的Java应用程序,指定Agent JAR文件。

例如,在MANIFEST.MF中:

  makefile 复制代码
Premain-Class: MyAgent

启动Java应用时的命令行:

  bash 复制代码
java -javaagent:path/to/agent.jar -jar myapp.jar

2. 运行时加载的Agent(Agent-On-Load)

这种Agent可以在JVM运行时动态加载和附加,通常用于对正在运行的应用程序进行监控和修改。

如何实现:

  • 在Agent代码中,你需要实现一个带有特定签名的agentmain方法。这个方法在Agent被动态加载到JVM时由JVM调用。
  • agentmain方法的签名必须是:public static void agentmain(String agentArgs, Instrumentation inst)

代码示例:

  java 复制代码
import java.lang.instrument.Instrumentation;

public class MyRuntimeAgent {
    public static void agentmain(String agentArgs, Instrumentation inst) {
        System.out.println("Executing agentmain.........");
        // 这里可以进行字节码操纵或其他任务
    }
}

如何使用:

  • 编译Agent代码并打包成JAR文件,指定Agent-Class属性在MANIFEST.MF文件。
  • 使用特定的工具(如attach API)在运行时将Agent加载到目标JVM。

MANIFEST.MF中:

  makefile 复制代码
Agent-Class: MyRuntimeAgent

动态加载Agent(使用attach API的示例):

  java 复制代码
import com.sun.tools.attach.VirtualMachine;

public class AttachExample {
    public static void main(String[] args) throws Exception {
        VirtualMachine vm = VirtualMachine.attach("targetJvmPid");
        vm.loadAgent("path/to/agent.jar", "optionalAgentArgs");
        vm.detach();
    }
}

在上述代码中,targetJvmPid是你想要附加的JVM的进程ID。

path/to/agent.jar : 这是Java Agent的JAR文件的路径。在实际使用中,你需要将其替换为实际的Agent JAR文件的路径。例如,如果你的Agent JAR文件名为myagent.jar并且位于当前目录下,那么这部分应该替换为myagent.jar

optionalAgentArgs:这是传递给Agent的可选参数。这个字符串将作为参数传递给Agent的agentmain方法。如果你的Agent不需要任何参数,这部分可以为空字符串或者完全省略。

这些示例提供了如何实现和使用这两种类型的Java Agent的基本方法。实际应用中,你可能会根据需求在Agent中进行更复杂的操作,例如使用ASM或Javassist库进行字节码操作。

使用ASM进行字节码操作

在一个Java Agent中使用ASM进行字节码操作通常涉及以下步骤:

  1. 实现一个ClassFileTransformer:这个类将用来修改类的字节码。
  2. 注册这个Transformer到Instrumentation对象:在premainagentmain方法中。

代码示例

  java 复制代码
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class MyAgent {
    public static void premain(String agentArgs, Instrumentation inst) {
        inst.addTransformer(new MyClassFileTransformer());
    }

    static class MyClassFileTransformer implements ClassFileTransformer {
        @Override
        public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
            // 使用ASM API修改类字节码
            // 返回新的字节码数组,或者如果没有修改,则返回null
            return null;
        }
    }
}

在上面的代码中,你需要使用ASM的API来修改classfileBuffer(类的字节码数组)。

使用Javassist进行字节码操作

使用Javassist进行字节码操作通常更加简单,因为它允许以接近Java源代码的形式修改类。

代码示例

  java 复制代码
import java.lang.instrument.ClassFileTransformer;
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 agentArgs, Instrumentation inst) {
        inst.addTransformer(new MyClassFileTransformer());
    }

    static class MyClassFileTransformer implements ClassFileTransformer {
        @Override
        public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
            if (className.equals("my/target/ClassName")) {
                try {
                    ClassPool cp = ClassPool.getDefault();
                    CtClass cc = cp.get("my.target.ClassName");
                    CtMethod m = cc.getDeclaredMethod("myMethod");
                    m.insertBefore("{ System.out.println(\"Method called\"); }");
                    byte[] byteCode = cc.toBytecode();
                    cc.detach();
                    return byteCode;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    }
}

在上面的示例中,我们修改了名为my.target.ClassName的类,并在其myMethod方法开始前插入了一行打印语句。Javassist使得修改字节码更接近于编写普通的Java代码。

总结

Java Agent提供了一种强大的机制来在运行时修改和增强Java应用程序。ASM和Javassist是两个常用的库,用于实现Java Agent中的字节码操作。ASM提供了更低层次的控制,而Javassist则提供了更简单、更直观的方式来处理字节码。选择使用哪个库取决于具体的需求和对字节码操作的熟悉程度。通过这些工具,可以实现诸如性能监控、日志记录、动态代码修改等高级功能。


https://juejin.cn/post/7309775437942669322

 

标签:java,字节,代码,Agent,Java,public,作用
From: https://www.cnblogs.com/softidea/p/17887023.html

相关文章

  • java实例化的五种方式
    1.创建新对象五种方式1.用new语句创建对象,这是最常见的创建对象的方法。2.使用Class类的newInstance方法3.使用Constructor类的newInstance方法运用反射手段,调用java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。如:Objectobj=Class.forName("java......
  • Java synchronized
    synchronized是Java中最基本的线程同步机制之一,通过在方法或代码块上添加synchronized关键字,可以确保只有一个线程可以访问该方法或代码块。它是Java中实现线程安全的重要机制之一。synchronized关键字的使用方式有两种:1、修饰实例方法当synchronized关键字修饰一个实例方法时,......
  • Java synchronized 、ReentrantLock和Semaphore
    synchronized在Java中,使用synchronized关键字可以实现对代码块或方法的同步访问,以确保多个线程不会同时访问共享资源。当一个线程获取了对象的锁(即进入了synchronized代码块),其他线程如果也希望获取该对象的锁,它们将被阻塞,直到拥有锁的线程执行完毕并释放锁。因此,在某种意义上,使......
  • 已解决:若依更换日志EasyExcel框架导出报错 java.lang.NoClassDefFoundError: org/apac
    先描述一下当时的场景回忆看到出错了,我就想可能是哪个路径写错了,或者导依赖名字写对,或者说是多了少了标点符号什么的。然而,还是想简单了,检查重启后发现问题并没有解决。于是就把所有我改过的地方检查了一遍,检查和这个依赖相关的代码。发现还是没啥关系后来去找百度、百度给的......
  • 外贸CRM是什么?外贸CRM有什么作用?
     外贸行业对客户管理的追求日益提高,为了应对客户需求的变化和多元性,外贸企业需要借助CRM管理系统实现智能管理。下面,我们将详细探讨外贸CRM的概念、特点和具体应用。什么是外贸CRM?外贸CRM是指针对外贸行业的客户关系管理系统,它可以帮助外贸企业管理客户信息、跟进客户订单、......
  • kotlin协程和java线程有啥区别
    Kotlin协程相对于Java线程有一些优势,尤其在处理异步和并发任务时,提供了更加简洁、可读性更高的代码。以下是一些Kotlin协程相比于Java线程的优势:轻量级:协程是轻量级的,可以更高效地创建和销毁,不需要像线程那样消耗大量的系统资源。更好的可读性:使用协程可以避免......
  • 2023最新中级难度JavaScript面试题,包含答案。刷题必备!记录一下。
    好记性不如烂笔头内容来自面试宝典-中级难度JavaScript面试题合集问:如何实现在JavaScript中的操作settimeout/setinterval?在JavaScript中,setTimeout()和setInterval()是两个非常重要的函数,它们分别用于设置一次性延时执行的函数和周期性重复执行的函数。setTi......
  • 2023最新高级难度JavaScript面试题,包含答案。刷题必备!记录一下。
    好记性不如烂笔头内容来自面试宝典-高级难度JavaScript面试题合集问:请问你如何使用装饰器模式?装饰器模式是一种设计模式,它允许我们在不修改原有类的基础上,动态地添加新的功能或者行为。装饰器模式通过创建一个新的对象来包装原始对象,并提供与原始对象相同的方法接口,但是......
  • Java语言基础知识全总结
    一.Java的优点1.      跨平台性。一次编译,到处运行。Java编译器会将Java代码编译成能在JVM上直接运行的字节码文件,C++会将源代码编译成可执行的二进制代码文件,所以C++执行速度快2.      纯面向对象。Java所有的代码都必须在类中书写。C++兼具面向对象和面向过程的特......
  • Java-指令重排
    Java-指令重排指令重排(InstructionReordering)是指编译器或者处理器在不改变程序语义的前提下,重新安排指令的执行顺序,以优化性能或者满足硬件的执行特性。在多线程环境中,指令重排可能导致线程安全性问题,因为重排序可能改变原本按照程序顺序应该执行的操作次序。单线程-可提高程......