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 FactoryFinder
metode yang findServiceProvider
selalu membuat ServiceLoader
contoh 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#findServiceProvider
metode 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 findServiceProvider
panggilan 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.TransformerFactory
menentukan 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.EnterpriseTransformerFactory
saya 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.EnterpriseTransformerFactory
di classpath-nya. Jadi ini sepertinya tidak menjadi pilihan bagi saya. - Saya sudah refactored setiap tempat di mana a
TransformerFactory.newInstance
dipanggil 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.xml
paket 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 getResources
ClassLoader untuk membaca META-INF/services/javax.xml.stream.XMLInputFactory
file. 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?
-D
bendera ke Tomcat
proses 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