Relocate launcher classes

Create alternative launcher classes under the package
`org.springframework.boot.loader.launch` and use them in favor
of the previous location.

This update is designed to improve compatibility with future
changes in the loader.

Closes gh-37667
This commit is contained in:
Phillip Webb 2023-09-18 12:39:28 -07:00
parent f947bad3f7
commit c22548982a
33 changed files with 183 additions and 54 deletions

View File

@ -44,7 +44,7 @@ COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./ COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./ COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./ COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"] ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]
---- ----
Assuming the above `Dockerfile` is in the current directory, your docker image can be built with `docker build .`, or optionally specifying the path to your application jar, as shown in the following example: Assuming the above `Dockerfile` is in the current directory, your docker image can be built with `docker build .`, or optionally specifying the path to your application jar, as shown in the following example:

View File

@ -28,8 +28,8 @@ The following shows an example of a `layers.idx` file:
- BOOT-INF/lib/library1.jar - BOOT-INF/lib/library1.jar
- BOOT-INF/lib/library2.jar - BOOT-INF/lib/library2.jar
- "spring-boot-loader": - "spring-boot-loader":
- org/springframework/boot/loader/JarLauncher.class - org/springframework/boot/loader/launch/JarLauncher.class
- org/springframework/boot/loader/jar/JarEntry.class - ... <other classes>
- "snapshot-dependencies": - "snapshot-dependencies":
- BOOT-INF/lib/library3-SNAPSHOT.jar - BOOT-INF/lib/library3-SNAPSHOT.jar
- "application": - "application":

View File

@ -13,7 +13,7 @@ One way to run an unpacked archive is by starting the appropriate launcher, as f
[source,shell,indent=0,subs="verbatim"] [source,shell,indent=0,subs="verbatim"]
---- ----
$ jar -xf myapp.jar $ jar -xf myapp.jar
$ java org.springframework.boot.loader.JarLauncher $ java org.springframework.boot.loader.launch.JarLauncher
---- ----
This is actually slightly faster on startup (depending on the size of the jar) than running from an unexploded archive. This is actually slightly faster on startup (depending on the size of the jar) than running from an unexploded archive.

View File

@ -22,7 +22,7 @@ The following example shows a typical `MANIFEST.MF` for an executable jar file:
[indent=0] [indent=0]
---- ----
Main-Class: org.springframework.boot.loader.JarLauncher Main-Class: org.springframework.boot.loader.launch.JarLauncher
Start-Class: com.mycompany.project.MyApplication Start-Class: com.mycompany.project.MyApplication
---- ----

View File

