una todos reflexion recorrer obtener objetos objeto los example ejemplo clase atributos java jvm aop cglib

todos - reflection java ejemplo



cómo retransformar una clase en tiempo de ejecución (1)

Respuesta corta

  • No itere a través de todas las clases cargadas desde Instrumentation. En su lugar, simplemente examine el nombre de clase que se transfirió al transformador y si coincide con su clase objetivo, luego, transfórmelo. De lo contrario, simplemente devuelva el classfileBuffer pasado sin modificaciones.
  • Realice las llamadas de configuración fuera del transformador (es decir, en su caso, haga lo siguiente con su agente), de modo que inicialice su transformador con el nombre de clase que desea transformar (este será el formato interno, en lugar de foo.bar). Snafu , buscarás combinar con foo / bar / Snafu . Luego agrega el transformador, llama a la retransforma y luego quita el transformador.
  • Para llamar a la retransformación, necesitará la clase real [pre-transform] que puede encontrar llamando a Class.forName (en el agente principal), o si es absolutamente necesario, puede encontrarla en Intrumentation.getAllLoadedClasses () como un último recurso. Si no se ha cargado la clase de destino, necesitará el cargador de clases para llamar a Class.forName (name, boolean, classloader) en cuyo caso puede pasar la URL a la class-path de la clase de destino en el agente principal string args.

Respuesta larga

