Spring BootでConfigurableApplicationContextを使ってみる

f:id:ts0818:20210723174824j:plain

www.itmedia.co.jp

 米Alphabet傘下の英DeepMindが、遺伝子配列情報からタンパク質の立体構造を解析するAI「AlphaFold v2.0」(以下、AlphaFold2)をGitHub上で無償公開し、ネット上で注目を集めている。Twitterを利用する生物系の研究者からは「革命的な成果だ」「これからの研究の前提が変わっていく」など、AlphaFold2の予測精度に対して驚きの声が相次いだ。

「6年解けなかった構造があっさり」──タンパク質の“形”を予測する「AlphaFold2」の衝撃 GitHubで公開、誰でも利用可能に - ITmedia NEWS

 ただし、AlphaFoldを利用するには428GBのファイルをダウンロードする必要があり、解凍後のファイル容量は2.2TBにもなるため、利用にはそれなりの保存容量や計算スペックを持ったPCが必要になる。一方で、ブラウザ上の実行環境である「Google Colaboratory」上で動かせる簡易版も有志のユーザーの手によって公開されている。一部仕様は異なるが、こちらはハイスペックなPCを用意しなくても利用できる。

「6年解けなかった構造があっさり」──タンパク質の“形”を予測する「AlphaFold2」の衝撃 GitHubで公開、誰でも利用可能に - ITmedia NEWS

格差社会~、お金を持ってる研究機関にとっては朗報ですかね。

というか、

 タンパク質の構造をAIで解析する取り組みに関しては、奇しくも同じ7月15日に、ワシントン大学の研究チームが、別の構造解析AI「RoseTTAFold」を無償公開。同日付で科学論誌「Science」に論文が掲載された。

「6年解けなかった構造があっさり」──タンパク質の“形”を予測する「AlphaFold2」の衝撃 GitHubで公開、誰でも利用可能に - ITmedia NEWS

jp.techcrunch.com

2020年末、DeepMindディープマインド)は、同社のAIモデルAlphaFold2(アルファフォールド2)がタンパク質の構造を正確に予測(一般的で非常に難しい問題だ)することで生物学界を驚かせた。数十年来の問題を「解決できた」と多くの人が宣言したからだ。今回研究者たちは、このときDeepMindが世界を飛び越えてみせたように、今度はRoseTTAFold(ロゼッタフォールド)でDeepMindを飛び越えたと主張している。RoseTTAFoldは、わずかな計算コストでほぼ同じことを行うシステムだ(しかも無料で使用できる)

DeepMindのAlphaFold2に匹敵するより高速で自由に利用できるタンパク質フォールディングモデルを研究者が開発 | TechCrunch Japan

⇧「RoseTTAFold」ってほうは、計算コストが抑えられるんだそうな。

www.ipd.uw.edu

⇧ 上記サイト様で、論文のリンクも掲載してくれてる模様。

いやはや、「深層学習(Deep Learning)」の世界は、日進月歩が凄まじいことになってきてますな。

脱線しましたが、今回は、JavaフレームワークSpring Frameworkの機能をチョイスして利用していく、Spring Bootについてです。

レッツトライ~。 

 

Spring Bootとは?

公式の説明によると、

spring.io

Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run".

We take an opinionated view of the Spring platform and third-party libraries so you can get started with minimum fuss. Most Spring Boot applications need minimal Spring configuration.

https://spring.io/projects/spring-boot#overview

⇧ ってな感じで、 滅茶苦茶にイメージし辛いんだけど、

ブログの情報によると、 

spring.io

The primary goals of Spring Boot are:

  • To provide a radically faster and widely accessible ‘getting started’ experience for all Spring development
  • To be opinionated out of the box, but get out of the way quickly as requirements start to diverge from the defaults
  • To provide a range of non-functional features that are common to large classes of projects (e.g. embedded servers, security, metrics, health checks, externalized configuration)

Spring Boot does not generate code and there is absolutely no requirement for XML configuration.

https://spring.io/blog/2013/08/06/spring-boot-simplifying-spring-for-everyone/

⇧ ってな感じで、「Spring Framework」の機能を自由に選んで素早く開発できるし、何と言っても、「XML(Extensible Markup Language)」の煩わしい設定が不要ですと。

 

