47

If I am developing a rather simple Spring Boot console-based application, I am unsure about the placement of the main execution code. Should I place it in the public static void main(String[] args) method, or have the main application class implement the CommandLineRunner interface and place the code in the run(String... args) method?

I will use an example as the context. Say I have the following [rudimentary] application (coded to interfaces, Spring style):

Application.java

public class Application {

  @Autowired
  private GreeterService greeterService;

  public static void main(String[] args) {
    // ******
    // *** Where do I place the following line of code
    // *** in a Spring Boot version of this application?
    // ******
    System.out.println(greeterService.greet(args));
  }
}

GreeterService.java (interface)

public interface GreeterService {
  String greet(String[] tokens);
}

GreeterServiceImpl.java (implementation class)

@Service
public class GreeterServiceImpl implements GreeterService {
  public String greet(String[] tokens) {

    String defaultMessage = "hello world";

    if (args == null || args.length == 0) {
      return defaultMessage;
    }

    StringBuilder message = new StringBuilder();
    for (String token : tokens) {
      if (token == null) continue;
      message.append(token).append('-');
    }

    return message.length() > 0 ? message.toString() : defaultMessage;
  }
}

The equivalent Spring Boot version of Application.java would be something along the lines: GreeterServiceImpl.java (implementation class)

@EnableAutoConfiguration
public class Application
    // *** Should I bother to implement this interface for this simple app?
    implements CommandLineRunner {

    @Autowired
    private GreeterService greeterService;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
        System.out.println(greeterService.greet(args)); // here?
    }

    // Only if I implement the CommandLineRunner interface...
    public void run(String... args) throws Exception {
        System.out.println(greeterService.greet(args)); // or here?
    }
}
u-ways
  • 6,136
  • 5
  • 31
  • 47
Web User
  • 7,438
  • 14
  • 64
  • 92
  • 3
    Use a `CommandLineRunner` that is what is it designed for, you can also create an instance of it and have dependencies injected into it. This would fail in your first scenario as you would not have a dependency injected or wouldn't be able to access it from the static method. – M. Deinum Jan 28 '15 at 19:27
  • @M.Deinum so such console-based applications must implement the CommandLineRunner interface as a general rule of thumb? That provides sufficient clarity for me, because even the docs don't focus on this point (probably because it is implicit to most folks!). – Web User Jan 28 '15 at 19:46
  • 3
    Well you ideally create a bean which implements this interface (and not your `Application` class). It has to do with separation of concerns (starting your application and executing your logic). – M. Deinum Jan 28 '15 at 19:54
  • Are you referring to the `GreeterService` [implementation] bean? Because my `Application` class only uses this service. So there is a separation of concern at this point already, no? – Web User Jan 28 '15 at 19:58
  • No I'm not referring to that. You are, for some reading, keep mentioning that you want your `Application` class to implement the `CommandLineRunner` interface. You probably don't want this but do that in a separate class instead. – M. Deinum Jan 28 '15 at 20:04
  • I'm guilty of not reading the API, so `CommandLineRunner` interface can be used by any bean that needs to run when contained within a Spring application. I was incorrectly presuming that its purpose it closely related to running an application on the command line. Given the basic requirement of using the service to process the command line arguments, what is the recommended approach to develop the Spring Boot application? Am I correct in saying that a Spring Boot application _must_ have a class with a main method? If so, that is all `Application` will do. – Web User Jan 28 '15 at 20:13
  • Correct. Like any other application you run from the command line you have to have a class with a `public static void main` else it won't run. – M. Deinum Jan 28 '15 at 20:20
  • @M.Deinum Please consider creating an answer out of your comments, as things you have pointed out are very helpfull and deserve an upvote and perhaps an accept. – Jacek Prucia Mar 10 '15 at 12:54

1 Answers1

63

You should have a standard loader:

@SpringBootApplication
public class MyDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyDemoApplication.class, args);
    }
}

and implement a CommandLineRunner interface with @Component annotation

    @Component
    public class MyRunner implements CommandLineRunner {

       @Override    
       public void run(String... args) throws Exception {

      }
   }

@EnableAutoConfiguration will do the usual SpringBoot magic.

UPDATE:

As @jeton suggests the latest Springboot implements a straight:

spring.main.web-application-type=none
spring.main.banner-mode=off

See docs at 72.2

blacktide
  • 10,654
  • 8
  • 33
  • 53
lrkwz
  • 6,105
  • 3
  • 36
  • 59
  • 5
    Why do you think this is the proper way to implement a CLI application using Spring Boot? `CommandLineRunner` and `ApplicationRunner` are not only meant to be used for CLI apps. Plus, when you use either of them, Spring executes its respective `run` method before starting the `main` method of your app as evident by the log message `INFO 6961 --- [ restartedMain] org.behrang.rpn.Main : Started Main in XX.YYY seconds (JVM running for MM.NNN)` appearing after the code in your `CommandLineRunner.run(...)` method is executed. – Behrang Feb 27 '16 at 17:03
  • 4
    @Behrang So what's the proper way to do it then? – Sam Oct 22 '16 at 02:57
  • 1
    @Wesam Unfortunately there's not an elegant way to do this that I know of. Here's a possible solution: https://gist.github.com/behrangsa/6a7f050e7f6d193918ad7e910812fb28 – Behrang Oct 24 '16 at 09:52
  • 2
    @Behrang this answer gives the correct way to implement this functionality. I've just suggested an edit to add a link to the official sample: https://github.com/spring-projects/spring-boot/tree/v1.4.2.RELEASE/spring-boot-samples/spring-boot-sample-simple – mdjnewman Nov 14 '16 at 10:59
  • spring.main.web-environment=false spring.main.banner-mode=off Please see 72.2 https://docs.spring.io/spring-boot/docs/current/reference/html/howto-properties-and-configuration.html – jeton Jul 25 '17 at 13:41
  • 2
    In springboot 2 it is `spring.main.web-application-type=none` – Zafar Feb 19 '21 at 02:28