Search code examples
spring-bootmavenmainclass

How to execute a separated Main method from a Spring boot repackaged Jar


How to execute a separated Main method from a Spring boot repackaged Jar

A classic Java Spring boot app, after execute maven package, it will generate a repackaged executable jar. There are two jar files:a-spring-boot-demo-1.0.0.jar & a-spring-boot-demo-1.0.0.jar.original

I add another new main class to the source code, is it possible to execute the main class from the jar? I didn’t change the maven build process.

The re-packaged Jar is like below:

a-spring-boot-demo-1.0.0.jar
   - BOOT-INF
     - classes
       - com
         - my
           - demo
             - MyNewConsole.class  # my new main class
       - user defined classes here
         ……
     - lib
       — the third party dependency jar here
   - META-INF 
     …………  # default files generated by Spring-boot-maven-plugin
   - org
     - springframework
       …. # default files generated by Spring-boot-maven-plugin
   

I want to execute the main in MyNewConsole I run on Windows in the project root directory:

java -cp .\target\a-spring-boot-demo-1.0.0.jar com.my.demo.MyNewConsole

It reported the error: Could not find or load main class com.my.demo.MyNewConsole

I run:

java -cp .\target\a-spring-boot-demo-1.0.0.jar.original com.my.demo.MyNewConsole

It reported: Exception in thread ‘main’ java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory

I know it can’t find the lib, so I tried to include the lib in jar:

java -cp .\target\a-spring-boot-demo-1.0.0.jar.original;.\target\a-spring-boot-demo-1.0.0.jar.original:BOOT-INF/lib/* com.my.demo.MyNewConsole

It still reported NoClassDefFoundError, What should I do to run my separated main class?


Solution

  • It is possible and can be done with the following command:

    java -cp .\target\a-spring-boot-demo-1.0.0.jar -Dloader.main=com.my.demo.MyNewConsole org.springframework.boot.loader.PropertiesLauncher

    This is a bit of a workaround as can be seen from the following discussion

    A different option would be, as suggested in the same discussion, to keep it simple and just add an if statement to the Spring main class that calls the correct class based on whatever logic:

    public static void main(String[] args) {
        if (TRUE.toString().equalsIgnoreCase(System.getProperties().getProperty("foo"))) {
            MyNewConsole.main(args);
        } else {
            SpringApplication.run(SomeOtherApplication.class, args);
        }
    }