Aquí hay algunas recomendaciones:

  1. Separar la operación que está llamando en 2 operaciones separadas:
    1. Instale el agente. Esto solo debe hacerse una vez.
    2. Transforma la clase objetivo [es]. Es posible que desee hacer esto n veces.
  2. Implementaría 1.2 al registrar un MBean JMX simple cuando instale el agente. Este MBean debe proporcionar una operación como public void transformClass(String className) . y debe inicializarse con una referencia a la instancia de Instrumentación adquirida del agente. La clase MBean, la interfaz y las clases de terceros requeridas deben incluirse en loaded.jar de su agente. También debe contener su clase ModifyMethodTest (que supongo que ya lo hace).
  3. Al mismo tiempo que instala su jar de agente, también instale el agente de administración desde $ JAVA_HOME / lib / management-agent.jar, que activará el agente de administración para que pueda invocar la operación de transformación en el MBean que está a punto de registrar.
  4. Parametrice su clase DemoTransformer para aceptar la forma interna del nombre de la clase que desea transformar. (es decir, si su nombre de clase binario es foo.bar.Snafu , la forma interna será foo / bar / Snafu . A medida que su instancia de DemoTransformer comience a recibir devoluciones de llamadas de transformación, ignore todos los nombres de clase que no coincidan con el nombre de clase de formulario interno que especificó. (es decir, simplemente devuelve el classfileBuffer sin modificar)
  5. Su operación Transformer MBean transformClass debería:
    1. Convierta el nombre de la clase pasada en forma interna.
    2. Crea un nuevo DemoTransformer, pasando el nombre de clase de formulario interno.
    3. Registre la instancia de DemoTransformer utilizando Instrumentation.addTransformer(theNewDemoTransformer, true) .
    4. Llame a Instrumentation.retransformClasses(ClassForName(className)) (con el nombre de clase binario pasado a la operación MBean). Cuando regrese esta llamada, tu clase se transformará.
    5. Retire el transformador con Intrumentation.removeTransformer(theNewDemoTransformer) .

La siguiente es una aproximación no probada de lo que quiero decir:

Transformador MBean

public interface TransformerServiceMBean { /** * Transforms the target class name * @param className The binary name of the target class */ public void transformClass(String className); }

Servicio de transformadores

public class TransformerService implements TransformerServiceMBean { /** The JVM''s instrumentation instance */ protected final Instrumentation instrumentation; /** * Creates a new TransformerService * @param instrumentation The JVM''s instrumentation instance */ public TransformerService(Instrumentation instrumentation) { this.instrumentation = instrumentation; } /** * {@inheritDoc} * @see com.heliosapm.shorthandexamples.TransformerServiceMBean#transformClass(java.lang.String) */ @Override public void transformClass(String className) { Class<?> targetClazz = null; ClassLoader targetClassLoader = null; // first see if we can locate the class through normal means try { targetClazz = Class.forName(className); targetClassLoader = targetClazz.getClassLoader(); transform(targetClazz, targetClassLoader); return; } catch (Exception ex) { /* Nope */ } // now try the hard/slow way for(Class<?> clazz: instrumentation.getAllLoadedClasses()) { if(clazz.getName().equals(className)) { targetClazz = clazz; targetClassLoader = targetClazz.getClassLoader(); transform(targetClazz, targetClassLoader); return; } } throw new RuntimeException("Failed to locate class [" + className + "]"); } /** * Registers a transformer and executes the transform * @param clazz The class to transform * @param classLoader The classloader the class was loaded from */ protected void transform(Class<?> clazz, ClassLoader classLoader) { DemoTransformer dt = new DemoTransformer(clazz.getName(), classLoader); instrumentation.addTransformer(dt, true); try { instrumentation.retransformClasses(clazz); } catch (Exception ex) { throw new RuntimeException("Failed to transform [" + clazz.getName() + "]", ex); } finally { instrumentation.removeTransformer(dt); } } }

El transformador de clase

public class DemoTransformer implements ClassFileTransformer { /** The internal form class name of the class to transform */ protected String className; /** The class loader of the class */ protected ClassLoader classLoader; /** * Creates a new DemoTransformer * @param className The binary class name of the class to transform * @param classLoader The class loader of the class */ public DemoTransformer(String className, ClassLoader classLoader) { this.className = className.replace(''.'', ''/''); this.classLoader = classLoader; } /** * {@inheritDoc} * @see java.lang.instrument.ClassFileTransformer#transform(java.lang.ClassLoader, java.lang.String, java.lang.Class, java.security.ProtectionDomain, byte[]) */ @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if(className.equals(this.className) && loader.equals(classLoader)) { return new ModifyMethodTest(classfileBuffer).modiySleepMethod(); } return classfileBuffer; } }

El agente

public class AgentMain { public static void agentmain (String agentArgs, Instrumentation inst) throws Exception { TransformerService ts = new TransformerService(inst); ObjectName on = new ObjectName("transformer:service=DemoTransformer"); // Could be a different MBeanServer. If so, pass a JMX Default Domain Name in agentArgs MBeanServer server = ManagementFactory.getPlatformMBeanServer(); server.registerMBean(ts, on); // Set this property so the installer knows we''re already here System.setProperty("demo.agent.installed", "true"); } }

El instalador del agente

public class AgentInstaller { /** * Installs the loader agent on the target JVM identified in <code>args[0]</code> * and then transforms all the classes identified in <code>args[1..n]</code>. * @param args The target JVM pid in [0] followed by the classnames to transform */ public static void main(String[] args) { String agentPath = "D://work//workspace//myjar//loaded.jar"; String vid = args[0]; VirtualMachine vm = VirtualMachine.attach(vid); // Check to see if transformer agent is installed if(!vm.getSystemProperties().contains("demo.agent.installed")) { vm.loadAgent(agentPath); // that property will be set now, // and the transformer MBean will be installed } // Check to see if connector is installed String connectorAddress = vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress", null); if(connectorAddress==null) { // It''s not, so install the management agent String javaHome = vm.getSystemProperties().getProperty("java.home"); File managementAgentJarFile = new File(javaHome + File.separator + "lib" + File.separator + "management-agent.jar"); vm.loadAgent(managementAgentJarFile.getAbsolutePath()); connectorAddress = vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress", null); // Now it''s installed } // Now connect and transform the classnames provided in the remaining args. JMXConnector connector = null; try { // This is the ObjectName of the MBean registered when loaded.jar was installed. ObjectName on = new ObjectName("transformer:service=DemoTransformer"); // Here we''re connecting to the target JVM through the management agent connector = JMXConnectorFactory.connect(new JMXServiceURL(connectorAddress)); MBeanServerConnection server = connector.getMBeanServerConnection(); for(int i = 1; i < args.length; i++) { String className = args[i]; // Call transformClass on the transformer MBean server.invoke(on, "transformClass", new Object[]{className}, new String[]{String.class.getName()}); } } catch (Exception ex) { ex.printStackTrace(System.err); } finally { if(connector!=null) try { connector.close(); } catch (Exception e) {} } // Done. (Hopefully) } }

================= ACTUALIZACIÓN =================

Hola Nick; Sí, esa es una de las limitaciones de los transformadores de clase actuales (es decir, Java 5-8). Para citar de la instrumentación javadoc :

"La retransformación puede cambiar los cuerpos de los métodos, el conjunto constante y los atributos. La retransformación no debe agregar, eliminar o renombrar campos o métodos, cambiar las firmas de los métodos o cambiar la herencia. Estas restricciones quizás se levanten en futuras versiones. no se verifican, verifican ni instalan hasta que se hayan aplicado las transformaciones, si los bytes resultantes son erróneos, este método emitirá una excepción ".

Como un aparte, esta misma limitación está documentada textualmente para redefinir las clases también.

Como tal, tienes 2 opciones:

  1. No agregue nuevos métodos. Esto es comúnmente muy limitante y descalifica el uso de patrones de AOP de código de bytes muy comunes, como el ajuste de métodos. Dependiendo de la biblioteca de manipulación de código de bytes que esté utilizando, es posible que pueda insertar toda la funcionalidad que desee en los métodos existentes. Algunas bibliotecas lo hacen más fácil que otros. O, debería decir, algunas bibliotecas lo harán más fácil que otros.

  2. Transforma la clase antes de que se cargue la clase. Utiliza el mismo patrón general del código que ya hemos discutido, excepto que no desencadena la transformación llamando a retransformClasses. En su lugar, registra ClassFileTransformer para realizar la transformación antes de que se cargue la clase y su clase objetivo se modificará cuando se cargue en la primera clase. En este caso, puede modificar la clase como desee, siempre que el producto final aún pueda validarse. Vencer la aplicación al golpe (es decir, conseguir que ClassFileTransformer se registre antes de que la aplicación cargue la clase) muy probablemente requerirá un comando como javaagent , aunque si tienes un control estricto del ciclo de vida de tu aplicación, es posible hacerlo de una forma más tradicional. código de capa de aplicación. Como dije, solo necesita asegurarse de registrar el transformador antes de que se cargue la clase objetivo.

Otra variación en el # 2 que puede usar es simular una nueva clase utilizando un nuevo cargador de clases. Si crea un nuevo cargador de clases aislado que no se delegará en la clase [cargada] existente, pero sí tiene acceso al código de bytes de clase objetivo [descargado], esencialmente está reproduciendo los requisitos del n. ° 2 anterior, ya que la JVM considera esto ser una nueva clase

================ ACTUALIZACIÓN ================

En sus últimos comentarios, siento que he perdido un poco la pista de dónde se encuentra. En cualquier caso, Oracle JDK 1.6 definitivamente admite la retransformación. No estoy muy familiarizado con ASM, pero el último error que publicó indica que la transformación de ASM de alguna manera modificó el esquema de clase que no está permitido, por lo que la retransformación falló.

Pensé que un ejemplo de trabajo agregaría más claridad. Las mismas clases que arriba (más una clase de prueba llamada Persona) están here . Hay un par de modificaciones / adiciones:

  • La operación de transformación en TransformerService ahora tiene 3 parámetros:
    1. El nombre de la clase binaria
    2. El nombre del método al instrumento
    3. Una expresión [regular] para coincidir con la firma del método. (si es nulo o está vacío, coincide con todas las firmas)
    4. La modificación real del bytecode se realiza usando Javassist en la clase ModifyMethodTest . Todo lo que hace la instrumentación es agregar un System.out.println que se ve así: -->Invoked method [com.heliosapm.shorthandexamples.Person.sayHello((I)V)]
  • El AgentInstaller (que tiene el Main de la demostración) simplemente instala automáticamente el agente y el servicio de transformación. (Más fácil para propósitos Dev / Demo, pero aún funcionará con otras JVM)
  • Una vez que el agente se autoinstala, el hilo principal crea una instancia de Person y simplemente realiza un bucle, llamando a los dos métodos sayHello de la Persona.

Antes de la transformación, ese resultado se ve de la siguiente manera.

Temp File:c:/temp/com.heliosapm.shorthandexamples.AgentMain8724970986698386534.jar Installing AgentMain... AgentMain Installed Agent Loaded Instrumentation Deployed:true Hello [0] Hello [0] Hello [1] Hello [-1] Hello [2] Hello [-2]

La persona tiene 2 métodos sayHello , uno toma un int , el otro toma un String . (The String one solo imprime el negativo del índice de bucle).

Una vez que inicio el AgentInstaller, el agente está instalado y la persona está siendo invocada en un bucle, me conecto a la JVM usando JConsole:

Navego hasta el MBean de TransformerService e invoco la operación transformClass . Proporciono el nombre [binario] de clase totalmente calificado, el nombre del método para el instrumento y una expresión de expresiones regulares (I) V que solo coincide con el método sayHello que toma un int como argumento. (O podría suministrar . * , O nada para que coincida con todas las sobrecargas). Ejecuto la operación.

Ahora cuando vuelvo a la JVM en ejecución y examino la salida:

Examining class [com/heliosapm/shorthandexamples/Person] Instrumenting class [com/heliosapm/shorthandexamples/Person] [ModifyMethodTest] Adding [System.out.println("/n/t-->Invoked method [com.heliosapm.shorthandexamples.Person.sayHello((I)V)]");] [ModifyMethodTest] Intrumented [1] methods -->Invoked method [com.heliosapm.shorthandexamples.Person.sayHello((I)V)] Hello [108] Hello [-108] -->Invoked method [com.heliosapm.shorthandexamples.Person.sayHello((I)V)] Hello [109] Hello [-109]

Hecho. Método instrumentado.

Tenga en cuenta que la razón por la que se permite la retransformación es porque la modificación del código de bytes de Javassist no hizo más cambios que inyectar código en un método existente.

Tener sentido ?

Estoy probando modificar la clase que ya se cargó en un jvm. La solución que encontré es:

  • Primero, adjunte un agente a un jvm especificado por pid. (por ejemplo, 8191) (Códigos: AttachTest)
  • 2nd Encuentra la clase que deseas modificar de aquellas que ya han sido cargadas en el jvm (ej. 8191).
  • 3º Añadir transformador usando Instrument (Códigos: AgentMain)
  • 4º Modificar la clase (por ejemplo, Persona) en el método de transform (Códigos: DemoTransformer)
  • 5º Retransformar la clase utilizando retransformClasses

Funciona bien desde el primer paso hasta el quinto paso, pero hay problemas en retransformClasses . Se llamó a transform nuevo que contiene códigos para modificar la clase. Y modifica otras clases que nunca quiero modificar. Creo que el problema puede addTransformer durante addTransformer o retransformClasses . Pero todavía estoy confundido. Bueno, ¿cómo retransformar una clase? ¿Algunas ideas? Gracias

public class AttachTest { public static void main(String[] args) throws AttachNotSupportedException, IOException, AgentLoadException, AgentInitializationException { String agentPath = "D://work//workspace//myjar//loaded.jar"; String vid = args[0]; VirtualMachine vm = VirtualMachine.attach(vid); vm.loadAgent(agentPath); } }

//Agente

public class AgentMain { public static void agentmain (String agentArgs, Instrumentation inst) throws ClassNotFoundException, UnmodifiableClassException, InterruptedException { Class<?> [] allLoadedClasses = inst.getAllLoadedClasses(); String tmpString = null; for (int i = 0; i<allLoadedClasses.length; i++) { tmpString = allLoadedClasses[i].getName(); if (0 != tmpString.length()) { if (-1 != tmpString.lastIndexOf(".")) { tmpString = tmpString.substring(tmpString.lastIndexOf(".")+1,tmpString.length()); } if (tmpString.equals("Person")) { inst.addTransformer(new DemoTransformer(), true); inst.retransformClasses(allLoadedClasses[i]); } } } } }

|

public class DemoTransformer implements ClassFileTransformer { @Override public byte[] transform (ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { ModifyMethodTest tm = new ModifyMethodTest(classfileBuffer); byte[] byteArray = null; try { byteArray = tm.modiySleepMethod(); } catch (Exception e) { e.printStackTrace(); } return byteArray; } }

SALIDAS: EL PROGRAMA DE ADJUNTOS

javax.management.RuntimeMBeanException: java.lang.RuntimeException: Failed to transform [Person] at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.rethrow(DefaultMBeanServerInterceptor.java:856) at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.rethrowMaybeMBeanException(DefaultMBeanServerInterceptor.java:869) at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:838) at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:761) at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1427) at javax.management.remote.rmi.RMIConnectionImpl.access$200(RMIConnectionImpl.java:72) at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1265) at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1360) at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:788) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:305) at sun.rmi.transport.Transport$1.run(Transport.java:159) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.Transport.serviceCall(Transport.java:155) at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:619) at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:255) at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:233) at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:142) at com.sun.jmx.remote.internal.PRef.invoke(Unknown Source) at javax.management.remote.rmi.RMIConnectionImpl_Stub.invoke(Unknown Source) at javax.management.remote.rmi.RMIConnector$RemoteMBeanServerConnection.invoke(RMIConnector.java:993) at AttachStackOverflow.main(AttachStackOverflow.java:57) Caused by: java.lang.RuntimeException: Failed to transform [Person] at loaded3.TransformerService.transform(TransformerService.java:75) at loaded3.TransformerService.transformClass(TransformerService.java:38) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com.sun.jmx.mbeanserver.StandardMBeanIntrospector.invokeM2(StandardMBeanIntrospector.java:93) at com.sun.jmx.mbeanserver.StandardMBeanIntrospector.invokeM2(StandardMBeanIntrospector.java:27) at com.sun.jmx.mbeanserver.MBeanIntrospector.invokeM(MBeanIntrospector.java:208) at com.sun.jmx.mbeanserver.PerInterface.invoke(PerInterface.java:120) at com.sun.jmx.mbeanserver.MBeanSupport.invoke(MBeanSupport.java:262) at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:836) at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:761) at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1427) at javax.management.remote.rmi.RMIConnectionImpl.access$200(RMIConnectionImpl.java:72) at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1265) at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1360) at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:788) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:305) at sun.rmi.transport.Transport$1.run(Transport.java:159) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.Transport.serviceCall(Transport.java:155) at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:619) Caused by: java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the schema (add/remove fields) at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method) at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:124) at loaded3.TransformerService.transform(TransformerService.java:72) ... 31 more

