Tengo una aplicación Java ee bastante grande con un gran classpath que hace mucho procesamiento xml. Actualmente estoy tratando de acelerar algunas de mis funciones y localizar rutas de código lentas a través de perfiladores de muestreo.
Una cosa que noté es que especialmente las partes de nuestro código en las que tenemos llamadas TransformerFactory.newInstance(...)son extremadamente lentas. Seguí esto hasta el FactoryFindermétodo, findServiceProvidersiempre creando una nueva ServiceLoaderinstancia. En ServiceLoader javadoc encontré la siguiente nota sobre el almacenamiento en caché:
Los proveedores se ubican y crean instancias de manera perezosa, es decir, bajo demanda. Un cargador de servicios mantiene un caché de los proveedores que se han cargado hasta ahora. Cada invocación del método iterador devuelve un iterador que primero produce todos los elementos de la memoria caché, en orden de creación de instancias, y luego localiza e instancia perezosamente a los proveedores restantes, agregando cada uno a la memoria caché a su vez. El caché se puede borrar mediante el método de recarga.
Hasta aquí todo bien. Esto es parte del FactoryFinder#findServiceProvidermétodo OpenJDKs :
private static <T> T findServiceProvider(final Class<T> type)
throws TransformerFactoryConfigurationError
{
try {
return AccessController.doPrivileged(new PrivilegedAction<T>() {
public T run() {
final ServiceLoader<T> serviceLoader = ServiceLoader.load(type);
final Iterator<T> iterator = serviceLoader.iterator();
if (iterator.hasNext()) {
return iterator.next();
} else {
return null;
}
}
});
} catch(ServiceConfigurationError e) {
...
}
}
Cada llamada a las findServiceProviderllamadas ServiceLoader.load. Esto crea un nuevo ServiceLoader cada vez. De esta manera, parece que no hay ningún uso del mecanismo de almacenamiento en caché de ServiceLoaders. Cada llamada escanea el classpath para el ServiceProvider solicitado.
Lo que ya he probado:
- Sé que puede establecer una propiedad del sistema
javax.xml.transform.TransformerFactorypara especificar una implementación específica. De esta manera FactoryFinder no utiliza el proceso ServiceLoader y es súper rápido. Lamentablemente, esta es una propiedad amplia de jvm y afecta a otros procesos de Java que se ejecutan en mi jvm. Por ejemplo, mi aplicación se envía con Saxon y debería usarcom.saxonica.config.EnterpriseTransformerFactoryTengo otra aplicación que no se envía con Saxon. Tan pronto como configuro la propiedad del sistema, mi otra aplicación no se inicia porque no hay ningunacom.saxonica.config.EnterpriseTransformerFactoryen su classpath. Así que esto no parece ser una opción para mí. - Ya refactoricé todos los lugares donde
TransformerFactory.newInstancese llama a y almacené en caché TransformerFactory. Pero hay varios lugares en mis dependencias donde no puedo refactorizar el código.
Mi pregunta es: ¿Por qué FactoryFinder no reutiliza un ServiceLoader? ¿Hay alguna manera de acelerar todo este proceso de ServiceLoader que no sea usar las propiedades del sistema? ¿No podría cambiarse esto en el JDK para que FactoryFinder reutilice una instancia de ServiceLoader? Además, esto no es específico de un único FactoryFinder. Este comportamiento es el mismo para todas las clases de FactoryFinder en el javax.xmlpaquete que he visto hasta ahora.
Estoy usando OpenJDK 8/11. Mis aplicaciones se implementan en una instancia de Tomcat 9.
Editar: proporcionar más detalles
Aquí está la pila de llamadas para una sola llamada XMLInputFactory.newInstance:

Donde se utilizan la mayoría de los recursos es en ServiceLoaders$LazyIterator.hasNextService. Este método llama getResourcesa ClassLoader para leer el META-INF/services/javax.xml.stream.XMLInputFactoryarchivo. Esa llamada solo toma alrededor de 35 ms cada vez.
¿Hay alguna manera de indicarle a Tomcat que guarde mejor estos archivos en caché para que se sirvan más rápido?
-Dflag en tu Tomcatproceso? Por ejemplo: -Djavax.xml.transform.TransformerFactory=<factory class>.no debe anular las propiedades de otras aplicaciones. Su publicación está bien descrita y probablemente lo haya intentado, pero me gustaría confirmarlo. Consulte Cómo configurar la propiedad del sistema Javax.xml.transform.TransformerFactory , Cómo configurar HeapMemory o JVM Arguments en Tomcat