ConfigurableApplicationContextって何ぞ?

これといった説明がドキュメントに見当たらなかったので、APIドキュメントを確認してみたところ、 

spring.pleiades.io

public interface ConfigurableApplicationContext
extends ApplicationContext, Lifecycle, Closeable

すべてではないにしても、ほとんどのアプリケーションコンテキストによって実装される SPI インターフェース。ApplicationContext インターフェースのアプリケーションコンテキストクライアントメソッドに加えて、アプリケーションコンテキストを構成する機能を提供します。

https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ConfigurableApplicationContext.html

ApplicationContext クライアントコードでわかりやすくなるのを避けるために、構成およびライフサイクルメソッドはここにカプセル化されます。現在のメソッドは、起動コードとシャットダウンコードでのみ使用する必要があります。 

https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ConfigurableApplicationContext.html

⇧ 曖昧な表現この上ないんだが...

SPIインターフェイスの「SPI」っていうのは、

サービス・プロバイダ・インターフェース:Service Provider Interface, :SPI)は、ソフトウェアコンポーネントの置き換えを可能にする仕組み。

サービス・プロバイダ・インターフェース - Wikipedia

⇧ ってことらしいのではないか、たぶん...。

 で、話を「ConfigurableApplicationContext」に戻すと、「org.springframework.context」に含まれるインタフェースの中の1つが「ConfigurableApplicationContext」らしい。

spring.pleiades.io

パッケージ org.springframework.context の説明

このパッケージは、beans パッケージに基づいて構築され、メッセージソースと Observer デザインパターンのサポート、および一貫性のある API を使用してリソースを取得するアプリケーションオブジェクトの機能を追加します。

https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/context/package-summary.html#package.description

Spring アプリケーションが ApplicationContext または BeanFactory の機能に明示的に依存する必要はありません。Spring アーキテクチャの長所の 1 つは、Spring 固有の API に依存せずにアプリケーションオブジェクトを構成できることが多いことです。

https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/context/package-summary.html#package.description

⇧ 分かり辛い...

バージョンが3.0.0.M3 っていう旧いドキュメントによると(最新のドキュメントだとイメージ図が記載されていないため)、

The Context module build on the solid base provided by the Core and Beans modules: it provides a way to access objects in a framework-style manner in a fashion somewhat reminiscent of a JNDI-registry. The Context module inherits its features from the Beans module and adds support for internationalization (I18N) (using for example resource bundles), event-propagation, resource-loading, and the transparent creation of contexts by, for example, a servlet container. The Context module also contains support for some Java EE features like EJB, JMX and basic remoting support.

https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch01s02.html

⇧「Context module」モジュール(「org.springframework.context」パッケージに含まれるモジュールと推測)は、「Core and Beans modules」を提供しますとあって、

The Core and Beans modules provide the most fundamental parts of the framework and provides the IoC and Dependency Injection features. The basic concept here is the BeanFactory, which provides a sophisticated implementation of the factory pattern which removes the need for programmatic singletons and allows you to decouple the configuration and specification of dependencies from your actual program logic.

https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch01s02.html

⇧「Core and Beans modules」はというと、「IoC(Inversion of Control)」と「DI(Dependency Injection)」なんかを提供しますと。

なんですが、

docs.spring.io

⇧ ん?

 「IoC(Inversion of Control)」=「DI(Dependency Injection)」

と言ってるように見えるんだが...

The org.springframework.beans and org.springframework.context packages are the basis for Spring Framework’s IoC container. The BeanFactory interface provides an advanced configuration mechanism capable of managing any type of object.

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans

ApplicationContext is a sub-interface of BeanFactory. It adds:

  • Easier integration with Spring’s AOP features

  • Message resource handling (for use in internationalization)

  • Event publication

  • Application-layer specific contexts such as the WebApplicationContext for use in web applications.

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans

⇧「org.springframework.context」パッケージってのは、「IoC(Inversion of Control) Container」を実現するためのベースの1つと言ってますね。

「BeanFactory」インターフェイスが、あらゆるタイプのオブジェクト管理する、となっていて、「ApplicationContext」は「BeanFactory」のサブインターフェイスですと。

