Ben xml işleme çok yapıyor büyük bir sınıf yolu ile oldukça büyük bir java ee uygulama var. Şu anda bazı işlevleri hızlandırmak ve örnekleme profilers örnekleme yoluyla yavaş kod yolları bulma çalışıyorum.
Fark ettiğim bir şey, özellikle kodumuzun çağrı yaptığımız TransformerFactory.newInstance(...)
bölümlerinin umutsuzca yavaş olmasıdır. Bunu her zaman yeni bir örnek oluşturma FactoryFinder
yöntemine kadar izledim . Gelen javadoc ben önbelleğe alma hakkında aşağıdaki not buldum:findServiceProvider
ServiceLoader
ServiceLoader
Tedarikçiler tembel olarak, yani talep üzerine yerleştirilir ve somutlaştırılır. Bir hizmet yükleyici, şu ana kadar yüklenmiş olan sağlayıcıların önbelleğini tutar. Yineleyici yönteminin her çağrılması, önce önbelleğin tüm öğelerini örnekleme sırasında veren bir yineleyici döndürür ve ardından kalan sağlayıcıları tembel olarak bulur ve her birini sırayla önbelleğe ekler. Önbellek yeniden yükleme yöntemi ile temizlenebilir.
Çok uzak çok iyi. Bu OpenJDKs FactoryFinder#findServiceProvider
yönteminin bir parçasıdır :
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) {
...
}
}
Yapılan her çağrı findServiceProvider
aramalar ServiceLoader.load
. Bu, her seferinde yeni bir ServiceLoader oluşturur . Bu şekilde, ServiceLoaders önbellekleme mekanizmasının hiç kullanılmadığı görülmektedir. Her çağrı, istenen ServiceProvider için sınıfyolunu tarar.
Zaten denedim:
javax.xml.transform.TransformerFactory
Belirli bir uygulamayı belirtmek gibi bir sistem özelliği ayarlayabileceğinizi biliyorum . Bu şekilde FactoryFinder ServiceLoader işlemini ve süper hızını kullanmaz. Ne yazık ki bu bir jvm geniş özellik ve benim jvm çalışan diğer java süreçlerini etkiler. Örneğin benim uygulamam Saxon ile birlikte geliyor ve kullanmalıyımcom.saxonica.config.EnterpriseTransformerFactory
Saxon ile gönderilmeyen başka bir uygulamam var. System özelliğini ayarlar ayarlamaz diğer uygulamam başlatılamıyor çünkücom.saxonica.config.EnterpriseTransformerFactory
sınıf yolunda yok. Yani bu benim için bir seçenek gibi görünmüyor.- Ben zaten a
TransformerFactory.newInstance
denilen her yeri yeniden düzenledim ve TransformerFactory önbellek. Ancak bağımlılıklarımda kodu yeniden düzenleyemediğim çeşitli yerler var.
Sorularım: FactoryFinder neden bir ServiceLoader'ı yeniden kullanmıyor? Sistem özelliklerini kullanmak dışında tüm ServiceLoader işlemini hızlandırmanın bir yolu var mı? Bu JDK'da değiştirilemez, böylece bir FactoryFinder bir ServiceLoader örneğini yeniden kullanır mı? Ayrıca bu, tek bir FactoryFinder'a özgü değildir. Bu bahaviour javax.xml
, şimdiye kadar baktığım paketteki tüm FactoryFinder sınıfları için aynı .
OpenJDK 8/11 kullanıyorum. Uygulamalarım bir Tomcat 9 örneğinde dağıtıldı.
Düzenle: Daha fazla ayrıntı sağlama
Tek bir XMLInputFactory.newInstance çağrısı için çağrı yığını şöyledir:
Kaynakların çoğunun kullanıldığı yerler ServiceLoaders$LazyIterator.hasNextService
. Bu yöntem dosyayı getResources
okumak için ClassLoader'ı çağırır META-INF/services/javax.xml.stream.XMLInputFactory
. Sadece bu çağrı her seferinde yaklaşık 35 ms sürer.
Tomcat'e daha hızlı sunulmaları için bu dosyaları daha iyi önbelleğe almaları talimatı vermenin bir yolu var mı?
-D
bayrak kullanarak özellik ayarlamayı denediniz Tomcat
mi? Örneğin: -Djavax.xml.transform.TransformerFactory=<factory class>.
Diğer uygulamaların özelliklerini geçersiz kılmamalıdır. Yayınınız iyi tanımlanmış ve muhtemelen denediniz, ancak onaylamak istiyorum. Bkz Javax.xml.transform.TransformerFactory sistem özelliği nasıl ayarlanır , nasıl Tomcat HeapMemory veya JVM değişkenleri ayarlamak için