简体   繁体   中英

Java Modules - Simple Spring Boot application, create custom runtime

I created a simple Spring Boot application using start.spring.io with Maven , Java 19 , Spring Boot 3.0

I added just one additional dependency, commons-lang3

pom.xml
<?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>3.0.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>19</java.version>
    </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>
        
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

When NetBeans 15 builds the project, there is a target folder containing the jar file demo-0.0.1-SNAPSHOT.jar

I can run that jar with

java -jar target/demo-0.0.1-SNAPSHOT.jar

I can see my output and the Spring Boot logo and it terminates.

java -jar target/demo-0.0.1-SNAPSHOT.jar 

MIX

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.0.0)

2022-11-30T19:47:53.468+01:00  INFO 18179 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication v0.0.1-SNAPSHOT using Java 19.0.1 with PID 18179 (/home/me/NetBeansProjects/demo/target/demo-0.0.1-SNAPSHOT.jar started by neblaz in /home/me/NetBeansProjects/demo)
2022-11-30T19:47:53.470+01:00  INFO 18179 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to 1 default profile: "default"
2022-11-30T19:47:54.131+01:00  INFO 18179 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 1.172 seconds (process running for 1.666)

The main class is simple

package com.example.demo;

import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        String mix = "MIX";
        if (StringUtils.isNoneBlank(mix)) {
            System.out.println(mix);
        }
        SpringApplication.run(DemoApplication.class, args);
    }

}

Now I want to create a minimized custom runtime image with jlink to run that jar file with it.

I found this article https://medium.com/azulsystems/using-jlink-to-build-java-runtimes-for-non-modular-applications-9568c5e70ef4 but cannot figure it out.

With jdeps I get some not fully understandable output

jdeps target/demo-0.0.1-SNAPSHOT.jar
demo-0.0.1-SNAPSHOT.jar -> java.base
demo-0.0.1-SNAPSHOT.jar -> java.logging
demo-0.0.1-SNAPSHOT.jar -> not found
   com.example.demo                                   -> java.io                                            java.base
   com.example.demo                                   -> java.lang                                          java.base
   com.example.demo                                   -> org.apache.commons.lang3                           not found
   com.example.demo                                   -> org.springframework.boot                           not found
   com.example.demo                                   -> org.springframework.boot.autoconfigure             not found
   com.example.demo                                   -> org.springframework.context                        not found
   org.springframework.boot.loader                    -> java.io                                            java.base
   org.springframework.boot.loader                    -> java.lang                                          java.base
   org.springframework.boot.loader                    -> java.lang.invoke                                   java.base
   org.springframework.boot.loader                    -> java.lang.reflect                                  java.base
   org.springframework.boot.loader                    -> java.net                                           java.base
   org.springframework.boot.loader                    -> java.nio.charset                                   java.base
   org.springframework.boot.loader                    -> java.security                                      java.base
   org.springframework.boot.loader                    -> java.util                                          java.base
   org.springframework.boot.loader                    -> java.util.function                                 java.base
   org.springframework.boot.loader                    -> java.util.jar                                      java.base
   org.springframework.boot.loader                    -> java.util.regex                                    java.base
   org.springframework.boot.loader                    -> java.util.stream                                   java.base
   org.springframework.boot.loader                    -> java.util.zip                                      java.base
   org.springframework.boot.loader                    -> org.springframework.boot.loader.archive            demo-0.0.1-SNAPSHOT.jar
   org.springframework.boot.loader                    -> org.springframework.boot.loader.jar                demo-0.0.1-SNAPSHOT.jar
   org.springframework.boot.loader                    -> org.springframework.boot.loader.util               demo-0.0.1-SNAPSHOT.jar
   org.springframework.boot.loader.archive            -> java.io                                            java.base
   org.springframework.boot.loader.archive            -> java.lang                                          java.base
   org.springframework.boot.loader.archive            -> java.lang.invoke                                   java.base
   org.springframework.boot.loader.archive            -> java.net                                           java.base
   org.springframework.boot.loader.archive            -> java.nio.file                                      java.base
   org.springframework.boot.loader.archive            -> java.nio.file.attribute                            java.base
   org.springframework.boot.loader.archive            -> java.util                                          java.base
   org.springframework.boot.loader.archive            -> java.util.function                                 java.base
   org.springframework.boot.loader.archive            -> java.util.jar                                      java.base
   org.springframework.boot.loader.archive            -> java.util.zip                                      java.base
   org.springframework.boot.loader.archive            -> org.springframework.boot.loader.jar                demo-0.0.1-SNAPSHOT.jar
   org.springframework.boot.loader.data               -> java.io                                            java.base
   org.springframework.boot.loader.data               -> java.lang                                          java.base
   org.springframework.boot.loader.jar                -> java.io                                            java.base
   org.springframework.boot.loader.jar                -> java.lang                                          java.base
   org.springframework.boot.loader.jar                -> java.lang.invoke                                   java.base
   org.springframework.boot.loader.jar                -> java.lang.ref                                      java.base
   org.springframework.boot.loader.jar                -> java.lang.reflect                                  java.base
   org.springframework.boot.loader.jar                -> java.net                                           java.base
   org.springframework.boot.loader.jar                -> java.nio.charset                                   java.base
   org.springframework.boot.loader.jar                -> java.security                                      java.base
   org.springframework.boot.loader.jar                -> java.security.cert                                 java.base
   org.springframework.boot.loader.jar                -> java.time                                          java.base
   org.springframework.boot.loader.jar                -> java.time.temporal                                 java.base
   org.springframework.boot.loader.jar                -> java.util                                          java.base
   org.springframework.boot.loader.jar                -> java.util.concurrent                               java.base
   org.springframework.boot.loader.jar                -> java.util.function                                 java.base
   org.springframework.boot.loader.jar                -> java.util.jar                                      java.base
   org.springframework.boot.loader.jar                -> java.util.logging                                  java.logging
   org.springframework.boot.loader.jar                -> java.util.regex                                    java.base
   org.springframework.boot.loader.jar                -> java.util.stream                                   java.base
   org.springframework.boot.loader.jar                -> java.util.zip                                      java.base
   org.springframework.boot.loader.jar                -> org.springframework.boot.loader.data               demo-0.0.1-SNAPSHOT.jar
   org.springframework.boot.loader.jarmode            -> java.io                                            java.base
   org.springframework.boot.loader.jarmode            -> java.lang                                          java.base
   org.springframework.boot.loader.jarmode            -> java.lang.invoke                                   java.base
   org.springframework.boot.loader.jarmode            -> java.util                                          java.base
   org.springframework.boot.loader.jarmode            -> org.springframework.core.io.support                not found
   org.springframework.boot.loader.jarmode            -> org.springframework.util                           not found
   org.springframework.boot.loader.util               -> java.io                                            java.base
   org.springframework.boot.loader.util               -> java.lang                                          java.base
   org.springframework.boot.loader.util               -> java.lang.invoke                                   java.base
   org.springframework.boot.loader.util               -> java.util                                          java.base

