Spring Boot - How to specify an alternate start-class? (Multiple Entry Points)

14,237

Solution 1

I don't believe that property would apply in your case. There are 3 different "Launchers" (go back to the docs and see). If you are building a jar it uses the JarLauncher class. If you switch it to PropertiesLauncher then loader.main would be useful.

META-INF/MANIFEST.MF

Main-Class: org.springframework.boot.loader.PropertiesLauncher

Solution 2

I took a different approach and use a command line parameter to determine which class to use as my SpringApplication class. I only have a single main() method, but different Application classes with different configurations that are used based on a command line param.

I have a single class with a main() in it:

public static void main(String[] args) {
    SpringApplication app;
    if( ArrayUtils.contains(args, "--createdb")){
        app = new SpringApplication(CreateDB.class);
        args = (String[])ArrayUtils.add(args, "--spring.jpa.hibernate.ddl-auto=create");
    } else {
        app = new SpringApplication(Application.class);
    }

    app.setWebEnvironment(false);
    app.setShowBanner(false);
    app.addListeners(new ConfigurationLogger());

    // launch the app
    ConfigurableApplicationContext context = app.run(args);

    // finished so close the context
    context.close();
}

But I have 2 different SpringApplication classes: Application.class & CreateDB.class. Each class defines a different @ComponentScan path as well as different @EnableAutoConfiguration options and different @Configuration options. Finally, based on my command line arguments, I can decide whether to programatically enable additional profiles/etc.

In my case, I want a different launcher to just create the DB schema and exit, so I've forced the command line parameter.

Solution 3

I would suggest having a single main but using Spring profiles (or configuration properties) to select one or other "entry point" @Configuration class.

Share:
14,237

Related videos on Youtube

The Gilbert Arenas Dagger
Author by

The Gilbert Arenas Dagger

Updated on September 15, 2022

Comments

  • The Gilbert Arenas Dagger
    The Gilbert Arenas Dagger over 1 year

    I want to add an alternate entry point to my Spring-Boot application. I would prefer to keep this as a fat jar. Is this possible?

    According to their documentation, the property loader.main specifies the name of the main class to launch.

    I tried java -jar MyJar.jar --loader.main=com.mycompany.AlternateMain but the start-class specified in my pom.xml was still run (and if I remove this from the pom.xml then I error during the packaging).

    Alternatively, I tried java -cp MyJar.jar com.mycompany.AlternateMain but I don't know of a good way to add all the nested jars to the classpath.

    Any suggestions?

    Edit: Here is the solution that I used

    As jst suggested, I changed my launcher to use the PropertiesLauncher. I did this by modifying the configuration of my spring-boot-maven-plugin.

    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <configuration>
        <mainClass>${start-class}</mainClass>
        <layout>ZIP</layout>
        ...
    

    The <layout>ZIP</layout> triggers Spring Boot to use the PropertiesLauncher.

    I created my fat jar (mvn package) then called the alternate main like this:

    java -jar -Dloader.main=com.mycompany.AlternateMain MyJar.jar
    

    Thanks for the help!

    • FGreg
      FGreg almost 9 years
      Spring Boot simply uses the JAR's Manifest to specify the main class and classpath. So I think the real question here is can there be more than one Main Class in an executable JAR? That question is also asked/answered here: stackoverflow.com/q/3976514/953327
    • Makoto
      Makoto almost 9 years
      What are you intending to accomplish with this? Do you want to create multiple applications from within Spring Boot?
    • The Gilbert Arenas Dagger
      The Gilbert Arenas Dagger almost 9 years
      @FGreg I can access the alternate main using the second command that I noted, which matches the answer in the SO thread you link to. In order to use this successfully, I would have to figure out how to add my nested jars to the classpath.
    • The Gilbert Arenas Dagger
      The Gilbert Arenas Dagger almost 9 years
      @Makoto I do not want to create multiple applications with this. It's actually a proof of concept that I am doing now, but I have used multiple entry points in the past for a variety of reasons
  • The Gilbert Arenas Dagger
    The Gilbert Arenas Dagger almost 9 years
    This sounds very promising, but my results are the same. To use the PropertiesLauncher, I configured the spring-boot-maven-plugin, as described here stackoverflow.com/a/21328440/2860319. I could see in my manifest that it worked and the PropertiesLauncher was now being used, but the loader.main property specified via command line did not change the start-class... hmmmm
  • The Gilbert Arenas Dagger
    The Gilbert Arenas Dagger almost 9 years
    I was adding the properties incorrectly, I'll update my post with what I did. Thanks for the great suggestion!
  • ben3000
    ben3000 over 8 years
    This is where I was heading too, presumably CreateDB and Application exist in separate packages, thus enabling you to use @ComponentScan with basePackages set to that package?
  • Eric B.
    Eric B. over 8 years
    Indeed that is possible. In my case, they are actually in the same package, but my @ComponentScan() explicity sets different base packages to scan with different exclusion rules. It also allows you to have different @AutoConfiguration() options, different Config classes, etc. And quite frankly - I find it much easier to do this way than to use the launcher and launcher parameters to specify long class names; this allows me to abstract it any way I want. I've basically packaged 2 separate SpringBoot apps (which share common classes) in the same jar.
  • rmv
    rmv almost 7 years
    Can you provide an example, please?