そして、

⇧ 上図の「The Spring Container」の部分を構成するために必要なモジュール群をまとめたものが「org.springframework.context」パッケージですと。 

公式の情報ではないんですが、UML図を公開してくれてる方がおりましたので、確認してみたところ、

programmersought.com

www.programmersought.com

⇧ 上図のUMLが正しいという前提の話となりますが、「ConfigurableApplicationContext」を利用しないと、

  • FileSystemXmlApplicationContext
  • ClassPathXmlApplicationContext
  • AnnotationConfigApplicationContext

が利用できないということになり、「IoC(Inversion of Control) Container」を構成するための「Configuration Metadata」が使えないことになるので、「Spring Framework」の機能が利用できなくなるのではないかと推測いたします。

ちなみに、「Spring Boot」でアプリケーションを作る場合、デフォルトで「@SpringBootApplication」 ってアノテーションがアプリケーションの実行クラスに付与されるっぽいのですが、「@SpringBootApplication」には、

  • @SpringBootConfiguration
  • @EnableAutoConfiguration
  • @ComponentScan(excludeFilters={@Filter(type=CUSTOM, classes={TypeExcludeFilter.class}), @Filter(type=CUSTOM, classes={AutoConfigurationExcludeFilter.class})})
  • @Target(value={TYPE})
  • @Retention(value=RUNTIME)
  • @Documented
  • @Inherited

が含まれてるらしく、「@EnableAutoConfiguration」 のAPIドキュメントを見てみると、

Spring アプリケーションコンテキストの自動構成を有効にし、必要となる可能性のある Bean を推測および構成しようとします。通常、自動構成クラスは、クラスパスと定義した Bean に基づいて適用されます。例: tomcat-embedded.jar がクラスパスにある場合、TomcatServletWebServerFactory が必要になる可能性があります(独自の ServletWebServerFactory Bean を定義していない場合)。

https://spring.pleiades.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/EnableAutoConfiguration.html

⇧ となっているので、「クラスパス」に含まれるライブラリなんかを「Spring Framework」で利用できるようにしてくれるってことなんですかね?

 

改めて、ConfigurableApplicationContextって何ぞ?

IoC(Inversion of Control) Container」を実現するためのベースとなるパッケージが、 

  • org.springframework.beans
  • org.springframework.context

の2つということらしいのと、「Configuration Metadata」を実現しているであろうと思われる、

  • FileSystemXmlApplicationContext
  • ClassPathXmlApplicationContext
  • AnnotationConfigApplicationContext

の3つのクラスの親の親クラス「AbstractApplicationContext」の親クラスが「ConfigurableApplicationContext」ってことらしいので、「Spring Framework」のあらゆる機能を利用するために必要なクラスってことになるんですかね? 

Spring Framework」は、「IoC(Inversion of Control) Container」に登録されてる「Bean」経由で機能を利用しているっぽいので。 

 

@Componentと@Beanの違いって?

Spring Framework」は、「IoC(Inversion of Control) Container」に「Bean」を登録してるってことなんだけど、その「Bean」を登録する方法ってのが「Spring Boot」の場合は、「AnnotationConfigApplicationContext」で「Configuration Metadata」を定義して実施してるんじゃないかと思うんですが、公式のAPIドキュメントによりますと、

docs.spring.io

Standalone application context, accepting component classes as input — in particular @Configuration-annotated classes, but also plain @Component types and JSR-330 compliant classes using javax.inject annotations.

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/AnnotationConfigApplicationContext.html

In case of multiple @Configuration classes, @Bean methods defined in later classes will override those defined in earlier classes. This can be leveraged to deliberately override certain bean definitions via an extra @Configuration class.

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/AnnotationConfigApplicationContext.html

⇧ 説明を読んだ感じでは、

あたりの「アノテーション」が付いたクラスを「Spring Framework」で利用できる「Bean」として登録できるってことなのかね? 

当然、気になってくるのが、登録される順番の優先度とかよね。 

teratail.com

■@Bean
@Configurationがあるクラスに記述する。
メソッドに対してつけて戻り値はnew?

