POI在Windows 10上的Tomcat 8实例中初始化其第一个工作簿需要15分钟或更长时间。基于在调试器中中断进程并查看堆栈,它将花费时间在类加载器中,由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)的jars时,JIT会抛出它的手并以解释模式运行。有几个关于Oracle网站上列出的行为的报告称“我们不知道为什么会这样做,我们不会修复它”。
我下载了未在1.8中编译并从源代码构建的库的源代码,一切都很好。