Optimize JarLauncher when used with exploded jar

- Previously, we would create a JarFileArchive for all nested jars.
This was an additional overhead. We only need to create a JarFileArchive
for jars that can have nested jars in them. For all other jars we only need
the URL to build the classpath.
- While iterating over nested entries in the exploded jar, we only need to
look at BOOT-INF and we can skip any entry that does not match that.

Closes gh-16655

Co-authored-by: Phillip Webb <pwebb@pivotal.io>
This commit is contained in:
Madhura Bhave
2019-12-10 12:19:23 -08:00
parent 58022d72f5
commit 8f5777cf9e
13 changed files with 418 additions and 128 deletions

View File

@@ -20,6 +20,7 @@ import java.io.File;
import java.net.URL;
import java.util.List;
import org.codehaus.plexus.util.CollectionUtils;
import org.junit.jupiter.api.Test;
import org.springframework.boot.loader.archive.Archive;
@@ -39,7 +40,7 @@ class JarLauncherTests extends AbstractExecutableArchiveLauncherTests {
void explodedJarHasOnlyBootInfClassesAndContentsOfBootInfLibOnClasspath() throws Exception {
File explodedRoot = explode(createJarArchive("archive.jar", "BOOT-INF"));
JarLauncher launcher = new JarLauncher(new ExplodedArchive(explodedRoot, true));
List<Archive> archives = launcher.getClassPathArchives();
List<Archive> archives = CollectionUtils.iteratorToList(launcher.getClassPathArchivesIterator());
assertThat(archives).hasSize(2);
assertThat(getUrls(archives)).containsOnly(new File(explodedRoot, "BOOT-INF/classes").toURI().toURL(),
new File(explodedRoot, "BOOT-INF/lib/foo.jar").toURI().toURL());
@@ -53,7 +54,7 @@ class JarLauncherTests extends AbstractExecutableArchiveLauncherTests {
File jarRoot = createJarArchive("archive.jar", "BOOT-INF");
try (JarFileArchive archive = new JarFileArchive(jarRoot)) {
JarLauncher launcher = new JarLauncher(archive);
List<Archive> classPathArchives = launcher.getClassPathArchives();
List<Archive> classPathArchives = CollectionUtils.iteratorToList(launcher.getClassPathArchivesIterator());
assertThat(classPathArchives).hasSize(2);
assertThat(getUrls(classPathArchives)).containsOnly(
new URL("jar:" + jarRoot.toURI().toURL() + "!/BOOT-INF/classes!/"),

View File

@@ -30,6 +30,7 @@ import java.util.jar.Manifest;
import org.assertj.core.api.Condition;
import org.awaitility.Awaitility;
import org.codehaus.plexus.util.CollectionUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -139,7 +140,7 @@ class PropertiesLauncherTests {
System.setProperty("loader.path", "jars/");
PropertiesLauncher launcher = new PropertiesLauncher();
assertThat(ReflectionTestUtils.getField(launcher, "paths").toString()).isEqualTo("[jars/]");
List<Archive> archives = launcher.getClassPathArchives();
List<Archive> archives = CollectionUtils.iteratorToList(launcher.getClassPathArchivesIterator());
assertThat(archives).areExactly(1, endingWith("app.jar"));
}
@@ -169,7 +170,7 @@ class PropertiesLauncherTests {
PropertiesLauncher launcher = new PropertiesLauncher();
assertThat(ReflectionTestUtils.getField(launcher, "paths").toString())
.isEqualTo("[jar:file:./src/test/resources/nested-jars/app.jar!/]");
List<Archive> archives = launcher.getClassPathArchives();
List<Archive> archives = CollectionUtils.iteratorToList(launcher.getClassPathArchivesIterator());
assertThat(archives).areExactly(1, endingWith("foo.jar!/"));
assertThat(archives).areExactly(1, endingWith("app.jar"));
}
@@ -178,7 +179,7 @@ class PropertiesLauncherTests {
void testUserSpecifiedRootOfJarPathWithDot() throws Exception {
System.setProperty("loader.path", "nested-jars/app.jar!/./");
PropertiesLauncher launcher = new PropertiesLauncher();
List<Archive> archives = launcher.getClassPathArchives();
List<Archive> archives = CollectionUtils.iteratorToList(launcher.getClassPathArchivesIterator());
assertThat(archives).areExactly(1, endingWith("foo.jar!/"));
assertThat(archives).areExactly(1, endingWith("app.jar"));
}
@@ -187,7 +188,7 @@ class PropertiesLauncherTests {
void testUserSpecifiedRootOfJarPathWithDotAndJarPrefix() throws Exception {
System.setProperty("loader.path", "jar:file:./src/test/resources/nested-jars/app.jar!/./");
PropertiesLauncher launcher = new PropertiesLauncher();
List<Archive> archives = launcher.getClassPathArchives();
List<Archive> archives = CollectionUtils.iteratorToList(launcher.getClassPathArchivesIterator());
assertThat(archives).areExactly(1, endingWith("foo.jar!/"));
}
@@ -196,7 +197,7 @@ class PropertiesLauncherTests {
System.setProperty("loader.path", "nested-jars/app.jar");
System.setProperty("loader.main", "demo.Application");
PropertiesLauncher launcher = new PropertiesLauncher();
List<Archive> archives = launcher.getClassPathArchives();
List<Archive> archives = CollectionUtils.iteratorToList(launcher.getClassPathArchivesIterator());
assertThat(archives).areExactly(1, endingWith("foo.jar!/"));
assertThat(archives).areExactly(1, endingWith("app.jar"));
}
@@ -206,7 +207,7 @@ class PropertiesLauncherTests {
System.setProperty("loader.path", "nested-jars/app.jar!/foo.jar");
System.setProperty("loader.main", "demo.Application");
PropertiesLauncher launcher = new PropertiesLauncher();
List<Archive> archives = launcher.getClassPathArchives();
List<Archive> archives = CollectionUtils.iteratorToList(launcher.getClassPathArchivesIterator());
assertThat(archives).hasSize(1).areExactly(1, endingWith("foo.jar!/"));
}
@@ -335,7 +336,7 @@ class PropertiesLauncherTests {
loaderPath.mkdir();
System.setProperty("loader.path", loaderPath.toURI().toURL().toString());
PropertiesLauncher launcher = new PropertiesLauncher();
List<Archive> archives = launcher.getClassPathArchives();
List<Archive> archives = CollectionUtils.iteratorToList(launcher.getClassPathArchivesIterator());
assertThat(archives.size()).isEqualTo(1);
File archiveRoot = (File) ReflectionTestUtils.getField(archives.get(0), "root");
assertThat(archiveRoot).isEqualTo(loaderPath);

View File

@@ -20,6 +20,7 @@ import java.io.File;
import java.net.URL;
import java.util.List;
import org.codehaus.plexus.util.CollectionUtils;
import org.junit.jupiter.api.Test;
import org.springframework.boot.loader.archive.Archive;
@@ -39,7 +40,7 @@ class WarLauncherTests extends AbstractExecutableArchiveLauncherTests {
void explodedWarHasOnlyWebInfClassesAndContentsOfWebInfLibOnClasspath() throws Exception {
File explodedRoot = explode(createJarArchive("archive.war", "WEB-INF"));
WarLauncher launcher = new WarLauncher(new ExplodedArchive(explodedRoot, true));
List<Archive> archives = launcher.getClassPathArchives();
List<Archive> archives = CollectionUtils.iteratorToList(launcher.getClassPathArchivesIterator());
assertThat(archives).hasSize(2);
assertThat(getUrls(archives)).containsOnly(new File(explodedRoot, "WEB-INF/classes").toURI().toURL(),
new File(explodedRoot, "WEB-INF/lib/foo.jar").toURI().toURL());
@@ -53,7 +54,7 @@ class WarLauncherTests extends AbstractExecutableArchiveLauncherTests {
File jarRoot = createJarArchive("archive.war", "WEB-INF");
try (JarFileArchive archive = new JarFileArchive(jarRoot)) {
WarLauncher launcher = new WarLauncher(archive);
List<Archive> classPathArchives = launcher.getClassPathArchives();
List<Archive> classPathArchives = CollectionUtils.iteratorToList(launcher.getClassPathArchivesIterator());
assertThat(classPathArchives).hasSize(2);
assertThat(getUrls(classPathArchives)).containsOnly(
new URL("jar:" + jarRoot.toURI().toURL() + "!/WEB-INF/classes!/"),

View File

@@ -74,7 +74,6 @@ class ExplodedArchiveTests {
private void createArchive(String folderName) throws Exception {
File file = new File(this.tempDir, "test.jar");
TestJarCreator.createTestJar(file);
this.rootFolder = (StringUtils.hasText(folderName) ? new File(this.tempDir, folderName)
: new File(this.tempDir, UUID.randomUUID().toString()));
JarFile jarFile = new JarFile(file);
@@ -102,7 +101,7 @@ class ExplodedArchiveTests {
@Test
void getEntries() {
Map<String, Archive.Entry> entries = getEntriesMap(this.archive);
assertThat(entries.size()).isEqualTo(12);
assertThat(entries).hasSize(12);
}
@Test
@@ -121,7 +120,7 @@ class ExplodedArchiveTests {
Entry entry = getEntriesMap(this.archive).get("nested.jar");
Archive nested = this.archive.getNestedArchive(entry);
assertThat(nested.getUrl().toString()).isEqualTo(this.rootFolder.toURI() + "nested.jar");
((JarFileArchive) nested).close();
nested.close();
}
@Test