tipo tiempo texto tamaño obtener letra lbl etiquetas ejecucion cambiar boton asignar actualizar java playframework runtime classloader javassist

java - texto - Reemplazar el contenido de algunos métodos en tiempo de ejecución



lbl java (2)

Me gustaría reemplazar el contenido de algunos métodos en tiempo de ejecución.

Sé que puedo usar javassist para esto pero no funciona porque las clases que me gustaría mejorar ya están cargadas por el sistema classLoader .

¿Cómo puedo hacer para reemplazar el contenido de un método en tiempo de ejecución? ¿Debo intentar descargar la clase? Cómo puedo hacer eso ? Vi que era posible pero no pude averiguar cómo hacerlo.

Si es posible, me gustaría evitar usar una biblioteca externa para esto, me gustaría codificarla yo mismo.

Más información: - La clase que me gustaría mejorar está contenida en un marco (en un archivo jar) - Mi código es en realidad un complemento de este marco - El marco en el que se ejecuta mi complemento tiene su propio classLoader , pero este classLoader no lo hace carga sus propias clases (las delega en el cargador de clases del sistema): el marco que estoy usando es Play .

Gracias por tu ayuda !


Los ClassLoaders normales no admiten clases no definidas o modificadas una vez que se han definido. Por lo tanto, el complemento no puede modificar el comportamiento del marco a menos que ese marco proporcione enlaces para tales personalizaciones.

Puede crear un cargador de clases personalizado que oculta algunas clases de su cargador de clases principal y, en su lugar, las redefine, agregando cualquier instrumento que desee. Pero el marco se carga antes que el complemento, y resolverá las clases utilizando su propio cargador de clases. Por lo tanto, continuará utilizando las versiones no documentadas de las clases.

La única manera razonable de evitar esto (en lo que puedo pensar) es estar allí primero: si su código se inicia primero, puede presentar un cargador de clases que se utilizará para cargar el marco. Pero esto significa que tendrá que tener alguna forma de incluir su código en la cadena como una envoltura alrededor del marco. No estoy seguro de si esto es factible en su situación.

Actualización en respuesta al comentario:
Para crear un cargador de clases que identifique algunas clases, debe anular su método loadClass . Si su licencia permite el uso del código GPL, puede ver cómo OpenJDK hace esto en la implementación predeterminada. Solo debe remitirse al cargador de clases principal para aquellas clases que no desea ocultar.

Aún tendrás que modificar la clase después de ocultar la versión principal. Quizás el cargador de clases BCEL pueda ayudarte allí. O carga la clase desde un archivo jar que contiene una versión modificada. O algo como esto.


Puede hacerlo con Javaassist, así como con cualquier otra biblioteca de ingeniería de bytecode. La magia se encuentra en la API de Java Attach , que permite que los programas se conecten a JVMs en ejecución (y modifiquen las clases cargadas).

Se puede encontrar en el paquete com.sun.tools.attach y, como su nombre lo indica, es específico de la JVM de Oracle. No obstante, las herramientas de JDK como jstack y jmap utilizan para respaldar su función "adjuntar a JVM en ejecución", por lo que es seguro decir que está aquí para quedarse.

Los documentos en la API de Attach son bastante descriptivos, y esta publicación del blog de Oracle demuestra que se adjunta un agente en tiempo de ejecución. En general, se reduce a:

  • Haga un programa de retransformación de la manera "regular" -javaagent , con premain et al.
  • Renombrar como premain a agentmain
  • Cree un archivo JAR temporal que contenga sus clases de agente y que tenga un manifiesto que apunta Agent-Class de agente a su Agent-Class de agente (agente que contiene agente), y Can-Retransform-Classes establecido en true
  • Obtenga el PID de la JVM de destino (potencialmente el mismo proceso) y adjunte el archivo temporal al mismo

Afortunadamente, la API puede hacer esto sin mucho trabajo de su parte, aunque si está haciendo la generación JAR en tiempo de ejecución, puede ser un poco complicado empaquetar todas las clases que necesita su agente.

Esperaba incluir un agente de demostración que muestre adjuntar un generador de perfiles en el tiempo de ejecución, pero terminó siendo demasiado largo para publicar. Sin embargo, lo he puesto en un repo de Github .

Una advertencia de este enfoque es que hace que su programa dependa de las tools.jar que se tools.jar con los JDK y que no están presentes en los JRE. Puede tools.jar esto enviando tools.jar con (o extraído en) su aplicación, pero aún tendrá que proporcionar la biblioteca nativa attach requerida por la API de Attach con su aplicación. He incluido las bibliotecas para todas las plataformas que pude encontrar en el repositorio vinculado anteriormente, aunque también puede obtenerlas usted mismo.

Dependiendo de su caso de uso, esto puede o no ser ideal. ¡Pero ciertamente funciona!

Esto no está claro en la pregunta, pero si lo que desea hacer es completamente "hotswap" una clase en tiempo de ejecución con el suyo, no necesita usar ninguna biblioteca de manipulación de código de bytes. En su lugar, puede compilar su clase por separado ( asegurándose del mismo paquete, nombre de clase, etc. ) y simplemente devolver los bytes para su nueva clase cuando se llame a la transform en su clase objetivo.