Mam dość dużą aplikację Java ee z ogromną ścieżką klasy, która wykonuje wiele przetwarzania XML. Obecnie próbuję przyspieszyć niektóre z moich funkcji i zlokalizować wolne ścieżki kodu za pomocą profilerów próbkujących.
Zauważyłem, że szczególnie części naszego kodu, w których mamy wywołania, TransformerFactory.newInstance(...)
są desperacko wolne. Śledziłem to FactoryFinder
metodą, która findServiceProvider
zawsze tworzy nową ServiceLoader
instancję. W ServiceLoader
javadoc znalazłem następującą notatkę o buforowaniu:
Dostawcy są zlokalizowani i utworzeni leniwie, czyli na żądanie. Program ładujący utrzymuje pamięć podręczną dostawców, którzy zostali załadowani do tej pory. Każde wywołanie metody iteratora zwraca iterator, który najpierw zwraca wszystkie elementy pamięci podręcznej w kolejności tworzenia instancji, a następnie leniwie lokalizuje i tworzy instancję pozostałych dostawców, dodając kolejno każdego z nich do pamięci podręcznej. Pamięć podręczną można wyczyścić za pomocą metody przeładowania.
Na razie w porządku. Jest to część FactoryFinder#findServiceProvider
metody OpenJDK :
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) {
...
}
}
Każde połączenie do findServiceProvider
połączeń ServiceLoader.load
. Tworzy to za każdym razem nowy ServiceLoader. W ten sposób wydaje się, że mechanizm buforowania ServiceLoaders w ogóle nie jest używany. Każde połączenie skanuje ścieżkę klasy w poszukiwaniu żądanego dostawcy usługi.
Co już próbowałem:
- Wiem, że możesz ustawić właściwość systemową, np.
javax.xml.transform.TransformerFactory
Określić konkretną implementację. W ten sposób FactoryFinder nie korzysta z procesu ServiceLoader i jego superszybkiego działania. Niestety jest to właściwość dla całego środowiska JVM i wpływa na inne procesy Java uruchomione w moim środowisku JVM. Na przykład moja aplikacja jest dostarczana z Saxonem i powinienem użyćcom.saxonica.config.EnterpriseTransformerFactory
Mam inną aplikację, która nie jest dostarczana z Saxonem. Gdy tylko ustawię właściwość systemową, moja inna aplikacja nie uruchamia się, ponieważ nie macom.saxonica.config.EnterpriseTransformerFactory
jej w ścieżce klasy. Więc nie wydaje mi się to rozwiązaniem. - Już dokonałem refaktoryzacji każdego miejsca, w którym
TransformerFactory.newInstance
nazywa się a, i buforuję TransformerFactory. Ale w moich zależnościach są różne miejsca, w których nie mogę refaktoryzować kodu.
Moje pytania brzmią: dlaczego FactoryFinder nie używa ponownie programu ServiceLoader? Czy istnieje sposób na przyspieszenie całego procesu ServiceLoader, inny niż użycie właściwości systemowych? Czy nie można tego zmienić w JDK, aby FactoryFinder ponownie używał instancji ServiceLoader? Nie dotyczy to również pojedynczego FactoryFinder. To zachowanie jest takie samo dla wszystkich klas FactoryFinder w javax.xml
pakiecie, na który patrzyłem do tej pory.
Używam OpenJDK 8/11. Moje aplikacje są wdrażane w instancji Tomcat 9.
Edycja: podając więcej szczegółów
Oto stos wywołań dla pojedynczego wywołania XMLInputFactory.newInstance:
Tam, gdzie wykorzystuje się większość zasobów, znajduje się ServiceLoaders$LazyIterator.hasNextService
. Ta metoda wywołuje getResources
ClassLoader w celu odczytania META-INF/services/javax.xml.stream.XMLInputFactory
pliku. Samo połączenie za każdym razem zajmuje około 35 ms.
Czy istnieje sposób, aby poinstruować Tomcat, aby lepiej buforował te pliki, aby były szybciej dostarczane?
-D
flagi do swojego Tomcat
procesu? Na przykład: -Djavax.xml.transform.TransformerFactory=<factory class>.
nie powinno zastępować właściwości innych aplikacji. Twój post jest dobrze opisany i prawdopodobnie próbowałeś, ale chciałbym to potwierdzić. Zobacz Jak ustawić właściwość systemową Javax.xml.transform.TransformerFactory , Jak ustawić argumenty HeapMemory lub JVM w Tomcat