@ -132,7 +132,7 @@ The printed banner is registered as a singleton bean under the following name: `
The `${application.version}` and `${application.formatted-version}` properties are only available if you are using Spring Boot launchers. The `${application.version}` and `${application.formatted-version}` properties are only available if you are using Spring Boot launchers.
The values will not be resolved if you are running an unpacked jar and starting it with `java -cp <classpath> <mainclass>`. The values will not be resolved if you are running an unpacked jar and starting it with `java -cp <classpath> <mainclass>`.
This is why we recommend that you always launch unpacked jars using `java org.springframework.boot.loader.JarLauncher`. This is why we recommend that you always launch unpacked jars using `java org.springframework.boot.loader.launch.JarLauncher`.
This will initialize the `application.*` banner variables before building the classpath and launching your app. This will initialize the `application.*` banner variables before building the classpath and launching your app.
==== ====

View File

@ -290,7 +290,7 @@ The following example shows how to build an executable archive with Ant:
</mappedresources> </mappedresources>
<zipfileset src="${lib.dir}/loader/spring-boot-loader-jar-${spring-boot.version}.jar" /> <zipfileset src="${lib.dir}/loader/spring-boot-loader-jar-${spring-boot.version}.jar" />
<manifest> <manifest>
<attribute name="Main-Class" value="org.springframework.boot.loader.JarLauncher" /> <attribute name="Main-Class" value="org.springframework.boot.loader.launch.JarLauncher" />
<attribute name="Start-Class" value="${start-class}" /> <attribute name="Start-Class" value="${start-class}" />
</manifest> </manifest>
</jar> </jar>

View File

@ -61,7 +61,7 @@
<zipfileset src="${destdir}/dependency/spring-boot-loader.jar" /> <zipfileset src="${destdir}/dependency/spring-boot-loader.jar" />
<manifest> <manifest>
<attribute name="Main-Class" <attribute name="Main-Class"
value="org.springframework.boot.loader.JarLauncher" /> value="org.springframework.boot.loader.launch.JarLauncher" />
<attribute name="Start-Class" value="${start-class}" /> <attribute name="Start-Class" value="${start-class}" />
<attribute name="Spring-Boot-Classes" value="BOOT-INF/classes/" /> <attribute name="Spring-Boot-Classes" value="BOOT-INF/classes/" />
<attribute name="Spring-Boot-Lib" value="BOOT-INF/lib/" /> <attribute name="Spring-Boot-Lib" value="BOOT-INF/lib/" />

View File

@ -66,7 +66,7 @@ task fullJar(type: Jar) {
} }
manifest { manifest {
attributes( attributes(
"Main-Class": "org.springframework.boot.loader.JarLauncher", "Main-Class": "org.springframework.boot.loader.launch.JarLauncher",
"Start-Class": "org.springframework.boot.cli.SpringCli" "Start-Class": "org.springframework.boot.cli.SpringCli"
) )
} }

View File

@ -59,7 +59,7 @@ set CMD_LINE_ARGS=%$
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%SPRING_HOME%\lib\* set CLASSPATH=%SPRING_HOME%\lib\*
"%JAVA_EXE%" %JAVA_OPTS% -cp "%CLASSPATH%" org.springframework.boot.loader.JarLauncher %CMD_LINE_ARGS% "%JAVA_EXE%" %JAVA_OPTS% -cp "%CLASSPATH%" org.springframework.boot.loader.launch.JarLauncher %CMD_LINE_ARGS%
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell

View File

@ -115,4 +115,4 @@ if $cygwin; then
fi fi
IFS=" " read -r -a javaOpts <<< "$JAVA_OPTS" IFS=" " read -r -a javaOpts <<< "$JAVA_OPTS"
exec "${JAVA_HOME}/bin/java" "${javaOpts[@]}" -cp "$CLASSPATH" org.springframework.boot.loader.JarLauncher "$@" exec "${JAVA_HOME}/bin/java" "${javaOpts[@]}" -cp "$CLASSPATH" org.springframework.boot.loader.launch.JarLauncher "$@"

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -33,7 +33,7 @@ import org.springframework.boot.loader.tools.JavaExecutable;
*/ */
class ForkProcessCommand extends RunProcessCommand { class ForkProcessCommand extends RunProcessCommand {
private static final String MAIN_CLASS = "org.springframework.boot.loader.JarLauncher"; private static final String MAIN_CLASS = "org.springframework.boot.loader.launch.JarLauncher";
private final Command command; private final Command command;

View File

@ -10,7 +10,7 @@ tasks.named("bootWar") {
// tag::properties-launcher[] // tag::properties-launcher[]
tasks.named("bootWar") { tasks.named("bootWar") {
manifest { manifest {
attributes 'Main-Class': 'org.springframework.boot.loader.PropertiesLauncher' attributes 'Main-Class': 'org.springframework.boot.loader.launch.PropertiesLauncher'
} }
} }
// end::properties-launcher[] // end::properties-launcher[]

View File

@ -12,7 +12,7 @@ tasks.named<BootWar>("bootWar") {
// tag::properties-launcher[] // tag::properties-launcher[]
tasks.named<BootWar>("bootWar") { tasks.named<BootWar>("bootWar") {
manifest { manifest {
attributes("Main-Class" to "org.springframework.boot.loader.PropertiesLauncher") attributes("Main-Class" to "org.springframework.boot.loader.launch.PropertiesLauncher")
} }
} }
// end::properties-launcher[] // end::properties-launcher[]

View File

@ -61,9 +61,9 @@ class BootArchiveSupport {
static { static {
Set<String> defaultLauncherClasses = new HashSet<>(); Set<String> defaultLauncherClasses = new HashSet<>();
defaultLauncherClasses.add("org.springframework.boot.loader.JarLauncher"); defaultLauncherClasses.add("org.springframework.boot.loader.launch.JarLauncher");
defaultLauncherClasses.add("org.springframework.boot.loader.PropertiesLauncher"); defaultLauncherClasses.add("org.springframework.boot.loader.launch.PropertiesLauncher");
defaultLauncherClasses.add("org.springframework.boot.loader.WarLauncher"); defaultLauncherClasses.add("org.springframework.boot.loader.launch.WarLauncher");
DEFAULT_LAUNCHER_CLASSES = Collections.unmodifiableSet(defaultLauncherClasses); DEFAULT_LAUNCHER_CLASSES = Collections.unmodifiableSet(defaultLauncherClasses);
} }

View File

@ -49,7 +49,7 @@ import org.gradle.work.DisableCachingByDefault;
@DisableCachingByDefault(because = "Not worth caching") @DisableCachingByDefault(because = "Not worth caching")
public abstract class BootJar extends Jar implements BootArchive { public abstract class BootJar extends Jar implements BootArchive {
private static final String LAUNCHER = "org.springframework.boot.loader.JarLauncher"; private static final String LAUNCHER = "org.springframework.boot.loader.launch.JarLauncher";
private static final String CLASSES_DIRECTORY = "BOOT-INF/classes/"; private static final String CLASSES_DIRECTORY = "BOOT-INF/classes/";

View File

@ -48,7 +48,7 @@ import org.gradle.work.DisableCachingByDefault;
@DisableCachingByDefault(because = "Not worth caching") @DisableCachingByDefault(because = "Not worth caching")
public abstract class BootWar extends War implements BootArchive { public abstract class BootWar extends War implements BootArchive {
private static final String LAUNCHER = "org.springframework.boot.loader.WarLauncher"; private static final String LAUNCHER = "org.springframework.boot.loader.launch.WarLauncher";
private static final String CLASSES_DIRECTORY = "WEB-INF/classes/"; private static final String CLASSES_DIRECTORY = "WEB-INF/classes/";

View File

@ -166,7 +166,7 @@ class PackagingDocumentationTests {
assertThat(file).isFile(); assertThat(file).isFile();
try (JarFile jar = new JarFile(file)) { try (JarFile jar = new JarFile(file)) {
assertThat(jar.getManifest().getMainAttributes().getValue("Main-Class")) assertThat(jar.getManifest().getMainAttributes().getValue("Main-Class"))
.isEqualTo("org.springframework.boot.loader.PropertiesLauncher"); .isEqualTo("org.springframework.boot.loader.launch.PropertiesLauncher");
} }
} }

View File

@ -270,7 +270,9 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
void loaderIsWrittenToTheRootOfTheJarWhenUsingThePropertiesLauncher() throws IOException { void loaderIsWrittenToTheRootOfTheJarWhenUsingThePropertiesLauncher() throws IOException {
this.task.getMainClass().set("com.example.Main"); this.task.getMainClass().set("com.example.Main");
executeTask(); executeTask();
this.task.getManifest().getAttributes().put("Main-Class", "org.springframework.boot.loader.PropertiesLauncher"); this.task.getManifest()
.getAttributes()
.put("Main-Class", "org.springframework.boot.loader.launch.PropertiesLauncher");
try (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) { try (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {
assertThat(jarFile.getEntry("org/springframework/boot/loader/LaunchedURLClassLoader.class")).isNotNull(); assertThat(jarFile.getEntry("org/springframework/boot/loader/LaunchedURLClassLoader.class")).isNotNull();
assertThat(jarFile.getEntry("org/springframework/boot/loader/")).isNotNull(); assertThat(jarFile.getEntry("org/springframework/boot/loader/")).isNotNull();
@ -362,7 +364,7 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
assertThat(jarFile.getManifest().getMainAttributes().getValue("Main-Class")) assertThat(jarFile.getManifest().getMainAttributes().getValue("Main-Class"))
.isEqualTo("com.example.CustomLauncher"); .isEqualTo("com.example.CustomLauncher");
assertThat(jarFile.getManifest().getMainAttributes().getValue("Start-Class")).isEqualTo("com.example.Main"); assertThat(jarFile.getManifest().getMainAttributes().getValue("Start-Class")).isEqualTo("com.example.Main");
assertThat(jarFile.getEntry("org/springframework/boot/loader/LaunchedURLClassLoader.class")).isNull(); assertThat(jarFile.getEntry("org/springframework/boot/loader/launch/LaunchedClassLoader.class")).isNull();
} }
} }

View File

@ -41,7 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat;
class BootJarTests extends AbstractBootArchiveTests<BootJar> { class BootJarTests extends AbstractBootArchiveTests<BootJar> {
BootJarTests() { BootJarTests() {
super(BootJar.class, "org.springframework.boot.loader.JarLauncher", "BOOT-INF/lib/", "BOOT-INF/classes/", super(BootJar.class, "org.springframework.boot.loader.launch.JarLauncher", "BOOT-INF/lib/", "BOOT-INF/classes/",
"BOOT-INF/"); "BOOT-INF/");
} }

View File

@ -39,7 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat;
class BootWarTests extends AbstractBootArchiveTests<BootWar> { class BootWarTests extends AbstractBootArchiveTests<BootWar> {
BootWarTests() { BootWarTests() {
super(BootWar.class, "org.springframework.boot.loader.WarLauncher", "WEB-INF/lib/", "WEB-INF/classes/", super(BootWar.class, "org.springframework.boot.loader.launch.WarLauncher", "WEB-INF/lib/", "WEB-INF/classes/",
"WEB-INF/"); "WEB-INF/");
} }

View File

@ -21,5 +21,5 @@ task explode(type: Sync) {
task launch(type: JavaExec) { task launch(type: JavaExec) {
classpath = files(explode) classpath = files(explode)
mainClass = 'org.springframework.boot.loader.JarLauncher' mainClass = 'org.springframework.boot.loader.launch.JarLauncher'
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2021 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -66,7 +66,7 @@ public final class Layouts {
@Override @Override
public String getLauncherClassName() { public String getLauncherClassName() {
return "org.springframework.boot.loader.JarLauncher"; return "org.springframework.boot.loader.launch.JarLauncher";
} }
@Override @Override
@ -108,7 +108,7 @@ public final class Layouts {
@Override @Override
public String getLauncherClassName() { public String getLauncherClassName() {
return "org.springframework.boot.loader.PropertiesLauncher"; return "org.springframework.boot.loader.launch.PropertiesLauncher";
} }
} }
@ -148,7 +148,7 @@ public final class Layouts {
@Override @Override
public String getLauncherClassName() { public String getLauncherClassName() {
return "org.springframework.boot.loader.WarLauncher"; return "org.springframework.boot.loader.launch.WarLauncher";
} }
@Override @Override

View File

@ -105,7 +105,7 @@ abstract class AbstractPackagerTests<P extends Packager> {
execute(packager, NO_LIBRARIES); execute(packager, NO_LIBRARIES);
Manifest actualManifest = getPackagedManifest(); Manifest actualManifest = getPackagedManifest();
assertThat(actualManifest.getMainAttributes().getValue("Main-Class")) assertThat(actualManifest.getMainAttributes().getValue("Main-Class"))
.isEqualTo("org.springframework.boot.loader.JarLauncher"); .isEqualTo("org.springframework.boot.loader.launch.JarLauncher");
assertThat(actualManifest.getMainAttributes().getValue("Start-Class")).isEqualTo("a.b.C"); assertThat(actualManifest.getMainAttributes().getValue("Start-Class")).isEqualTo("a.b.C");
assertThat(hasPackagedLauncherClasses()).isTrue(); assertThat(hasPackagedLauncherClasses()).isTrue();
} }
@ -121,7 +121,7 @@ abstract class AbstractPackagerTests<P extends Packager> {
execute(packager, NO_LIBRARIES); execute(packager, NO_LIBRARIES);
Manifest actualManifest = getPackagedManifest(); Manifest actualManifest = getPackagedManifest();
assertThat(actualManifest.getMainAttributes().getValue("Main-Class")) assertThat(actualManifest.getMainAttributes().getValue("Main-Class"))
.isEqualTo("org.springframework.boot.loader.JarLauncher"); .isEqualTo("org.springframework.boot.loader.launch.JarLauncher");
assertThat(actualManifest.getMainAttributes().getValue("Start-Class")).isEqualTo("a.b.C"); assertThat(actualManifest.getMainAttributes().getValue("Start-Class")).isEqualTo("a.b.C");
assertThat(hasPackagedLauncherClasses()).isTrue(); assertThat(hasPackagedLauncherClasses()).isTrue();
} }
@ -133,7 +133,7 @@ abstract class AbstractPackagerTests<P extends Packager> {
execute(packager, NO_LIBRARIES); execute(packager, NO_LIBRARIES);
Manifest actualManifest = getPackagedManifest(); Manifest actualManifest = getPackagedManifest();
assertThat(actualManifest.getMainAttributes().getValue("Main-Class")) assertThat(actualManifest.getMainAttributes().getValue("Main-Class"))
.isEqualTo("org.springframework.boot.loader.JarLauncher"); .isEqualTo("org.springframework.boot.loader.launch.JarLauncher");
assertThat(actualManifest.getMainAttributes().getValue("Start-Class")).isEqualTo("a.b.C"); assertThat(actualManifest.getMainAttributes().getValue("Start-Class")).isEqualTo("a.b.C");
assertThat(hasPackagedLauncherClasses()).isTrue(); assertThat(hasPackagedLauncherClasses()).isTrue();
} }
@ -684,7 +684,7 @@ abstract class AbstractPackagerTests<P extends Packager> {
protected boolean hasPackagedLauncherClasses() throws IOException { protected boolean hasPackagedLauncherClasses() throws IOException {
return hasPackagedEntry("org/springframework/boot/") return hasPackagedEntry("org/springframework/boot/")
&& hasPackagedEntry("org/springframework/boot/loader/JarLauncher.class"); && hasPackagedEntry("org/springframework/boot/loader/launch/JarLauncher.class");
} }
private boolean hasPackagedEntry(String name) throws IOException { private boolean hasPackagedEntry(String name) throws IOException {

View File

@ -79,7 +79,7 @@ class RepackagerTests extends AbstractPackagerTests<Repackager> {
repackager.repackage(NO_LIBRARIES); repackager.repackage(NO_LIBRARIES);
Manifest actualManifest = getPackagedManifest(); Manifest actualManifest = getPackagedManifest();
assertThat(actualManifest.getMainAttributes().getValue("Main-Class")) assertThat(actualManifest.getMainAttributes().getValue("Main-Class"))
.isEqualTo("org.springframework.boot.loader.JarLauncher"); .isEqualTo("org.springframework.boot.loader.launch.JarLauncher");
assertThat(actualManifest.getMainAttributes().getValue("Start-Class")).isEqualTo("a.b.C"); assertThat(actualManifest.getMainAttributes().getValue("Start-Class")).isEqualTo("a.b.C");
assertThat(hasPackagedLauncherClasses()).isTrue(); assertThat(hasPackagedLauncherClasses()).isTrue();
} }
@ -220,7 +220,7 @@ class RepackagerTests extends AbstractPackagerTests<Repackager> {
private boolean hasLauncherClasses(File file) throws IOException { private boolean hasLauncherClasses(File file) throws IOException {
return hasEntry(file, "org/springframework/boot/") return hasEntry(file, "org/springframework/boot/")
&& hasEntry(file, "org/springframework/boot/loader/JarLauncher.class"); && hasEntry(file, "org/springframework/boot/loader/launch/JarLauncher.class");
} }
private boolean hasEntry(File file, String name) throws IOException { private boolean hasEntry(File file, String name) throws IOException {

View File

@ -0,0 +1,34 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.loader.launch;
/**
* Repackaged {@link org.springframework.boot.loader.JarLauncher}.
*
* @author Phillip Webb
* @since 3.2.0
*/
public final class JarLauncher {
private JarLauncher() {
}
public static void main(String[] args) throws Exception {
org.springframework.boot.loader.JarLauncher.main(args);
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.loader.launch;
/**
* Repackaged {@link org.springframework.boot.loader.PropertiesLauncher}.
*
* @author Phillip Webb
* @since 3.2.0
*/
public final class PropertiesLauncher {
private PropertiesLauncher() {
}
public static void main(String[] args) throws Exception {
org.springframework.boot.loader.PropertiesLauncher.main(args);
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.loader.launch;
/**
* Repackaged {@link org.springframework.boot.loader.WarLauncher}.
*
* @author Phillip Webb
* @since 3.2.0
*/
public final class WarLauncher {
private WarLauncher() {
}
public static void main(String[] args) throws Exception {
org.springframework.boot.loader.WarLauncher.main(args);
}
}

View File

@ -0,0 +1,23 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Repackaged launcher classes.
*
* @see org.springframework.boot.loader.launch.JarLauncher
* @see org.springframework.boot.loader.launch.WarLauncher
*/
package org.springframework.boot.loader.launch;

View File

@ -57,7 +57,7 @@ class JarIntegrationTests extends AbstractArchiveIntegrationTests {
File repackaged = new File(project, "target/jar-0.0.1.BUILD-SNAPSHOT.jar"); File repackaged = new File(project, "target/jar-0.0.1.BUILD-SNAPSHOT.jar");
assertThat(launchScript(repackaged)).isEmpty(); assertThat(launchScript(repackaged)).isEmpty();
assertThat(jar(repackaged)).manifest((manifest) -> { assertThat(jar(repackaged)).manifest((manifest) -> {
manifest.hasMainClass("org.springframework.boot.loader.JarLauncher"); manifest.hasMainClass("org.springframework.boot.loader.launch.JarLauncher");
manifest.hasStartClass("some.random.Main"); manifest.hasStartClass("some.random.Main");
manifest.hasAttribute("Not-Used", "Foo"); manifest.hasAttribute("Not-Used", "Foo");
}) })
@ -66,7 +66,7 @@ class JarIntegrationTests extends AbstractArchiveIntegrationTests {
.hasEntryWithNameStartingWith("BOOT-INF/lib/spring-jcl") .hasEntryWithNameStartingWith("BOOT-INF/lib/spring-jcl")
.hasEntryWithNameStartingWith("BOOT-INF/lib/jakarta.servlet-api-6") .hasEntryWithNameStartingWith("BOOT-INF/lib/jakarta.servlet-api-6")
.hasEntryWithName("BOOT-INF/classes/org/test/SampleApplication.class") .hasEntryWithName("BOOT-INF/classes/org/test/SampleApplication.class")
.hasEntryWithName("org/springframework/boot/loader/JarLauncher.class"); .hasEntryWithName("org/springframework/boot/loader/launch/JarLauncher.class");
assertThat(buildLog(project)) assertThat(buildLog(project))
.contains("Replacing main artifact " + repackaged + " with repackaged archive,") .contains("Replacing main artifact " + repackaged + " with repackaged archive,")
.contains("The original artifact has been renamed to " + original) .contains("The original artifact has been renamed to " + original)
@ -273,9 +273,9 @@ class JarIntegrationTests extends AbstractArchiveIntegrationTests {
.goals("package", "-Dspring-boot.repackage.layout=ZIP") .goals("package", "-Dspring-boot.repackage.layout=ZIP")
.execute((project) -> { .execute((project) -> {
File main = new File(project, "target/jar-with-layout-property-0.0.1.BUILD-SNAPSHOT.jar"); File main = new File(project, "target/jar-with-layout-property-0.0.1.BUILD-SNAPSHOT.jar");
assertThat(jar(main)) assertThat(jar(main)).manifest(
.manifest((manifest) -> manifest.hasMainClass("org.springframework.boot.loader.PropertiesLauncher") (manifest) -> manifest.hasMainClass("org.springframework.boot.loader.launch.PropertiesLauncher")
.hasStartClass("org.test.SampleApplication")); .hasStartClass("org.test.SampleApplication"));
assertThat(buildLog(project)).contains("Layout: ZIP"); assertThat(buildLog(project)).contains("Layout: ZIP");
}); });
} }
@ -284,9 +284,9 @@ class JarIntegrationTests extends AbstractArchiveIntegrationTests {
void whenALayoutIsConfiguredTheSpecifiedLayoutIsUsed(MavenBuild mavenBuild) { void whenALayoutIsConfiguredTheSpecifiedLayoutIsUsed(MavenBuild mavenBuild) {
mavenBuild.project("jar-with-zip-layout").execute((project) -> { mavenBuild.project("jar-with-zip-layout").execute((project) -> {
File main = new File(project, "target/jar-with-zip-layout-0.0.1.BUILD-SNAPSHOT.jar"); File main = new File(project, "target/jar-with-zip-layout-0.0.1.BUILD-SNAPSHOT.jar");
assertThat(jar(main)) assertThat(jar(main)).manifest(
.manifest((manifest) -> manifest.hasMainClass("org.springframework.boot.loader.PropertiesLauncher") (manifest) -> manifest.hasMainClass("org.springframework.boot.loader.launch.PropertiesLauncher")
.hasStartClass("org.test.SampleApplication")); .hasStartClass("org.test.SampleApplication"));
assertThat(buildLog(project)).contains("Layout: ZIP"); assertThat(buildLog(project)).contains("Layout: ZIP");
}); });
} }

View File

@ -57,10 +57,10 @@ class WarIntegrationTests extends AbstractArchiveIntegrationTests {
.hasEntryWithNameStartingWith("WEB-INF/lib/spring-core") .hasEntryWithNameStartingWith("WEB-INF/lib/spring-core")
.hasEntryWithNameStartingWith("WEB-INF/lib/spring-jcl") .hasEntryWithNameStartingWith("WEB-INF/lib/spring-jcl")
.hasEntryWithNameStartingWith("WEB-INF/lib-provided/jakarta.servlet-api-6") .hasEntryWithNameStartingWith("WEB-INF/lib-provided/jakarta.servlet-api-6")
.hasEntryWithName("org/springframework/boot/loader/WarLauncher.class") .hasEntryWithName("org/springframework/boot/loader/launch/WarLauncher.class")
.hasEntryWithName("WEB-INF/classes/org/test/SampleApplication.class") .hasEntryWithName("WEB-INF/classes/org/test/SampleApplication.class")
.hasEntryWithName("index.html") .hasEntryWithName("index.html")
.manifest((manifest) -> manifest.hasMainClass("org.springframework.boot.loader.WarLauncher") .manifest((manifest) -> manifest.hasMainClass("org.springframework.boot.loader.launch.WarLauncher")
.hasStartClass("org.test.SampleApplication") .hasStartClass("org.test.SampleApplication")
.hasAttribute("Not-Used", "Foo"))); .hasAttribute("Not-Used", "Foo")));
} }

View File

@ -93,9 +93,10 @@ class PaketoBuilderTests {
.contains("paketo-buildpacks/ca-certificates", "paketo-buildpacks/bellsoft-liberica", .contains("paketo-buildpacks/ca-certificates", "paketo-buildpacks/bellsoft-liberica",
"paketo-buildpacks/executable-jar", "paketo-buildpacks/dist-zip", "paketo-buildpacks/executable-jar", "paketo-buildpacks/dist-zip",
"paketo-buildpacks/spring-boot"); "paketo-buildpacks/spring-boot");
metadata.processOfType("web").containsExactly("java", "org.springframework.boot.loader.JarLauncher"); metadata.processOfType("web")
.containsExactly("java", "org.springframework.boot.loader.launch.launch.JarLauncher");
metadata.processOfType("executable-jar") metadata.processOfType("executable-jar")
.containsExactly("java", "org.springframework.boot.loader.JarLauncher"); .containsExactly("java", "org.springframework.boot.loader.launch.launch.JarLauncher");
}); });
assertImageHasJvmSbomLayer(imageReference, config); assertImageHasJvmSbomLayer(imageReference, config);
assertImageHasDependenciesSbomLayer(imageReference, config, "executable-jar"); assertImageHasDependenciesSbomLayer(imageReference, config, "executable-jar");
@ -238,9 +239,10 @@ class PaketoBuilderTests {
.contains("paketo-buildpacks/ca-certificates", "paketo-buildpacks/bellsoft-liberica", .contains("paketo-buildpacks/ca-certificates", "paketo-buildpacks/bellsoft-liberica",
"paketo-buildpacks/executable-jar", "paketo-buildpacks/dist-zip", "paketo-buildpacks/executable-jar", "paketo-buildpacks/dist-zip",
"paketo-buildpacks/spring-boot"); "paketo-buildpacks/spring-boot");
metadata.processOfType("web").containsExactly("java", "org.springframework.boot.loader.WarLauncher"); metadata.processOfType("web")
.containsExactly("java", "org.springframework.boot.loader.launch.WarLauncher");
metadata.processOfType("executable-jar") metadata.processOfType("executable-jar")
.containsExactly("java", "org.springframework.boot.loader.WarLauncher"); .containsExactly("java", "org.springframework.boot.loader.launch.WarLauncher");
}); });
assertImageHasJvmSbomLayer(imageReference, config); assertImageHasJvmSbomLayer(imageReference, config);
assertImageHasDependenciesSbomLayer(imageReference, config, "executable-jar"); assertImageHasDependenciesSbomLayer(imageReference, config, "executable-jar");

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2021 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -55,8 +55,8 @@ class ExplodedApplicationLauncher extends AbstractApplicationLauncher {
@Override @Override
protected List<String> getArguments(File archive, File serverPortFile) { protected List<String> getArguments(File archive, File serverPortFile) {
String mainClass = (archive.getName().endsWith(".war") ? "org.springframework.boot.loader.WarLauncher" String mainClass = (archive.getName().endsWith(".war") ? "org.springframework.boot.loader.launch.WarLauncher"
: "org.springframework.boot.loader.JarLauncher"); : "org.springframework.boot.loader.launch.JarLauncher");
try { try {
explodeArchive(archive); explodeArchive(archive);
return Arrays.asList("-cp", this.exploded.getAbsolutePath(), mainClass, serverPortFile.getAbsolutePath()); return Arrays.asList("-cp", this.exploded.getAbsolutePath(), mainClass, serverPortFile.getAbsolutePath());

View File

@ -67,7 +67,7 @@
</mappedresources> </mappedresources>
<zipfileset src="${lib.dir}/loader/spring-boot-loader-jar-${ant-spring-boot.version}.jar" /> <zipfileset src="${lib.dir}/loader/spring-boot-loader-jar-${ant-spring-boot.version}.jar" />
<manifest> <manifest>
<attribute name="Main-Class" value="org.springframework.boot.loader.JarLauncher" /> <attribute name="Main-Class" value="org.springframework.boot.loader.launch.JarLauncher" />
<attribute name="Start-Class" value="${start-class}" /> <attribute name="Start-Class" value="${start-class}" />
</manifest> </manifest>
</jar> </jar>