问题
It takes 15 minutes or more for POI to initialize its first workbook in Java 8 on Windows 10, in a Tomcat 8 instance. Based on interrupting the process in the debugger and looking at the stack, it is spending the time in the classloader, driven by xbeans.
Edit This has the feel of a classloader issue because when I implemented the workaround for the POI library (below), other classes started expressing the same issue.
Edit The stack trace looks most similar to this bug: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8022063
As you can see in jvisualvm, there is no classloader contention in the process thread taskExecutor-1.
I have a workaround, but it should not be necessary. The accepted answer will explain WHY this is happening.
EDIT: Workaround
During application initialization I added this line to the static class initializer for a configuration bean, to force the classloader to preload the classes and resources. It executes instantly there, and when the actual process is invoked it also executes instantly.
XSSFWorkbook preload = new XSSFWorkbook ();
The final workaround was to preload all of the jar files related to SSL, security, and POI. As near as I can tell, when loaded late in a spring batch context (may be a red herring), the classloader is attempting to validate the bouncycastle jar files with algorithms encoded in the bouncycastle classes, and is running everything in the SSL stack in interpreted mode.
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 excerpt:
<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>
Code:
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???
}
}
回答1:
It turns out that under some circumstances when you mix jars from different versions of java (say 1.5 and 1.8), the JIT will throw up its hands and run in interpreted mode. There are several reports of the behavior listed on Oracle's website that say "we don't know why it's doing this, we won't fix it".
I downloaded sources for the libraries that were not compiled in 1.8 and built from source, and all is well.
来源:https://stackoverflow.com/questions/54185197/apache-poi-4-0-1-super-slow-getting-started-15-minutes-or-more-what-is-wron