Spring Boot基于控制台的应用程序是如何工作的?

47

如果我正在开发一个相对简单的基于Spring Boot的控制台应用程序,我不确定主要执行代码的位置。我应该将其放在public static void main(String[] args) 方法中还是让主应用程序类实现CommandLineRunner 接口并将代码放在run(String... args) 方法中?

我将使用一个示例作为上下文。假设我有以下[基本]应用程序(使用接口编码、Spring方式):

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(接口)

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

GreeterServiceImpl.java(实现类)

@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;
  }
}

Application.java的Spring Boot版本相当于以下内容: GreeterServiceImpl.java(实现类)

@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?
    }
}

3
使用CommandLineRunner,它的设计目的就是这样,您还可以创建一个实例,并将依赖项注入其中。在第一个场景中,这种方法会失败,因为您无法注入依赖项或无法从静态方法中访问它。 - M. Deinum
@M.Deinum,所以基于控制台的应用程序通常必须实现CommandLineRunner接口作为一个经验法则?这对我来说提供了足够的清晰度,因为即使文档没有专注于这一点(可能是因为大多数人都隐含地知道!)。 - Web User
3
最好创建一个实现该接口的Bean(而不是您的Application类)。这涉及到关注点分离(启动应用程序和执行逻辑的分离)。 - M. Deinum
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Web User
我承认没有阅读API,所以CommandLineRunner接口可以被任何需要在Spring应用程序中运行的bean使用。我错误地认为它的目的与在命令行上运行应用程序密切相关。鉴于使用服务处理命令行参数的基本要求,开发Spring Boot应用程序的推荐方法是什么?如果是这样,那么一个Spring Boot应用程序必须有一个带有main方法的类吗?如果是这样,那么Application将只做这些。 - Web User
显示剩余3条评论
1个回答

63

你应该使用标准的加载器:

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

实现一个带有@Component注解的CommandLineRunner接口

Translated sentence:

Implement a CommandLineRunner interface with @Component annotation

    @Component
    public class MyRunner implements CommandLineRunner {

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

      }
   }

@EnableAutoConfiguration将执行通常的SpringBoot魔法。

更新:

如@jeton所建议,最新的Springboot实现了一个简单的:

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

请参阅72.2处的文档


5
你认为使用Spring Boot实现CLI应用程序的正确方式是什么?CommandLineRunnerApplicationRunner不仅适用于CLI应用程序。此外,当你使用它们之一时,Spring在启动main方法之前执行其各自的run方法,这可以从记录消息INFO 6961 --- [ restartedMain] org.behrang.rpn.Main : Started Main in XX.YYY seconds (JVM running for MM.NNN)中看出,在执行CommandLineRunner.run(...)方法中的代码后出现该消息。 - Behrang
4
那么正确的做法是什么? - Sam
1
@Wesam 很不幸,我不知道有什么优雅的方法可以做到这一点。这里是一个可能的解决方案:https://gist.github.com/behrangsa/6a7f050e7f6d193918ad7e910812fb28 - Behrang
2
@Behrang 这个答案提供了实现这个功能的正确方法。我刚刚建议编辑添加了一个指向官方示例的链接: https://github.com/spring-projects/spring-boot/tree/v1.4.2.RELEASE/spring-boot-samples/spring-boot-sample-simple - mdjnewman
spring.main.web-environment=false spring.main.banner-mode=off请参见72.2 https://docs.spring.io/spring-boot/docs/current/reference/html/howto-properties-and-configuration.html - jeton
2
在Spring Boot 2中,它是 spring.main.web-application-type=none - Zafar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接