SALIDAS: PROGRAMA OBJETIVO

print Call sayHello() print Hello World! Supported Redefine Supported Retransform Call transform() in TransformerService Add transformer support redefine. return TRUE support retransforme. return TRUE IsModifiable class "class Person". return TRUE Retransform classes Number of times to Call transform() in DemoTransformer:1 ####ASM CODE#### consturct ModifyMethodTest Call modifySleepMethod new classreader new classwriter construct ModifyClassAdapter sayHello consturct Modifymethod [arg1] = java/io/PrintStream [arg2] = println #5 [arg1] = java/io/PrintStream [arg2] = println #13 [arg1] = java/util/concurrent/TimeUnit [arg2] = sleep #22 [arg1] = java/io/PrintStream [arg2] = println #30 sayHello2 consturct Modifymethod [arg1] = java/io/PrintStream [arg2] = println #5 [arg1] = java/io/PrintStream [arg2] = println #13 <init> consturct Modifymethod [arg1] = java/lang/Object [arg2] = <init> #1 main consturct Modifymethod [arg1] = Person [arg2] = <init> #4 [arg1] = Person [arg2] = sayHello #9 [arg1] = Person [arg2] = sayHello2 #13 [arg1] = java/lang/InterruptedException [arg2] = printStackTrace #21 getName consturct Modifymethod setName consturct Modifymethod Call visitend Finished to call modifymethodtest ####End of ASM CODE Remove transformer Call transform() in TransformerService Add transformer support redefine. return TRUE support retransforme. return TRUE IsModifiable class "class Person". return TRUE Retransform classes Number of times to Call transform() in DemoTransformer:2 ####ASM CODE#### consturct ModifyMethodTest Call modifySleepMethod new classreader new classwriter construct ModifyClassAdapter sayHello consturct Modifymethod [arg1] = java/io/PrintStream [arg2] = println #5 [arg1] = java/io/PrintStream [arg2] = println #13 [arg1] = java/util/concurrent/TimeUnit [arg2] = sleep #22 [arg1] = java/io/PrintStream [arg2] = println #30 sayHello2 consturct Modifymethod [arg1] = java/io/PrintStream [arg2] = println #5 [arg1] = java/io/PrintStream [arg2] = println #13 <init> consturct Modifymethod [arg1] = java/lang/Object [arg2] = <init> #1 main consturct Modifymethod [arg1] = Person [arg2] = <init> #4 [arg1] = Person [arg2] = sayHello #9 [arg1] = Person [arg2] = sayHello2 #13 [arg1] = java/lang/InterruptedException [arg2] = printStackTrace #21 getName consturct Modifymethod setName consturct Modifymethod Call visitend Finished to call modifymethodtest ####End of ASM CODE Remove transformer print in sayHello() print Call sayHello2() print Hello World!2