I understand that the application uses the Java modules java.base and java.logging , but sometimes not found and sometimes the jar file are give as modules.

Trying jlink like

jlink --module-path $JAVA_HOME/jmods --add-modules java.base,java.logging --output mycustomrt

creates the custom runtime image, but running it with

mycustomrt/bin/java -jar target/demo-0.0.1-SNAPSHOT.jar

results in

19:08:07.912 [main] ERROR org.springframework.boot.SpringApplication - Application run failed
java.lang.NoClassDefFoundError: java/beans/PropertyEditorSupport
        at java.base/java.lang.ClassLoader.defineClass1(Native Method)
        at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1013)
        at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
        at java.base/java.net.URLClassLoader.defineClass(URLClassLoader.java:524)
        at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:427)
        at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:421)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
        at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:420)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
        at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:149)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
        at org.springframework.boot.context.properties.bind.BindConverter$TypeConverterConverter.<clinit>(BindConverter.java:180)
        at org.springframework.boot.context.properties.bind.BindConverter$TypeConverterConversionService.<init>(BindConverter.java:157)
        at org.springframework.boot.context.properties.bind.BindConverter.<init>(BindConverter.java:63)
        at org.springframework.boot.context.properties.bind.BindConverter.getSharedInstance(BindConverter.java:133)
        at org.springframework.boot.context.properties.bind.BindConverter.get(BindConverter.java:126)
        at org.springframework.boot.context.properties.bind.Binder.<init>(Binder.java:190)
        at org.springframework.boot.context.properties.bind.Binder.<init>(Binder.java:160)
        at org.springframework.boot.context.properties.bind.Binder.<init>(Binder.java:139)
        at org.springframework.boot.context.properties.bind.Binder.get(Binder.java:531)
        at org.springframework.boot.context.properties.bind.Binder.get(Binder.java:516)
        at org.springframework.boot.context.config.ConfigDataEnvironment.<init>(ConfigDataEnvironment.java:141)
        at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.getConfigDataEnvironment(ConfigDataEnvironmentPostProcessor.java:101)
        at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:96)
        at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:89)
        at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:109)
        at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:94)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:131)
        at org.springframework.boot.context.event.EventPublishingRunListener.multicastInitialEvent(EventPublishingRunListener.java:136)
        at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:81)
        at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:64)
        at java.base/java.lang.Iterable.forEach(Iterable.java:75)
        at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118)
        at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:112)
        at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:63)
        at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:352)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291)
        at com.example.demo.DemoApplication.main(DemoApplication.java:18)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
        at java.base/java.lang.reflect.Method.invoke(Method.java:578)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:95)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65)
Caused by: java.lang.ClassNotFoundException: java.beans.PropertyEditorSupport
        at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
        at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:149)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
        ... 49 common frames omitted

The jlink command seems not to be fully correct, don't know how to specify it correctly.

Looking into the demo-0.0.1-SNAPSHOT.jar file I see that all necessary jars are

BOOT-INF
   classpath.idx
   layers.idx
   lib/commons-lang3-3.12.0.jar
   lib/spring-boot-3.0.0.jar
   lib/...

Can you try with adding this as vm argument:

--add-modules java.xml,java.sql,java.prefs,java.desktop

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM