java agent使用全解析

2020-07-01 17:01 来源:易采站长站 作者:于丽 点击: 评论:

A-A+

原标题:java agent使用全解析

今天打算写一下 Java agent,一开始我对它的概念也比较陌生,后来在别人口中听到 字节码插桩,bTrace,Arthas后面才逐渐了解到Java还提供了这么个工具。

JVM启动前静态Instrument

Java agent 是什么?

Java agent是java命令的一个参数。参数 javaagent 可以用于指定一个 jar 包,并且对该 java 包有2个要求:

这个 jar 包的 MANIFEST.MF 文件必须指定 Premain-Class 项。 Premain-Class 指定的那个类必须实现 premain() 方法。

premain 方法,从字面上理解,就是运行在 main 函数之前的的类。当Java 虚拟机启动时,在执行 main 函数之前,JVM 会先运行-javaagent所指定 jar 包内 Premain-Class 这个类的 premain 方法 。

在命令行输入 java可以看到相应的参数,其中有 和 java agent相关的:

-agentlib:<libname>[=<选项>] 加载本机代理库 <libname>, 例如 -agentlib:hprof
 另请参阅 -agentlib:jdwp=help 和 -agentlib:hprof=help
-agentpath:<pathname>[=<选项>]
 按完整路径名加载本机代理库
-javaagent:<jarpath>[=<选项>]
 加载 Java 编程语言代理, 请参阅 java.lang.instrument

在上面-javaagent参数中提到了参阅java.lang.instrument,这是在rt.jar 中定义的一个包,该路径下有两个重要的类:

该包提供了一些工具帮助开发人员在 Java 程序运行时,动态修改系统中的 Class 类型。其中,使用该软件包的一个关键组件就是 Javaagent。从名字上看,似乎是个 Java 代理之类的,而实际上,他的功能更像是一个Class 类型的转换器,他可以在运行时接受重新外部请求,对Class类型进行修改。

从本质上讲,Java Agent 是一个遵循一组严格约定的常规 Java 类。 上面说到 javaagent命令要求指定的类中必须要有premain()方法,并且对premain方法的签名也有要求,签名必须满足以下两种格式:

public static void premain(String agentArgs, Instrumentation inst)
  
public static void premain(String agentArgs)

JVM 会优先加载 带 Instrumentation 签名的方法,加载成功忽略第二种,如果第一种没有,则加载第二种方法。这个逻辑在sun.instrument.InstrumentationImpl 类中:

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);

  boolean isRetransformClassesSupported();

  //在类加载之后,重新定义 Class。这个很重要,该方法是1.6 之后加入的,事实上,该方法是 update 了一个类。
  void retransformClasses(Class<?>... classes) throws UnmodifiableClassException;

  boolean isRedefineClassesSupported();

  
  void redefineClasses(ClassDefinition... definitions)
    throws ClassNotFoundException, UnmodifiableClassException;

  boolean isModifiableClass(Class<?> theClass);

  @SuppressWarnings("rawtypes")
  Class[] getAllLoadedClasses();

 
  @SuppressWarnings("rawtypes")
  Class[] getInitiatedClasses(ClassLoader loader);

  //获取一个对象的大小
  long getObjectSize(Object objectToSize);


  
  void appendToBootstrapClassLoaderSearch(JarFile jarfile);

  
  void appendToSystemClassLoaderSearch(JarFile jarfile);

  
  boolean isNativeMethodPrefixSupported();

  
  void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix);
}

【易采站长站编辑:秋军】