我有一个相当大的Java ee应用程序,它具有执行许多xml处理的巨大类路径。目前,我正在尝试加快某些功能的速度,并通过采样分析器定位慢速代码路径。
我注意到的一件事是,特别是我们在其中调用类似代码的部分TransformerFactory.newInstance(...)
非常慢。我跟踪下来到FactoryFinder
方法findServiceProvider
始终创建一个新的ServiceLoader
实例。在ServiceLoader
javadoc中,我发现了有关缓存的以下说明:
提供商的位置很懒,即按需实例化。服务加载器维护到目前为止已加载的提供者的缓存。每次迭代器方法的调用都会返回一个迭代器,该迭代器首先按实例化顺序生成高速缓存的所有元素,然后懒惰地定位和实例化任何剩余的提供程序,依次将每个提供程序添加到高速缓存中。可以通过reload方法清除缓存。
到目前为止,一切都很好。这是OpenJDKs FactoryFinder#findServiceProvider
方法的一部分:
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缓存机制。每个调用都会扫描类路径以查找请求的ServiceProvider。
我已经尝试过的:
- 我知道您可以设置系统属性
javax.xml.transform.TransformerFactory
来指定特定的实现。这样,FactoryFinder不会使用ServiceLoader进程及其超快的速度。遗憾的是,这是jvm范围的属性,会影响在我的jvm中运行的其他java进程。例如,我的应用程序随Saxon一起提供,并且应该使用,但com.saxonica.config.EnterpriseTransformerFactory
我有另一个应用程序随Saxon一起提供。设置系统属性后,其他应用程序将无法启动,因为com.saxonica.config.EnterpriseTransformerFactory
其类路径中没有。因此,这似乎不是我的选择。 - 我已经重构了每个
TransformerFactory.newInstance
被称为a的地方,并缓存了TransformerFactory。但是在我的依赖项中有很多地方无法重构代码。
我的问题是:为什么FactoryFinder不重用ServiceLoader?除了使用系统属性以外,是否有办法加快整个ServiceLoader进程?不能在JDK中对此进行更改,以便FactoryFinder重用ServiceLoader实例吗?此外,这并非特定于单个FactoryFinder。javax.xml
到目前为止,我对软件包中所有FactoryFinder类的行为都相同。
我正在使用OpenJDK 8/11。我的应用程序部署在Tomcat 9实例中。
编辑:提供更多详细信息
这是单个XMLInputFactory.newInstance调用的调用堆栈:
使用最多资源的位置是ServiceLoaders$LazyIterator.hasNextService
。此方法调用getResources
ClassLoader读取META-INF/services/javax.xml.stream.XMLInputFactory
文件。每次通话大约需要35毫秒。
有没有一种方法可以指示Tomcat更好地缓存这些文件,以便更快地提供它们?
-D
标志来设置属性Tomcat
?例如:-Djavax.xml.transform.TransformerFactory=<factory class>.
它不应覆盖其他应用程序的属性。您的帖子描述得很好,也许您已经尝试过,但我想确认一下。请参阅如何设置javax.xml.transform.TransformerFactory的系统属性,如何设置Tomcat的HeapMemory或JVM参数