■@component
クラス名のところに記述すればOK

上記であれば全て@componentを利用すればいいのでは?と思ってしまいます。

Spring - Springフレームワーク@Beanと@componentの違い|teratail

⇧ 同じような疑問を抱いている方がおられました。

で、その回答として、

@BeanはもともとSpringの設定ファイル(applicationContext.xml)で管理しているクラスを定義する <bean>を、アノテーションで定義するのと同じもので、Springの動作とともに作られるもので、SpringBootでも @Configulation にて関連した @Bean が起動します。

Spring - Springフレームワーク@Beanと@componentの違い|teratail

対して @Componentは、Springのcomponent-scanと呼ばれる、特定のパッケージ&パッケージ以下にある SpringFrameworkのコンポーネントアノテーションがついたものを、@Autowiredでインスタンスを取得できます。

Spring - Springフレームワーク@Beanと@componentの違い|teratail

Springからインスタンスを取得して利用する分にはどちらも大きな差がありませんが、Spring起動時に設定する内容を取り込むのは @Bean で定義したクラスの役割で、@Componentなどのクラスは、実際にアプリケーションが動作してからロジックで使うものです。

Spring - Springフレームワーク@Beanと@componentの違い|teratail

⇧ ってな違いで、「Bean」として登録される順番としては、「@Bean」が一番早いってことみたいですね。

 

実際に実装してみる

というわけで、実際に実装してみますか。

github.com

⇧ 恒例の、上記サイト様のお題で。

qiita.com

qiita.com

⇧ 上記サイト様を参考にさせていただきました。

「Spring Boot」のバージョンによって、

qiita.com

Spring Boot 2.2.1で挙動が変わりました。
https://github.com/spring-projects/spring-boot/issues/18674
デフォルトでは@ConfigurationPropertiesはスキャンされません(@Component必要です)
@ConfigurationPropertiesScanでスキャンされます。

Spring Boot 2.2系で@ConfigurationPropertiesを使う - Qiita

@ConstructorBindingを使う場合は@Componentではダメで、@ConfigurationPropertiesScanまたは@EnableConfigurationPropertiesが必要です。
https://docs.spring.io/spring-boot/docs/2.2.x/reference/html/spring-boot-features.html#boot-features-external-config-constructor-binding

Spring Boot 2.2系で@ConfigurationPropertiesを使う - Qiita

⇧「プロパティファイル」を扱う方法が二転三転してる感が何とも...

利用者に優しくないな~。

今回は、「Spring Boot」のバージョンとしては、「2.5.0」なんだけど、何か変更あるのかね?

 Eclipseを起動し、「ファイル(F)」>「その他(O)...」を選択。

f:id:ts0818:20210609152500p:plain

「Spring Boot」>「Spring スターター・プロジェクト」を選択。

f:id:ts0818:20210609152804p:plain

「名前」を適当に入力し、「型:」で「Gradle(Buildship 3.x)」を選択。(「型:」は「ビルドツール」のことだと思われますが、自分の環境では選べるのは、「Maven」「Gradle(Buildship 2.x)」「Gradle(Buildship 3.x)」の3つになってました。)

f:id:ts0818:20210609153229p:plain

今回は、依存関係に何も追加しない状態で、「完了(F)」を押下。

f:id:ts0818:20210609153329p:plain

「パッケージ・エクスプローラー」に「Spring スターター・プロジェクト」が作成されてます。

f:id:ts0818:20210609153945p:plain

 で、Eclipseで「Spring スターター・プロジェクト」が利用してる「Gradle」ってのが、

f:id:ts0818:20210611202053p:plain
⇧「/[プロジェクト名]/gradle/wrapper/gradle-wrapper.properties」に記載されてるらしく、「プロパティ(R)」から確認できるファイルの配置場所にアクセスして、ファイルを開いてみると、

f:id:ts0818:20210611202351p:plain

f:id:ts0818:20210611201402p:plain

⇧「GRADLE_USER_HOME」の「wrapper/dists」ってフォルダに配置されるっぽい。

f:id:ts0818:20210611201624p:plain

