java - Apache POI 4.0.1 上手超慢... 15 分钟以上。怎么了?
问题描述
在 Tomcat 8 实例中,POI 需要 15 分钟或更长时间才能在 Windows 10 上的 Java 8 中初始化其第一个工作簿。基于在调试器中中断进程并查看堆栈,它将时间花在由 xbeans 驱动的类加载器中。
编辑 这有类加载器问题的感觉,因为当我为 POI 库(如下)实施解决方法时,其他类开始表达相同的问题。
编辑 堆栈跟踪看起来与此错误最相似:https ://bugs.java.com/bugdatabase/view_bug.do?bug_id=8022063
在 jvisualvm 中可以看到,进程线程 taskExecutor-1 中没有类加载器争用。
我有一个解决方法,但它不应该是必要的。接受的答案将解释为什么会这样。
编辑:解决方法
在应用程序初始化期间,我将此行添加到配置 bean 的静态类初始化程序中,以强制类加载器预加载类和资源。它在那里立即执行,当调用实际过程时,它也立即执行。
XSSFWorkbook preload = new XSSFWorkbook ();
最后的解决方法是预加载与 SSL、安全性和 POI 相关的所有 jar 文件。据我所知,当在春季批处理上下文中加载较晚时(可能是红鲱鱼),类加载器正在尝试使用在 bouncycastle 类中编码的算法验证 bouncycastle jar 文件,并且正在运行 SSL 堆栈中的所有内容解释模式。
Reflections reflections = new Reflections("org.bouncycastle", this.getClass().getClassLoader(), new SubTypesScanner(false));
Set<Class<? extends Object>> bouncyCastleClasses = reflections.getSubTypesOf(Object.class);
reflections = new Reflections("sun.security", this.getClass().getClassLoader(), new SubTypesScanner(false));
Set<Class<? extends Object>> sunSecurityClasses = reflections.getSubTypesOf(Object.class);
reflections = new Reflections("javax.ssl", this.getClass().getClassLoader(), new SubTypesScanner(false));
Set<Class<? extends Object>> javaSslClasses = reflections.getSubTypesOf(Object.class);
reflections = new Reflections("org.apache.poi", this.getClass().getClassLoader(), new SubTypesScanner(false));
Set<Class<? extends Object>> poiClasses = reflections.getSubTypesOf(Object.class);
POM摘录:
<poi.version>4.0.1</poi.version>
<!-- apache poi / poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
代码:
public void beforeJob(JobExecution jobExecution) {
if (logger.isDebugEnabled()) {
workbookname = "debuginfo-" + System.currentTimeMillis() + ".xlsx";
logger.debug("Debug statistics dump file will be saved at [{}]", workbookname);
debugStatsDump = new XSSFWorkbook(); // This line takes several minutes to run, apparently in the classloader???
}
}
解决方案
事实证明,在某些情况下,当您混合来自不同版本的 java(比如 1.5 和 1.8)的 jar 时,JIT 会举手并以解释模式运行。甲骨文网站上有几份关于该行为的报告称“我们不知道它为什么会这样,我们不会修复它”。
我下载了未在 1.8 中编译并从源代码构建的库的源代码,一切都很好。
推荐阅读
- android - admob 广告加载失败:3?
- java - MPEG2-TS 的 Xuggler IContainerFormat 字段
- google-maps - Flutter google_maps_flutter 无法通过 PopupMenuButton 更改 MapType
- php - 无法使用php和mysql登录
- sql - SQL Server 聚合最近 12 个月
- ios - 快速从 firebase 读取数据但无法显示。可能变量范围错误
- c++ - 如何使用 cmake 从面向 Windows 的 Linux 进行交叉编译?
- python - “TypeError:Singleton 数组不能被视为有效集合”使用 sklearn train_test_split
- c# - 块的 AES 加密和解密导致错误的输出
- java - 尝试隐藏工具栏后留下的空白