Saya punya aplikasi java ee agak besar dengan classpath besar melakukan banyak pemrosesan xml. Saat ini saya mencoba untuk mempercepat beberapa fungsi saya dan menemukan jalur kode lambat melalui sampling profiler.
Satu hal yang saya perhatikan adalah bahwa terutama bagian dari kode kita di mana kita memiliki panggilan seperti TransformerFactory.newInstance(...)sangat lambat Saya melacak ini ke FactoryFindermetode yang findServiceProviderselalu membuat ServiceLoadercontoh baru . Di ServiceLoader javadoc saya menemukan catatan berikut tentang caching:
Penyedia ditempatkan dan dipakai secara malas, yaitu, sesuai permintaan. Pemuat layanan menyimpan cache dari penyedia yang telah dimuat sejauh ini. Setiap permohonan metode iterator mengembalikan iterator yang pertama-tama menghasilkan semua elemen cache, dalam urutan instantiation, dan kemudian dengan malas menemukan dan membuat instantiate penyedia yang tersisa, menambahkan masing-masing ke cache pada gilirannya. Cache dapat dihapus melalui metode reload.
Sejauh ini bagus. Ini adalah bagian dari FactoryFinder#findServiceProvidermetode 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) {
...
}
}
Setiap panggilan ke findServiceProviderpanggilan ServiceLoader.load. Ini menciptakan yang baru ServiceLoader setiap kali. Dengan cara ini tampaknya tidak ada penggunaan mekanisme caching ServiceLoaders sama sekali. Setiap panggilan memindai classpath untuk ServiceProvider yang diminta.
Apa yang sudah saya coba:
- Saya tahu Anda dapat mengatur properti sistem ingin
javax.xml.transform.TransformerFactorymenentukan implementasi tertentu. Dengan cara ini FactoryFinder tidak menggunakan proses ServiceLoader dan sangat cepat. Sayangnya ini adalah properti jvm lebar dan mempengaruhi proses java lainnya yang berjalan di jvm saya. Misalnya aplikasi saya dikirim dengan Saxon dan harus menggunakancom.saxonica.config.EnterpriseTransformerFactorysaya punya aplikasi lain yang tidak dikirimkan dengan Saxon. Segera setelah saya mengatur properti sistem, aplikasi saya yang lain gagal untuk memulai, karena tidak adacom.saxonica.config.EnterpriseTransformerFactorydi classpath-nya. Jadi ini sepertinya tidak menjadi pilihan bagi saya. - Saya sudah refactored setiap tempat di mana a
TransformerFactory.newInstancedipanggil dan menyimpan cache TransformerFactory. Tetapi ada berbagai tempat di dependensi saya di mana saya tidak bisa memperbaiki kode.
Pertanyaan saya adalah: Mengapa FactoryFinder tidak menggunakan kembali ServiceLoader? Apakah ada cara untuk mempercepat seluruh proses ServiceLoader ini selain menggunakan properti sistem? Tidak bisakah ini diubah di JDK sehingga FactoryFinder menggunakan instance ServiceLoader? Juga ini tidak spesifik untuk FactoryFinder tunggal. Bahaviour ini sama untuk semua kelas FactoryFinder dalam javax.xmlpaket yang telah saya lihat sejauh ini.
Saya menggunakan OpenJDK 8/11. Aplikasi saya digunakan dalam instance Tomcat 9.
Sunting: Memberikan rincian lebih lanjut
Berikut adalah tumpukan panggilan untuk panggilan XMLInputFactory.newInstance tunggal:

Di mana sebagian besar sumber daya digunakan ServiceLoaders$LazyIterator.hasNextService. Metode ini memanggil getResourcesClassLoader untuk membaca META-INF/services/javax.xml.stream.XMLInputFactoryfile. Panggilan itu sendiri membutuhkan sekitar 35 ms setiap kali.
Apakah ada cara untuk menginstruksikan Tomcat untuk melakukan cache yang lebih baik pada file-file ini sehingga dilayani lebih cepat?
-Dbendera ke Tomcatproses Anda ? Misalnya: -Djavax.xml.transform.TransformerFactory=<factory class>.Seharusnya tidak menimpa properti untuk aplikasi lain. Posting Anda dijelaskan dengan baik dan mungkin Anda telah mencobanya tetapi saya ingin mengonfirmasi. Lihat Cara mengatur properti sistem Javax.xml.transform.TransformerFactory , Cara mengatur Argumen HeapMemory atau JVM di Tomcat