で、Winodws環境だと、自分で「Gradle」をインストールしちゃったりなんかしてる場合、「環境変数」に「Gradle」のパスを通しちゃったりしてると、コマンドプロンプトなんかで「Gradle」コマンドを実行すると、Eclipseがインストールしてる「Gradle」(今回だと「Spring スターター・プロジェクト」がインストールしてるってことになると思われます)ではないほうが有効になっちゃてる問題があるあるなんですよね。

なので、Eclipseがインストールしてるほうの「Gradle」を使う場合は、その使いたい「gradle」ファイルまでのフルパスを指定してコマンドを実行する感じになるというね、め、面倒くせぇ... 

脱線しましたが、今回は以下のようなファイル群の構成になりました。

f:id:ts0818:20210719162931p:plain

⇧ 本当は、「DTO(Data Transfer Object)」のフィールドとして、「propeties」パッケージの各Contextクラスを持たせたかったんだけど、@Autowiredが上手く機能しなくてNullPointerExceptionになってしまうので、今回は断念。

さらに、Javaの「application.properties」 が厄介なことに、「文字コード」が「ISO-8859-1」で処理されるらしいですと。

ja.stackoverflow.com

weblabo.oscasierra.net

natsumesouxx.hatenadiary.org

Javaのドキュメントに、サポートしてる「エンコード」の全量っぽいものが記載されてるらしい。

docs.oracle.com

java.io.InputStreamReader、java.io.OutputStreamWriter、java.lang.String、および java.nio.charset パッケージのクラスを使用すると、Unicode とその他のいくつかの文字エンコーディング間の変換を行うことができます。サポートされるエンコーディングは、Java プラットフォームの実装によって異なります。

https://docs.oracle.com/javase/jp/6/technotes/guides/intl/encoding.doc.html

docs.oracle.com

The java.io.InputStreamReaderjava.io.OutputStreamWriterjava.lang.String classes, and classes in the java.nio.charset package can convert between Unicode and a number of other character encodings. The supported encodings vary between different implementations of the Java SE Platform. 

https://docs.oracle.com/en/java/javase/15/intl/supported-encodings.html#GUID-E20951E6-C420-4D2F-A6BE-1470B4D55B3B

Javaのバージョン毎に異なるってことなんかな?

ちなみに、「ISO-8859-1」は、

ISO 8859-1(より正式にはISO/IEC 8859-1)はISO/IEC 8859の第一部であり、ラテンアルファベット文字コード標準である。よりくだけた言い方ではLatin-1と呼ばれる。最初はISOによって開発されたが、後にISOとIECによって合同で保守されている。

ISO/IEC 8859-1 - Wikipedia

この標準に追加の文字を(16進符号0x00-0x1Fの「C0領域」と、0x80-0x9F「C1領域」の範囲に)割り当てたものは、2つの広く使われているキャラクタセットの基となる。ISO-8859-1余分なハイフンに注意)とWindows-1252と呼ばれるものである。

ISO/IEC 8859-1 - Wikipedia

2004年6月、8ビット符号化文字集合の整備を担当するISO/IECの作業部会は、国際符号化文字集合 (UCS) とUnicodeの開発に専念するために解散し、ISO 8859-1を含むすべてのISO 8859の整備を中止した。

ISO/IEC 8859-1 - Wikipedia

コンピュータアプリケーションにおいては、(UTF-8UTF-16のような)完全なUCSサポートを提供するエンコーディングが、ISO 8859-1に基づくエンコーディングよりもますます多く使われるようになりつつある。

ISO/IEC 8859-1 - Wikipedia

⇧ 2004年に整備中止になったらしいの...Oh, my gosh...

今現在2021年なので、17年経ってるのにSpring Frameworkでは「application.properties」に対しては「ISO-8859-1」を使い続けるっていう選択をしてるのは、何なんだろう...

バージョンアップを盛んにしてる割には、肝心な部分の対応は後回しなんだね...

脱線しましたが、ファイルの内容は以下のような感じに。

■/Spring_Boot/build.gradle

plugins {
	id 'org.springframework.boot' version '2.5.0'
	id 'io.spring.dependency-management' version '1.0.11.RELEASE'
	//id 'java'
	id 'application'
}

