Cuando se trata de inyectar una clase que está en el java.lang
espacio de nombres a través java.lang.instrument.Instrumentation#appendToBootstrapClassLoaderSearch
de un OpenJDK 11, no pasa nada y se lanza ningún error. Al colocar la clase de inyectar en un paquete diferente, funciona como se esperaba.
JarFile jar = new JarFile(new File("file/to/bootstrap.jar));
instrumentation.appendToBootstrapClassLoaderSearch(jar);
// throws ClassNotFoundException java/lang/Dispatcher
Class.forName("java.lang.Dispatcher", false, null);
bootstrap.jar
└─ java/lang/Dispatcher.class
La razón por la que quiero hacer esto es para superar los problemas con algunos contenedores OSGi. Por lo general restringen la delegación en el cargador de clases de arranque a solamente ciertos paquetes. Por defecto siempre que, obviamente, incluye java.*
que es por eso que quiero poner mi Dispatcher
clase hay. Soy consciente de org.osgi.framework.bootdelegation
que esa propiedad solamente se lee durante la inicialización. Eso significa que cuando se conecta un agente en tiempo de ejecución, ya es demasiado tarde para reemplazar este valor.
Una alternativa sería la de todos los conocidos instrumentos cargadores de clases OSGi y para la lista blanca las clases de agentes. Pero hacer que para cada marco y la prueba de que para cada versión parece menos factible.
¿Cómo puedo inyectar una clase personalizada como java.lang.Dispatcher
en el cargador de clases de arranque? ¿Hay otros patrones o las mejores prácticas para evitar problemas bootdelegation OSGi?
Para proporcionar un poco más de contexto:
Mi idea es inyectar sólo ésta Dispatcher
clase en el cargador de clases de arranque. El despachador básicamente sólo tiene un mapa estático. El resto de clases del agente sería cargado por un URLClassLoader dedicado que es un hijo del cargador de clases de arranque. El agente sería luego registrar MethodHandle
s en el Mapa del despachador para que el código de bytes inyectado puede ponerme en contacto con los MethodHandles que permiten el acceso del agente clases cargadas en el cargador de clases de agente.
Es posible mediante el uso de la API inseguro. Desde Java 9, la implementación del cargador de clases de arranque ha cambiado sólo a comprobar un jmod designado para un paquete conocido, pero la ruta de búsqueda de arranque ya no está marcada.
Java 11 también eliminó el sun.misc.Unsafe#defineClass
método, pero el mismo método todavía está disponible en jdk.internal.misc.Unsafe
.
Usted tiene que abrir el módulo de la clase que es interno. Usted puede hacer ya sea por lo que mediante el uso de sun.misc.Unsafe
lo que le permite escribir un valor de campo ( accessible
) sin controles de accesibilidad o mediante el uso de la API oficial de Instrumentación.
Si está utilizando Byte de amigos, echar un vistazo a las ClassInjector
implementaciones que ofrecen implementaciones para todos los enfoques.
Hay un billete abierto para adressing la necesidad de agentes de Java para inyectar ayudante clases , sino hasta que se resuelva, esto es una solución común.