Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support application images with jlink #24889

Closed
nipafx opened this issue Jan 19, 2021 · 8 comments
Closed

Support application images with jlink #24889

nipafx opened this issue Jan 19, 2021 · 8 comments

Comments

@nipafx
Copy link

nipafx commented Jan 19, 2021

I'm working on a small Spring Boot app and would like to create a self-contained application image with jlink.

  • Java 16
  • Spring Boot 2.4.2

What I tried

I tried several different approaches, but all of them failed.

Proper module-info.java

My first try was to create my own module-info.java, but that gets moved into the fat JAR's root without further changes. That means it still lists the Spring modules as dependencies, but since they're now included in the JAR, they won't be found on any module path and thus jlink refuses to create the image.

There are hacky ways around that (creating empty JARs with the right module names), but I suspect this would lead to the same problems as the next approach.

Using Moditect on fat JAR

With Moditect, I can inject a module declaration into the fat JAR. That's actually pretty easy because there are no external dependencies.

Unfortunately, jlink refuses to create the image because of the BOOT-INF folder:

[INFO] --- moditect-maven-plugin:1.0.0.RC1:create-runtime-image (create-runtime-image) @ calendar ---
[ERROR] Error: java.lang.IllegalArgumentException: BOOT-INF.classes.dev.nipafx.calendar.spring:
        Invalid package name: 'BOOT-INF' is not a Java identifier

(I expect the approach above would fail at this step as well even if the problem with the module descriptor could be solved.)

Using Moditext on all JARs

I considered configuring Spring Boot to not create a fat JAR. My goal was to then use Moditect to create a module descriptor for all (transitive) dependencies of the app and thus use jlink on all of them. This may work, but due to the sheer number of dependencies and my (possibly faulty) impression that I need to configure the declaration for all of them. That's a lot of work.

Conclusion

It seems that there's no (good) way to create an application image that contains a Spring Boot app. That's a shame because that's a pretty nifty feature. It would be nice if Spring Boot offered at least one path to application image heaven. 😁

@nipafx nipafx changed the title Support appl Support application images with jlink Jan 19, 2021
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jan 19, 2021
@philwebb philwebb added the for: team-meeting An issue we'd like to discuss as a team to make progress label Jan 19, 2021
@wilkinsona
Copy link
Member

@nipafx Have you tried using Maven's shade plugin to build the jar and then pointing jlink at that? It would remove the problem created by BOOT-INF while also avoiding the need to deal with all of the dependencies.

@wilkinsona wilkinsona added the status: waiting-for-feedback We need additional information before we can continue label Jan 19, 2021
@nipafx
Copy link
Author

nipafx commented Jan 20, 2021

Thanks for the quick reply, I will try that.

I assume there's a reason, why Spring Boot doesn't just shade. Ignoring the module stuff, are there any complications I should expect with this approach? A quick Google search shows a few hits, but no official documentation. If you have an authoritative source for this, it would be greatly appreciated. 😃

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Jan 20, 2021
@wilkinsona
Copy link
Member

There's a little bit in the reference documentation about some limitations of shading.

spring-boot-starter-parent contains some configuration for Maven's Shade plugin that you can use in your app. Here's an example pom that uses this configuration:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.4.2</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>shaded</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>shaded</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>1.8</java.version>
		<start-class>com.example.shaded.ShadedApplication</start-class>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-shade-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

Note the start-class property and the declaration of the maven-shade-plugin. package will now build a shaded jar that can be executed with java -jar.

@wilkinsona wilkinsona added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Jan 20, 2021
@philwebb philwebb removed the for: team-meeting An issue we'd like to discuss as a team to make progress label Jan 20, 2021
@spring-projects-issues
Copy link
Collaborator

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

@spring-projects-issues spring-projects-issues added the status: feedback-reminder We've sent a reminder that we need additional information before we can continue label Jan 27, 2021
@spring-projects-issues
Copy link
Collaborator

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.

@spring-projects-issues spring-projects-issues removed status: waiting-for-feedback We need additional information before we can continue status: feedback-reminder We've sent a reminder that we need additional information before we can continue status: waiting-for-triage An issue we've not yet triaged labels Feb 3, 2021
@dwhitla

This comment has been minimized.

@wilkinsona

This comment has been minimized.

@jordanst3wart
Copy link

So this seems to work:

jdeps -s target/$FAT_JAR # look at JVM dependencies

jlink --output app --add-modules java.logging,java.base # found with jdeps -s

# copy app into image
mkdir app/jars
cp target/$FAT_JAR app/jars/app.jar

# launch
app/bin/java -cp app/jars/app.jar org.springframework.boot.loader.JarLauncher

That's from the article by @nipafx
https://medium.com/nipafx-news/jlinked-spring-boot-packages-vs-folders-king-kong-7035e6543ec4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants