ฉันมีแอปพลิเคชัน Java ee ค่อนข้างใหญ่ที่มี classpath ขนาดใหญ่ที่ทำการประมวลผล xml จำนวนมาก ขณะนี้ฉันกำลังพยายามเพิ่มความเร็วฟังก์ชั่นบางอย่างของฉันและค้นหาเส้นทางของรหัสที่ช้าโดยใช้เครื่องมือเก็บตัวอย่าง
สิ่งหนึ่งที่ฉันสังเกตเห็นคือโดยเฉพาะอย่างยิ่งส่วนต่าง ๆ ของรหัสของเราที่เรามีการเรียกเช่นTransformerFactory.newInstance(...)
ช้ามาก ฉันติดตามสิ่งนี้เป็นFactoryFinder
วิธีfindServiceProvider
การสร้างServiceLoader
อินสแตนซ์ใหม่เสมอ ในServiceLoader
javadocฉันพบบันทึกย่อต่อไปนี้เกี่ยวกับการแคช:
ผู้ให้บริการตั้งอยู่และยกตัวอย่างขี้เกียจนั่นคือตามความต้องการ ตัวโหลดเซอร์วิสรักษาแคชของตัวให้บริการที่ถูกโหลดไปแล้ว การร้องขอเมธอด iterator แต่ละครั้งจะส่งคืนตัววนซ้ำที่ให้องค์ประกอบทั้งหมดของแคชตามลำดับการเริ่มต้นจากนั้นหาตำแหน่งอย่างเกียจคร้านแล้วค้นหาตำแหน่งของผู้ให้บริการที่เหลืออยู่อย่างเกียจคร้าน แคชสามารถล้างได้ด้วยวิธีการโหลดซ้ำ
จนถึงตอนนี้ดีมาก นี่เป็นส่วนหนึ่งของFactoryFinder#findServiceProvider
วิธีการ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) {
...
}
}
สายทุกสายfindServiceProvider
ServiceLoader.load
สิ่งนี้จะสร้างServiceLoader ใหม่ทุกครั้ง วิธีนี้ดูเหมือนว่าไม่มีการใช้กลไกการแคช ServiceLoaders เลย การโทรทุกครั้งจะสแกน classpath สำหรับ ServiceProvider ที่ร้องขอ
สิ่งที่ฉันได้ลองไปแล้ว:
- ฉันรู้ว่าคุณสามารถตั้งค่าคุณสมบัติของระบบที่ต้องการ
javax.xml.transform.TransformerFactory
ระบุการใช้งานเฉพาะ วิธีนี้ FactoryFinder ไม่ใช้กระบวนการ ServiceLoader และมันเร็วสุด น่าเศร้าที่นี่เป็นคุณสมบัติกว้าง jvm และมีผลต่อกระบวนการ java อื่น ๆ ที่ทำงานใน jvm ของฉัน ตัวอย่างเช่นแอปพลิเคชันของฉันมาพร้อมกับ Saxon และควรใช้com.saxonica.config.EnterpriseTransformerFactory
ฉันมีแอปพลิเคชันอื่นที่ไม่ได้จัดส่งกับ Saxon ทันทีที่ฉันตั้งค่าคุณสมบัติระบบแอปพลิเคชันอื่นของฉันไม่สามารถเริ่มทำงานได้เนื่องจากไม่มีcom.saxonica.config.EnterpriseTransformerFactory
อยู่ใน classpath ดังนั้นนี่ดูเหมือนจะไม่ใช่ตัวเลือกสำหรับฉัน - ฉันได้รับการปรับโครงสร้างใหม่แล้วทุกที่ที่
TransformerFactory.newInstance
เรียกว่าและแคช TransformerFactory แต่มีหลายสถานที่ในการพึ่งพาของฉันที่ฉันไม่สามารถ refactor รหัส
คำถามของฉันคือ: เหตุใด FactoryFinder จึงไม่นำ ServiceLoader ไปใช้ซ้ำ มีวิธีใดบ้างที่จะเร่งกระบวนการทั้งหมดของ ServiceLoader นอกเหนือจากการใช้คุณสมบัติของระบบ สิ่งนี้ไม่สามารถเปลี่ยนแปลงได้ใน JDK เพื่อให้ FactoryFinder นำอินสแตนซ์ของ ServiceLoader กลับมาใช้ใหม่ได้หรือไม่ นอกจากนี้นี่ไม่เฉพาะกับ FactoryFinder เดียว บาฮาเวียร์นี้เหมือนกันสำหรับคลาส FactoryFinder ทั้งหมดในjavax.xml
แพ็คเกจที่ฉันได้ดูไปแล้ว
ฉันใช้ OpenJDK 8/11 แอปพลิเคชันของฉันถูกปรับใช้ในอินสแตนซ์ Tomcat 9
แก้ไข: ให้รายละเอียดเพิ่มเติม
นี่คือสแตกการเรียกสำหรับการเรียก XMLInputFactory.newInstance เดียว:
ServiceLoaders$LazyIterator.hasNextService
ที่เป็นทรัพยากรส่วนใหญ่จะใช้อยู่ใน วิธีนี้เรียกร้องgetResources
ให้ ClassLoader อ่านMETA-INF/services/javax.xml.stream.XMLInputFactory
ไฟล์ การโทรนั้นจะใช้เวลาประมาณ 35ms ต่อครั้ง
มีวิธีในการสั่งให้ Tomcat ทำการแคชไฟล์เหล่านี้ให้ดีขึ้นหรือไม่เพื่อให้สามารถทำงานได้เร็วขึ้น?
-D
แฟล็กเป็นTomcat
กระบวนการของคุณหรือไม่? ตัวอย่างเช่น: -Djavax.xml.transform.TransformerFactory=<factory class>.
ไม่ควรแทนที่คุณสมบัติของแอพอื่น โพสต์ของคุณได้รับการอธิบายอย่างดีและคุณอาจจะลองแล้ว แต่ฉันต้องการยืนยัน ดูวิธีการตั้งค่าคุณสมบัติระบบ Javax.xml.transform.TransformerFactory , วิธีการตั้งค่า HeapMemory หรือ JVM ข้อโต้แย้งใน Tomcat