Java- technology zone -javaagent (instrumentation, attach)

  

Transfer: https: //blog.csdn.net/qinhaotong/article/details/100693414

java agent

What Javaagent that?

  javaAgent run before class loader to load classes dynamically modify the class to make.

  Add run java command execution parameter specifies -javaagent packaged agent i.e. the jar can can define multiple agent, in the given order

java -javaagent:agent1.jar -javaagent:agent2.jar -jar MyProgram.jar

  Bytecode instrumentation, bTrace, Arthas are achieved in this way.

Method class javaAgent

  Create a class which defines agent method

public static void premain(String agentArgs, Instrumentation inst)

public static void premain(String agentArgs)

  JVM will give priority to the loading method with the signature of Instrumentation, loaded successfully ignored the second, if not the first, the second method is loaded. Instrumentation is an important parameter.

Instrumentation interface definition method

the Instrumentation interface {public

  // converter to increase a Class file, the data converter for changing Class binary stream, the parameter set whether to allow canRetransform reconverted.
  void addTransformer (ClassFileTransformer transformer, boolean canRetransform   );

  // before class loading, Class document redefined, ClassDefinition said the new definition of a class, if after the class is loaded, the method requires the use of retransformClasses

        redefine.   

       After addTransformer configuration method, the subsequent load category will be intercepted Transformer. For the class has been loaded, it can be re-triggered execution retransformClasses

  The Transformer interception. After loading the bytecode class is modified, unless again retransform, it would not be restored.

       void addTransformer(ClassFileTransformer transformer);

       // delete a class converter
       boolean removeTransformer (ClassFileTransformer transformer);

  boolean isRetransformClassesSupported();

  // After loading the class, redefine Class. This is very important, which is added after 1.6, in fact, the method is a class 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);

  // Get the size of an object
  long getObjectSize (Object objectToSize);

  void appendToBootstrapClassLoaderSearch(JarFile jarfile);

  void appendToSystemClassLoaderSearch(JarFile jarfile);

  boolean isNativeMethodPrefixSupported();

  void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix);
}

Java Agent - Hello World

  Use javaagent requires several steps:

  Define a MANIFEST.MF file must contain Premain-Class option, also typically added Can-Redefine-Classes and Can-Retransform-Classes option.

  Premain-Class Creating a specified class, class contains premain process, process logic is determined by the user.

  The premain classes and MANIFEST.MF file labeled jar package.

  Use parameters -javaagent: jar package Path To start the agent.

  After performing the above steps, JVM will first perform premain method, most of the class will be loaded by this method, note: that most, not all. Of course, the main omission is the class system, because a lot of class system performed prior to agent, and the user class loader will certainly be intercepted. In other words, this method is the most active class of interceptor loaded before the main method to start, since it can be loaded intercept class, then we can do such an operation to rewrite the class, in conjunction with third-party bytecode compiler tools, such as ASM, javassist, cglib etc. to rewrite the implementation class.

Creating javaAgent class

public class HelloAgent {
  public static void premain(String agentArgs, Instrumentation inst) {
    System.out.println("agentArgs : " + agentArgs);
    inst.addTransformer(new DefineTransformer(), true);
  }

  static class DefineTransformer implements ClassFileTransformer {

    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain     

      protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
      System.out.println("premain load Class:" + className);
      return classfileBuffer;
    }
  }
}

Creating MANIFEST.MF

Manifest-Version: 1.0
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Premain-Class: com.tttiger.HelloAgent

      Note the last line needs empty lines. Add in the idea of ​​the article, do not accept tips do not control, will automatically give you idea MANIFEST.MF might create a conflict, so that idea created, created and then to modify the configuration.

Mount agent running

  Create a new class or jar, add the command -javaagent at run time: e: /xxx.jar complete package of javaagentjar package path.

  Packaged using maven

  Add maven plugin specified javaagent class, maven automatically manifest configuration, do not have to go to the recommended configuration

<plugin>

  <groupId>org.apache.maven.plugins</groupId>

  <artifactId>maven-jar-plugin</artifactId>

  <version>3.1.0</version>

  <configuration>

    <archive>

    <! - automatically add META-INF / MANIFEST.MF ->

    <manifest>

      <addClasspath>true</addClasspath>

    </manifest>

    <manifestEntries>

      <Premain-Class>com.rickiyang.learn.PreMainTraceAgent</Premain-Class>

      <Agent-Class>com.rickiyang.learn.PreMainTraceAgent</Agent-Class>

      <Can-Redefine-Classes>true</Can-Redefine-Classes>

      <Can-Retransform-Classes>true</Can-Retransform-Classes>

    </manifestEntries>

    </archive>

  </configuration>

</plugin>


MANIFEST.MF Parameter Description

  Premain-Class: class method comprising premain (full path name of the class) method before main operation Agent

  Agent-Class: class method comprising agentmain (full path name and the like) another agent class may be modified after the start of main structure

  Boot-Class-Path: Set the bootstrap class loader path list search. After the failure to find class-specific mechanisms of the platform, the bootstrap class loader will search these paths. The search path they are listed. Path list are separated by one or more spaces. Path uses a hierarchical URI path component syntax. If the path begins with a slash character ( "/"), for the absolute path, or a relative path. Relative path is resolved against the absolute path to the agent JAR file. Ignore malformed path and the path does not exist. If the agent is started after VM at a time to start, it does not represent a JAR file path is ignored. (Optional) To put it plainly is dependent agent class

  Can-Redefine-Classes: true indicates this agent can redefine the desired class, the default value is false (optional)

  Can-Retransform-Classes: true indicates this agent can be reconverted to the desired category, a default value is false (optional)

  Can-Set-Native-Method-Prefix: true indicates this agent can set the desired native method prefix, the default value is false (optional)

