只需要一种选项,以下是原生的中文改写:使用Spring Boot可以启动CLI应用程序
总结
我曾经利用Spring开发了一个基于Web的应用程序,但现在需要开发一个不使用Spring Web的批处理应用程序,因为在批处理应用程序中无法找到处理DI容器的方法,所以决定写这篇文章作为备忘录。
这篇文章的目标
利用Spring Initializr 创建的新项目中,实现一个具有以下功能的命令行应用程序。
-
- 実行時に引数を受け取り、指定の機能を実行することができる。
- CLIアプリケーションでSpringのBeanを利用する。
环境
-
- Java 11
-
- Spring Boot 2.4.3
- Pleiades All in One Eclipse 2020-12
一部分的依存关系
对于Maven项目来说,pom.xml的编写是必要的。
<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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
如果是Gradle项目,则build.gradle文件中的描述是。
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}
都是使用Spring Initializr创建的。
之后将在Eclipse中导入该项目并进行开发。
关于这次制作的内容
创建的应用程序将接受一个启动参数作为名称,并在控制台上向接收到的名称打招呼。如果没有接收到参数,则输出“Hello World!”。
为了使应用程序正常工作,我们将在启动时使用application.properties禁用Spring Boot的启动横幅。
此外,本次控制台输出使用了Logback。
各项设置如下所示。
spring.main.banner-mode = off
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<logger name="console-logger">
<appender-ref ref="STDOUT" />
</logger>
</configuration>
文件层次结构
CliApplication
├ src/main/java
│ └ com.example
│ ├ controller
│ │ └ CliController.java
│ ├ service
│ │ ├ CliService.java
│ │ └ CliServiceImpl.java
│ └ CliApplication.java
└ src/main/resources
├ application.properties
└ logback.xml
Cli应用
├ src/main/java
│ └ com.example
│ ├ 控制器
│ │ └ CliController.java
│ ├ 服务
│ │ ├ CliService.java
│ │ └ CliServiceImpl.java
│ └ CliApplication.java
└ src/main/resources
├ application.properties
└ logback.xml
执行
虽然前面有很长的引言,但首先具有main方法的类如下所示。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import com.example.controller.CliController;
@SpringBootApplication
public class CliApplication {
private final static Logger logger = LoggerFactory.getLogger("console-logger");
public static void main(String[] args) {
logger.info("処理開始!");
try (ConfigurableApplicationContext ctx = SpringApplication.run(CliApplication.class, args)) {
CliController controller = ctx.getBean(CliController.class);
controller.process(args);
} catch(Exception e) {
e.printStackTrace();
}
logger.info("処理終了!");
}
}
非常重要的部分是通过 “ConfigurableApplicationContext ctx = SpringApplication.run(CliApplication.class, args)” 来创建 Spring 的 DI Container。
对于 Web 应用程序,当服务器启动时,Bean 会被创建并处于等待状态,以便随时使用。
然而,如果像这次一样,开始后不处于等待状态,即使调用也会出现 NullPointerException,所以需要自己准备使用 DI Container。
通过这样做,就可以使用在 CliApplication.java 包下定义的 Bean,并通过 “ctx.getBean(CliController.class)” 来调用控制器。
try-with-resource 语句块是为了在主类执行后准备使用 DI Container,并在处理完成后将其关闭。
然后,每个控制器类和服务类如下所示。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import com.example.service.CliService;
@Controller
public class CliController {
@Autowired
private CliService service;
public void process(String[] args) {
if (args.length == 0) {
service.greeting();
} else {
service.greeting(args[0]);
}
}
}
public interface CliService {
public void greeting();
public void greeting(String arg);
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@Service
public class CliServiceImpl implements CliService {
private final static Logger logger = LoggerFactory.getLogger("console-logger");
public void greeting() {
logger.info("Hello! World!");
}
public void greeting(String arg) {
logger.info(String.format("Hello! %s!", arg));
}
}
在Controller类中,不像在主类中那样调用ConfigurableApplicationContext ctx = SpringApplication.run(CliController.class, args),这是因为这样的写法会创建一个依赖注入容器。但是,由于已经在上面的包中创建了一个已存在的依赖注入容器,再次创建一个重复的依赖注入容器是没有必要的。
在主类中准备使用依赖注入容器,并在该范围内调用它,这时候处于所谓的等待状态。因此,在这里使用@Autowired可以使用Bean。
确认动作
如果不带参数启动上述项目,输出如下:
処理開始!
Hello! World!
処理終了!
而且,如果把参数设为“Nobunaga”,输出结果将如下所示。
処理開始!
Hello! Nobunaga!
処理終了!
这个处理非常简单,所以在这方面我没有特别的说明。
这次我们没有处理启动选项,所以在使用Eclipse运行时,请注意在运行配置中取消勾选ANSI控制台输出的复选框,否则会显示”Hello! –spring.output.ansi.enabled=always!”。