mainClassName = 'com.example.demo.Application'
//bootJar {
//	mainClass = 'com.example.demo.Application'
//}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	//compileOnly 'org.springframework.boot:spring-boot-configuration-processor'
	annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
}

compileJava.inputs.files(processResources)

test {
	useJUnitPlatform()
}

tasks.withType(JavaCompile) {
	options.encoding = 'UTF-8'
}

■/Spring_Boot/src/main/resources/application.properties

# メッセージサンプル
american.message=Hello World!
chinese.message=你好,世界!
japanese.message=こんにちは 世界!

■/Spring_Boot/src/main/java/com/example/demo/config/properties/CommonContext.java

package com.example.demo.config.properties;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

public abstract class CommonContext {
	private String message;

	public String getMessage() {
		return this.message;
	}

	public void setMessage(String message) throws UnsupportedEncodingException {
		this.message = new String(URLDecoder.decode(message, "iso-8859-1").getBytes("iso-8859-1"),"utf-8");
	}
}

■/Spring_Boot/src/main/java/com/example/demo/config/properties/AmericanContext.java

package com.example.demo.config.properties;

public class AmericanContext extends CommonContext{

}

■/Spring_Boot/src/main/java/com/example/demo/config/properties/ChineseContext.java

package com.example.demo.config.properties;

public class ChineseContext extends CommonContext {

}

■/Spring_Boot/src/main/java/com/example/demo/config/properties/JapaneseContext.java

package com.example.demo.config.properties;

public class JapaneseContext extends CommonContext {

}

■/Spring_Boot/src/main/java/com/example/demo/config/beanProvider/PersonProvider.java

package com.example.demo.config.beanProvider;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.example.demo.config.properties.AmericanContext;
import com.example.demo.config.properties.ChineseContext;
import com.example.demo.config.properties.JapaneseContext;

@Configuration
public class PersonProvider {

	@Bean
	@ConfigurationProperties(prefix="american")
	public AmericanContext getAmericanContext() {
		return new AmericanContext();
	}

	@Bean
	@ConfigurationProperties(prefix="chinese")
	public ChineseContext getChineseContext() {
		return new ChineseContext();
	}

	@Bean
	@ConfigurationProperties(prefix="japanese")
	public JapaneseContext getJapaneseContext() {
		return new JapaneseContext();
	}
//	@Bean
//	public American getAmerican() {
//		return new American();
//	}
//
//	@Bean
//	public Chinese getChinese() {
//		return new Chinese();
//	}
//
//	@Bean
//	public Japanese getJapanese() {
//		return new Japanese();
//	}

}

■/Spring_Boot/src/main/java/com/example/demo/Application.java

package com.example.demo;

import java.io.UnsupportedEncodingException;

import org.springframework.beans.BeansException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

import com.example.demo.config.properties.AmericanContext;
import com.example.demo.config.properties.ChineseContext;
import com.example.demo.config.properties.CommonContext;
import com.example.demo.config.properties.JapaneseContext;

@SpringBootApplication
public class Application {

	private static final String contextRootDir = "com.example.demo.config.properties.";

	private static final String[] contextArr = {
			contextRootDir + "AmericanContext",
			contextRootDir + "ChineseContext",
			contextRootDir + "JapaneseContext",
	};

	public static void main(String[] args) {
		ConfigurableApplicationContext ctx =  SpringApplication.run(Application.class, args);
		String targetText = args[0];
		try {
			if ("--spring.output.ansi.enabled=always".equals(args[0])) {
				targetText = contextArr[(int)(Math.random()*contextArr.length)];
			}
			Class<?> clazz = Class.forName(targetText);
			System.out.println("Done!");
			CommonContext context = (CommonContext)ctx.getBean(clazz);
			printResult(context);
			System.out.println(System.getProperty("file.encoding"));
		} catch (BeansException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		}
	}

	public static void printResult(CommonContext context) throws UnsupportedEncodingException {

		if (context instanceof AmericanContext) {
			System.out.println(((AmericanContext)context).getMessage());

		} else if (context instanceof ChineseContext) {
			System.out.println(((ChineseContext)context).getMessage());

		} else if (context instanceof JapaneseContext) {
			System.out.println(((JapaneseContext)context).getMessage());

		}
	}

}

