1. Getting Started
To see what Spring Shell has to offer, we can write a trivial hello world shell application that has a simple argument.
| Spring Shell is based on Spring Boot 3.0.1 and Spring Framework 6.0.3 and thus requires JDK 17. |
1.1. Creating a Project
For the purpose of this tutorial, we create a simple Spring Boot application by
using https://start.spring.io where you can choose Spring Shell dependency.
This minimal application depends only on spring-boot-starter and
spring-shell-starter.
Spring Shell version on start.spring.io is usually latest release.
|
With maven you’re expected to have something like:
<properties>
<spring-shell.version>3.0.0-RC1</spring-shell.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-shell-starter</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.shell</groupId>
<artifactId>spring-shell-dependencies</artifactId>
<version>${spring-shell.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
With gradle you’re expected to have something like:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.shell:spring-shell-starter'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
dependencyManagement {
imports {
mavenBom "org.springframework.shell:spring-shell-dependencies:3.0.0-RC1"
}
}
Given that Spring Shell starts the REPL (Read-Eval-Print-Loop) because this
dependency is present, you need to either skip tests when you build (-DskipTests)
throughout this tutorial or remove the sample integration test that was generated
by https://start.spring.io. If you do not remove it, the integration test creates
the Spring ApplicationContext and, depending on your build tool, stays stuck in
the eval loop or crashes with a NPE.
|
Once compiled it can be run either in interactive mode:
$ $JAVA_HOME/bin/java -jar demo-0.0.1-SNAPSHOT.jar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.0.1)
2022-09-13T18:42:12.818+01:00 INFO 12644 --- [ main] com.example.demo.DemoApplication
: Starting DemoApplication using Java 17.0.4 on ...
2022-09-13T18:42:12.821+01:00 INFO 12644 --- [ main] com.example.demo.DemoApplication
: No active profile set, falling back to 1 default profile: "default"
2022-09-13T18:42:13.606+01:00 INFO 12644 --- [ main] com.example.demo.DemoApplication
: Started DemoApplication in 1.145 seconds (process running for 1.578)
shell:>help
AVAILABLE COMMANDS
Built-In Commands
help: Display help about available commands
stacktrace: Display the full stacktrace of the last error.
clear: Clear the shell screen.
quit, exit: Exit the shell.
history: Display or save the history of previously run commands
version: Show version info
script: Read and execute commands from a file.
Or in non-interactive mode:
$JAVA_HOME/bin/java -jar demo-0.0.1-SNAPSHOT.jar help
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.0.1)
2022-09-13T18:42:12.818+01:00 INFO 12644 --- [ main] com.example.demo.DemoApplication
: Starting DemoApplication using Java 17.0.4 on ...
2022-09-13T18:42:12.821+01:00 INFO 12644 --- [ main] com.example.demo.DemoApplication
: No active profile set, falling back to 1 default profile: "default"
2022-09-13T18:42:13.606+01:00 INFO 12644 --- [ main] com.example.demo.DemoApplication
: Started DemoApplication in 1.145 seconds (process running for 1.578)
AVAILABLE COMMANDS
Built-In Commands
help: Display help about available commands
stacktrace: Display the full stacktrace of the last error.
clear: Clear the shell screen.
quit, exit: Exit the shell.
history: Display or save the history of previously run commands
version: Show version info
script: Read and execute commands from a file.
| Check out [using-shell-customization-logging] making logging to work better with shell apps. |
1.2. Your First Command
Now we can add our first command. To do so, create a new class (named whatever you want) and
annotate it with @ShellComponent which is a variation of @Component that is used to restrict
the set of classes that are scanned for candidate commands.
Then we can create a helloWorld method that takes String as an argument and
returns it with "Hello world". Add @ShellMethod and optionally change command name
using key parameter. You can use @ShellOption to define argument default value
if it’s not given when running a command.
package com.example.demo;
import org.springframework.shell.standard.ShellComponent;
import org.springframework.shell.standard.ShellMethod;
import org.springframework.shell.standard.ShellOption;
@ShellComponent
public class MyCommands {
@ShellMethod(key = "hello-world")
public String helloWorld(
@ShellOption(defaultValue = "spring") String arg
) {
return "Hello world " + arg;
}
}
New hello-world command becomes visible to help:
My Commands
hello-world:
And you can run it:
shell:>hello-world
Hello world spring
shell:>hello-world --arg boot
Hello world boot
The rest of this document delves deeper into the whole Spring Shell programming model.