Managent

  In Instrumentation Java SE 6 and gives them a new proxy method of operation: agentmain, it can run again after the main function starts running.
  Premain with the same function, developers can write a Java class containing agentmain function:

  // using attach mechanism, the proxy target VM program has been started a long time ago there may, of course, that all classes have been loaded,

// this time need the help of Instrumentation # retransformClasses (Class <?> ... classes)

  // make corresponding class can be re-converted to activate the implementation of the re-converted class ClassFileTransformer callback list

public static void agentmain (String agentArgs, Instrumentation inst)

public static void agentmain (String agentArgs)

  agentMain mainly used for monitoring of java program, call the java process, you will have written agentMain injection target to complete the monitoring program modifications.

Creating agentmain

public class TestMainAgent {

  public static void agentmain(String agentArgs, Instrumentation instrumentation) {

    System.out.println("loadagent after main run.args=" + agentArgs);

    Class<?>[] classes = instrumentation.getAllLoadedClasses();

    for (Class<?> cls : classes){
      System.out.println(cls.getName());
    }

    System.out.println("agent run completely.");
  }

  static class DefineTransformer implements ClassFileTransformer {

    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,

      ProtectionDomain protectionDomain,

      byte[] classfileBuffer) throws IllegalClassFormatException {

      System.out.println("premain load Class:" + className);
      return classfileBuffer;
    }
  }
}

 

Add maven plugin package

  • <build>
  •   <plugins>
  •   <plugin>
  •     <groupId>org.apache.maven.plugins</groupId>
  •     <artifactId>maven-jar-plugin</artifactId>
  •     <version>3.1.0</version>
  •     <configuration>
  •       <archive>
  •       <! - automatically add META-INF / MANIFEST.MF ->
  •       <manifest>
  •         <addClasspath>true</addClasspath>
  •       </manifest>
  •     <manifestEntries>
  •       <Agent-Class>com.tttiger.TestMainAgent</Agent-Class>
  •       <Can-Redefine-Classes>true</Can-Redefine-Classes>
  •       <Can-Retransform-Classes>true</Can-Retransform-Classes>
  •     </manifestEntries>
  •     </archive>
  •   </configuration>
  • </plugin>
  • </plugins>
  • </build>

AgentMain test instrumentation to other classes

  Also enabled a jvm process, find jvm process needs to attach and let it load agentMain, then agentMain will be loaded into each other jvm execution. arthas is to use this way attach into the jvm process, and then open a socket to monitor the target jvm.

public static void main(String[] args) throws IOException, AttachNotSupportedException,

  AgentLoadException, AgentInitializationException,InterruptedException {

  // get the current system the virtual machine running all
  System.out.println ( "Start running the JVM");
  List <VirtualMachineDescriptor> = VirtualMachine.list List ();
  for (VMD VirtualMachineDescriptor: List) {
    // If the virtual machine xxx is the name of the virtual machine to the target virtual machine, the virtual machine to obtain pid
    // load agent.jar then sent to the virtual machine
    System.out.println (vmd.displayName ());
    IF (vmd.displayName ( ) .endsWith ( "com.tttiger.TestJVM")) {
      System.out.println (vmd.id ());
      VirtualMachine VirtualMachine = VirtualMachine.attach (vmd.id ());  
      virtualMachine.loadAgent ( "E: / Test SNAPSHOT.jar-1.0--agentMain ");
      virtualMachine.detach ();
      System.out.println (" the attach ");
    }
  }
  the Thread.sleep (10000L);
}
  

  VirtualMachine literally represents a Java virtual machine, which is the need to monitor the program's target virtual machine, providing obtain system information (such as access memory dump, thread dump, statistics class and class information such as the number of instances (such as loaded), loadAgent , Attach and Detach (opposite behavior Attach action, the lifting of a proxy from above JVM) and other methods, functions can be achieved can be said is very powerful. This class allows us to attach a jvm method of passing pid (process id), remote connection to the jvm.

  A proxy class that simply injecting operation of many functions, registered by loadAgent method jvm an agent to agent, the agent in the agent will be in a Instrumentation instance of class byte code can be changed before loading class, It can also be reloaded after the class is loaded. In the method call Instrumentation instance, these methods use the interface provided by ClassFileTransformer process.

  VirtualMachineDescriptor is a description of a virtual machine container class, with the class perform various functions VirtualMachine

  (Pid) method, you can attach through attach VirtualMachine class onto a running java process, after which they can be the agent of the jar package injected into the corresponding process through loadAgent (agentJarPath), then the corresponding process calls agentmain method .

Instrumentation limitations

 

 

  In most cases, we are using functions that use Instrumentation byte code instrumentation, or in general terms, that is to redefine the class (Class Redefine) function, but has the following limitations:

  After premain and agentmain two ways to modify the timing of the bytecode class files are loaded, that is to say with Class must be of the type parameter, you can not be bytecode files and custom redefine a class name would not otherwise exist class.

  Modified bytecode class called class switching (Class Transform), based in fact ultimately converted back to class redefinition Instrumentation # redefineClasses () method , this method has the following limitations:

  1 parent class and the new class must be the same old;
  the number of classes and interfaces 2 new and old class have achieved the same, and the same interface;
  3 old class and the new class access operator must be consistent. The number of new and old classes and class fields and field names to be consistent;
  add or delete old 4 new classes and class methods must be private static / final modification;
  5 can modify the method body.

  In addition to the above way, if you want to redefine a class, it can be considered based on the class loader isolation of ways: create a new custom class loader to define a new class to the new bytecode, but there are only through reflection to invoke limitations of the new class.

 

Guess you like

Origin www.cnblogs.com/liboware/p/12391510.html