⇧ ってな感じの内容で保存し、コマンドで実行してみる。

■Gradleコマンドでビルド済みのファイル群を削除

[gradleが配置されてるディレクトリ]\gradle clean -PjavaVersion=[利用したいJavaのバージョン] -Dorg.gradle.java.home=[利用したいJava.exeが配置されてるディレクトリ]

f:id:ts0818:20210723162459p:plain


 

■Gradleコマンドでビルド

[gradleが配置されてるディレクトリ]\gradle build -PjavaVersion=[利用したいJavaのバージョン] -Dorg.gradle.java.home=[利用したいJava.exeが配置されてるディレクトリ]

f:id:ts0818:20210723162625p:plain

⇧ ってな具合で、どのJavaを利用するかも指定してあげといたほうが良さ気。

 

ビルドで、プログラミングの実行に必要なファイル群の準備できたら、プログラミングを実行で。 

f:id:ts0818:20210723163048p:plain

[gradleが配置されてるディレクトリ]\gradle run --args=[渡したいコマンドライン引数]    

⇧ ってな感じで、無事、実行結果が表示されました。

Eclipseで実行した場合も、

f:id:ts0818:20210723165552p:plain

f:id:ts0818:20210723163506p:plain

⇧ 無事に実行されました。

ちなみに、「application.properties」なんかで、独自なプロパティを利用する場合に、IDEが認識してくれない問題ですが、

spring.pleiades.io

Spring Boot の構成ファイルの処理は非常に柔軟であり、@ConfigurationProperties Bean にバインドされていないプロパティが存在する場合がよくあります。また、既存のキーの一部の属性を調整する必要がある場合があります。このような場合をサポートし、カスタムの「ヒント」を提供できるようにするために、アノテーションプロセッサーは META-INF/additional-spring-configuration-metadata.json のアイテムをメインメタデータファイルに自動的にマージします。

https://spring.pleiades.io/spring-boot/docs/current/reference/html/configuration-metadata.html#configuration-metadata.annotation-processor.adding-additional-metadata

自動的に検出されたプロパティを参照する場合、説明、デフォルト値、非推奨情報は、指定されていれば上書きされます。手動プロパティ宣言が現在のモジュールで識別されない場合、新しいプロパティとして追加されます。

https://spring.pleiades.io/spring-boot/docs/current/reference/html/configuration-metadata.html#configuration-metadata.annotation-processor.adding-additional-metadata

additional-spring-configuration-metadata.json ファイルの形式は、通常の spring-configuration-metadata.json とまったく同じです。追加のプロパティファイルはオプションです。追加のプロパティがない場合は、ファイルを追加しないでください。

https://spring.pleiades.io/spring-boot/docs/current/reference/html/configuration-metadata.html#configuration-metadata.annotation-processor.adding-additional-metadata

⇧ ってな記載を試してみたんですが、

f:id:ts0818:20210723164205p:plain

⇧ 解消されないんだが...

ちなみに、「[プロジェクト名]/build/classes/java/main/META-INF/spring-configuration-metadata.json」ってファイルは、ビルドした時に、Spring Bootが勝手に作成してくれるっぽい。

何て言うか、相変わらず、フレームワークのコアな部分の仕組みってブラックボックスだな~、という気がしてならない。

毎度、モヤモヤ感が募る一方ですが...

今回はこのへんで。

 

おまけ

ちなみに、Eclipseでビルドツールに「Gradle」を使ってるプロジェクトを扱ってる場合、「Gradle」のキャッシュに関するファイル群を削除する際に、Eclipseを起動してると、「別のプログラムがこのフォルダーまたはファイルを開いているので、操作を完了できません」ってなって削除できないっぽいので要注意ですかね。

Windowsの場合は、「C:\Users\[ユーザー名]\.gradle\caches」ってディレクトリに「Gradle」のキャッシュに関するファイル群が配置されるらしい。

f:id:ts0818:20210720171252p:plain

⇧ Eclipseでビルドツールに「Gradle」を使ってるプロジェクトを扱ってる場合は、Eclipseを閉じた状態で削除するようにしていきましょう。