args
配列にはアプリケーション起動時に指定された引数が格納されています。
つまり下記のように引数を与えて実行した場合
java -jar ./path/to/consuming-rest-0.0.1-SNAPSHOT.jar aaa bbb ccc
args
配列には3つの文字列が格納されています。
試しに以下のようにlogを出力するコードを追加してみると(1),(2)の順番でログに出力されていると思います。
java
1public static void main(String[] args) {
2 // (1)
3 log.info(Arrays.toString(args));
4 SpringApplication.run(ConsumingRestApplication.class, args);
5}
java
1return args -> {
2 // (2)
3 log.info(Arrays.toString(args));
4 Quote quote = restTemplate.getForObject(
5 "https://gturnquist-quoters.cfapps.io/api/random", Quote.class);
6 log.info(quote.toString());
7};
Spring Bootに限らず、Javaのプログラムは引数を与えるとmainメソッドのargs
で受け取ります。
その引数をSpring Bootアプリケーション内で利用するために、さらに下記のようにして持ちまわしています。
java
1// (3) アプリケーション実行時の引数を持ちまわす
2SpringApplication.run(ConsumingRestApplication.class, args);
それを確認するには、下記のようにmainメソッド内で別の配列を定義して実行してみます。すると(2)の部分ではこのnewArgs
配列の値が出力されたと思います。
java
1String[] newArgs = {"ddd", "eee", "fff"};
2SpringApplication.run(ConsumingRestApplication.class, newArgs);
argsはラムダ式の引数に該当すると思われますが
蛇足ですが、この部分は従来の書き方をすると以下のようになります。
このCommandLineRunnerインターフェースを実装したインスタンスのrunメソッドには、Spring Bootによって(3)の部分で指定したargs
が渡されます。
java
1return new CommandLineRunner() {
2 @Override
3 public void run(String... args) throws Exception {
4 Quote quote = restTemplate.getForObject(
5 "https://gturnquist-quoters.cfapps.io/api/random", Quote.class);
6 log.info(quote.toString());
7 }
8};
2020/06/06 追記
一点のみどうしても疑問があるのですが、元コードの「run」メソッドの引数「args」はメソッド内で一度も使用されていないにも関わらず、記載されているのは何故
元コードというのは下記のことだと思いますが、端的に言うと引数args
が記載されているのはCommandLineRunner
インターフェースを実装しているからであり、引数を使用していないのはサンプルコード上必要がなかったから、ということではないでしょうか?
java
1return args -> {
2 Quote quote = restTemplate.getForObject(
3 "https://gturnquist-quoters.cfapps.io/api/random", Quote.class);
4 log.info(quote.toString());
5};
以下はCommandLineRunner
インターフェースのコードです。このインターフェースを実装するということはvoid run(String... args) throws Exception
をオーバーライドする必要があるということです。
java
1@FunctionalInterface
2public interface CommandLineRunner {
3
4 678
9 void run(String... args) throws Exception;
10
11}
このインターフェースを実装したクラスのコードは例えば以下のようになります。このようにrunメソッドをオーバーライドして、Springアプリケーションの起動時に実行したい処理を記述します。
java
1@Component
2public class CustomRunner implements CommandLineRunner {
3 private static final Logger log = LoggerFactory.getLogger(CustomRunner.class);
4
5 private final RestTemplate restTemplate;
6
7 public CustomRunner(RestTemplate restTemplate) {
8 this.restTemplate = restTemplate;
9 }
10
11 @Override
12 public void run(String... args) throws Exception {
13 log.info(Arrays.toString(args));
14 Quote quote = restTemplate.getForObject(
15 "https://gturnquist-quoters.cfapps.io/api/random", Quote.class);
16 log.info("2nd : {}", quote.toString());
17 }
18
19}
runメソッドの引数を使う必要がないからといって以下のようにオーバーライドしてもコンパイルエラーになります。なぜならこれではCommandLineRunner
インターフェースを実装していることにならないからです。
java
1@Override
2public void run() throws Exception {
3
4 // 省略
5
6}
ちなみに、引数を使うように実装するのであれば、以下のようにすることもできます。
サンプルコードで使用しているAPIのhttps://gturnquist-quoters.cfapps.io/api/random
は、randomの部分を任意の数値に変えると、それがID指定になります。
たとえば、https://gturnquist-quoters.cfapps.io/api/10
でリクエストすると、以下のjsonがレスポンスされます。
json
1{
2 "type":"success",
3 "value":{
4 "id":10,
5 "quote":"Really loving Spring Boot, makes stand alone Spring apps easy."
6 }
7}
このように実装すると(引数のチェックをしていないので例は悪いですが)、アプリケーション実行時の引数にIDを指定することができるようになります。
java
1return args -> {
2 String id = args[0];
3 Quote quote = restTemplate.getForObject(
4 "https://gturnquist-quoters.cfapps.io/api/" + id, Quote.class);
5 log.info(quote.toString());
6};
2020/06/07 追記
「Quote quote = restTemplate.getForObject(」こちらの行から読み取れるに、「Quote」型の変数を返しているということではないのでしょうか...?
すでに回答に記載していますがCommandLineRunner
インターフェースのrunメソッドのシグネチャは以下の通りです。
このように戻り値の型がvoidとなっているのでrunメソッドは何も返しません。args
という文字列の配列を引数に取り(それを使うかどうかは別として)実装した処理を実行する(Springフレームワークが)だけです。
java
1void run(String... args) throws Exception;
なので
「Quote」型の変数を返している
ということではありません。
以下が参考にされているページのオリジナルコードですが、このrunメソッド内でreturnしているのはラムダ式で書かれたCommandLineRunner
インターフェースを実装したクラス(匿名クラス、無名クラスとも)のインスタンスです。
java
1@Bean
2public CommandLineRunner run(RestTemplate restTemplate) throws Exception {
3
4 return args -> {
5 Quote quote = restTemplate.getForObject(
6 "https://gturnquist-quoters.cfapps.io/api/random", Quote.class);
7 log.info(quote.toString());
8 };
9
10}
上記の書き方を少し冗長化すると下記のようになります。returnはCommandLineRunner
型の変数runnerを返していることが分かりやすくなったかとおもいます。
ラムダ式について少し触れておくと、args -> { ... }
は、args
がメソッドの引数で、-> { ... }
がメソッドの本体ということになります。
java
1@Bean
2public CommandLineRunner run(RestTemplate restTemplate) throws Exception {
3
4 CommandLineRunner runner;
5
6 runner = args -> {
7 Quote quote = restTemplate.getForObject(
8 "https://gturnquist-quoters.cfapps.io/api/random", Quote.class);
9 log.info(quote.toString());
10 };
11
12 return runner;
13}
上記の書き方をラムダ式を使わずに記述すると下記のようになります。
これはいわゆるラムダ式導入以前の匿名クラス(無名クラス)を利用している書き方です。runner変数には匿名クラスのインスタンスが代入され、それがreturnされています。
さらにオーバーライドしたrunメソッドが何もreturnしていないことがわかると思います。
java
1@Bean
2public CommandLineRunner run(RestTemplate restTemplate) throws Exception {
3
4 CommandLineRunner runner = new CommandLineRunner() {
5 @Override
6 public void run(String... args) throws Exception {
7 Quote quote = restTemplate.getForObject(
8 "https://gturnquist-quoters.cfapps.io/api/random", Quote.class);
9 log.info(quote.toString());
10 }
11 };
12
13 return runner;
14}
上記の書き方は匿名クラスを使った例ですが、下記のように書くこともできます。
java
1public class CustomRunner implements CommandLineRunner {
2 private static final Logger log = LoggerFactory.getLogger(CustomRunner.class);
3
4 private final RestTemplate restTemplate;
5
6 public CustomRunner(RestTemplate restTemplate) {
7 this.restTemplate = restTemplate;
8 }
9
10 @Override
11 public void run(String... args) throws Exception {
12 Quote quote = restTemplate.getForObject(
13 "https://gturnquist-quoters.cfapps.io/api/random", Quote.class);
14 log.info(quote.toString());
15 }
16
17}
これでCommandLineRunner
インターフェースを実装したクラスのインスタンスを返していることがわかるでしょうか?
java
1@Bean
2public CommandLineRunner run(RestTemplate restTemplate) throws Exception {
3
4 CommandLineRunner runner = new CustomRunner(restTemplate);
5
6 return runner;
7}
すでに説明したと思いますが、returnしたインスタンスのrunメソッドは、アプリケーション起動時にSpringフレームワークによって実行されます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/06/06 02:15 編集
2020/06/06 11:42
2020/06/07 01:20 編集
2020/06/07 12:37 編集
2020/06/07 08:05 編集
2020/06/07 12:39
2020/06/08 14:31 編集