こんにちは!
23卒新卒エンジニアのkamaです!
前回はspringで必須になってくる事前知識について取り上げました。
今回は、その事前知識で学んだDIをどのようにSpringFrameworkを利用して実装するのか、という点に着目して、最小サイズのプログラムを作成していきたいと思います!!
本編前にちょっと
#1で取り上げた技術書のSpring徹底入門
ですが、こちら読み進めていくうちに、初学者向けじゃない+ハンズオン形式のものではなかったため、今回からは別の技術書を読みながら解説していきます!
今回から使っていく技術書は
SpringFramework超入門
優しくわかるWebアプリ開発
(株)フルネス 木下 雅章/著
出版社 : 技術評論社
です。
こちら、現在3分の1ほど読んでいるのですが、めちゃくちゃわかりやすいです。
専門的な用語や、難しい表現をなるべく省いているというのもあって、初学者でも理解しやすいと思いました。
最低限の知識として、ある程度のオブジェクト指向
に対する理解と、Java
の理解は必要なので、それらがまだな方は後回しのほうが良いかもです。
また、この記事では、最新の環境を用いた解説はしておりません!!
教材にしている本で取り上げられているバージョンが古いというのもあるのですが、それ以前に、私がアサインされた案件の要求バージョンがこの本よりさらに古いというのがもっともな理由です。
具体的な環境は以下の通りです。
OS : windows11
Ecripseのバージョン : 2021-12
JDKのバージョン : JDK-11.0.19.7-hotspot
まずは環境構築
Eclipseとは
なにはともあれ、環境構築が必要です。
Java単体を動作させるだけならVScodeで十分なんですけど、SpringFrameworkを利用するとなると、VScodeでは無理があります。
そこで登場するのが、Javaユーザーにはお馴染みらしいEclipseです。
javaの統合開発環境の1つで、機能性の高さはもちろん、オープンソースなので、拡張機能やプラグインが豊富なのが特徴です。
使い勝手だけで言えば、C++、C#で言うVisualStudioにあたるのかな~と感じました。(もっともVisualStudioはオープンソースじゃないですけどね)
今回インストールして使っていくのは、このEclipse
にさらに便利な機能や日本語化を付け加えた、Pleiades All in Oneというパッケージになります。
JDKやその他諸々も一緒についてきて便利なので、これを使うのがおすすめです。
インストールして起動
環境に合わせたものを以下からダウンロードします。
おそらく、ブラウザからセキュリティブロックを食らうと思いますが、無視しても問題ないです。
ダウンロードが終わったら解凍するのですが、その際に、なぜかWindowsデフォルトの解凍ではエラーが出てしまうので、7zipなどの外部のツールで解凍してください。
解凍先は任意のディレクトリで大丈夫ですが、なるべく浅い階層のほうが良いそうです。
解凍が完了したら、
任意のディレクトリ\pleiades{バージョン名}\pleiades\eclipse\eclipse.exe
を起動します。
起動すると、こんな画面が出ると思うので、赤枠の部分にチェックを入れて[起動(L)]を押す
プロジェクトの作成
実際に作っていくプロジェクトを作成できるまでが、環境構築です。(何かのインストールが足りてなくてプロジェクトが作れないパターンあり)
先ほどの画面から、
ファイル(F) => Springスターター・プロジェクト(Spring Initializer)
を選択する
この画面が表示されるはず。
とりあえず、この記事で必要になる項目について説明します。
表示 | 機能 |
---|---|
名前 | プロジェクトの名前。任意のものでOK(今回はPrefecturesOfJapan とした) |
タイプ | ビルドツールの選択、とりあえずはGradleでOK(私もまだ理解しきれてないです) |
Javaバージョン | 読んで字のごとく、Javaのバージョン。この記事では11を利用するが、どのバージョンでもできると思う... |
パッケージング | パッケージングの形式を指定する。ビルドするときに関係してくるが、とりあえずJarでOK |
他はデフォルトのまま次へ
依存関係を設定する画面に遷移します。
バージョンは任意のものに変更(今回は2.7.12)
いくつかデフォルトでチェックが入っているが、依存関係でエラーが出ると結構めんどくさいので、今回は必要なSpring Boot DevTools
だけにチェックを入れて完了を押す。
無事デフォルトのプロジェクトが出来上がれば成功です!
DI実装!!
さてついにここからは実際にプログラミングしていくターンになります。
DI実装と聞いて難しいことをやるように感じるかもしれませんが、実際には、ApplicationContextが全部やってくれるので、こちらはむしろ簡単ですよ!
今回は、難解な処理はせず、シンプルに都道府県名をprintするだけのプログラムを作成します。
クラスの確認
まずは大前提として、DIを実装するために必要な最低限のクラスについて確認して羅列しておきましょう。(その方が分かりやすいし、簡単)
インターフェースクラス
インターフェースを定義するクラスです。
今回の場合は、都道府県名をPrintするためのPrefecturesPrinter関数を抽象化しておきます。
実装クラス
インターフェースを実装するクラスです。
今回はわかりやすいように、TokyoとOsakaの2つを作成することにしましょう。
利用クラス
実際にインターフェースから注入されたインスタンスを利用するクラスです。
利用クラスは基本的にはエントリーポイントとなるmain関数があるクラスになると思いますが、今回作成したSpringスタータープロジェクトにはデフォルトで、プロジェクト名+Application
というmain関数を持ったクラスが作成されているので、こちらを利用します。
いざプログラミング
インターフェース
まずは、インターフェースクラスを作成しましょう。
パッケジエクスプローラーから階層を
PrefecturesOfJapan => src/main/java => com.example.demo
と下っていき、com.example.demo
を右クリックして、
新規(W) => パッケージ
をクリックします。
この画面が表示されたら、名前の部分の後ろに.used
を付けて、com.example.demo.used
にしたら、[完了(F)]を押す。
すると新しくパッケジエクスプローラーにcom.example.demo.usedという田のようなアイコンのパッケージが作成されているはず。
そのパッケージを右クリックして、
新規(W) => インターフェース
でインターフェースを作成する
インターフェース作成画面に遷移したら、任意の名前を付ける。
ここではPrefecturesPrinter
とする
[完了(F)]を押せばインターフェースクラスファイルが作成される。
作成されたファイルをクリックするとこのようなファイルになっているはず。
package com.example.demo.used;
public interface PerfecturesPrinter {
}
ここにPrefecturesPrint関数を抽象化しておいておきます。
Javaでは、クラス宣言時にinterface
キーワードを付けることで、そのクラスで関数はすべて暗黙的にpublic abstract
で宣言されたことになるので、抽象化に際して特別な記述はいらない。
package com.example.demo.used;
public interface PerfecturesPrinter {
/**
*都道府県を出力する
*/
void prefecturesPrint;
}
Java(eclipseだけ?)では関数やクラスの直前に以下の書き方で書かれたコメントアウトを記入すると、他のファイルなどで、そのクラスや関数にホバーしたときにコメントを表示させることができる。(C#のXMLドキュメントみたい)
/**
* ここが表示されるよ<br>
* 改行タグは<br>だよ
*/
実装クラス
ここまでは、ただのJavaでもやる範囲(のはず)。
ここからは、DIを実装するうえで大切なアノテーションを使って、記述していきます。
先ほどインターフェースクラスを作成したパッケージに実装クラスも作ってしまいます。(ほぼ操作は同じなので写真は省略)
ファイル => 新規(N) => クラス
でクラス作成画面へ遷移します。
今回も名前だけ変更で大丈夫です。
この手順でTokyo
とOsaka
を作成しましょう!
作成で来たら、まずは普通に実装クラスを書いてみます。
ちなみに、import
は必要に応じてeclipseが自動的に挿入削除してくれるので、気にしなくても大丈夫です!
package com.example.demo.used;
public class Tokyo implements PerfecturesPrinter{
public void prefecturePrint() {
System.out.println("東京です");
}
}
もちろん、これだけでもしっかりインターフェースの実装はできています。
が、ApplicationContextの恩恵を授かるためには、アノテーションで、そのクラス、関数がどういうものなのかを判別して管理してもらう必要があります。
そのためには、
実装クラスには@Component
@Component
自体は、Springでコンポーネントとして利用したいオブジェクトになら、何にでも付けれらます。
実装クラスに着けることで、ApplicationContextが自動的に依存関係を確認して、そのクラスが、どのインターフェースの実装をしたかまでを把握してくれて、なおかつインスタンスの生成も自動的にやってもらうように任せることができるようになります!
ちなみに
@Component
はインスタンス生成アノテーションと呼ばれるものになるのですが、このインスタンス生成アノテーションは、他に3種類あります。
それぞれレイヤによって分けることが推奨されているようですが、今はまだ意識しすぎなくてもいいのかな、とも感じます(下手に意識しすぎると、余計に設計がごちゃごちゃする)
アノテーション | レイヤ | 概要 |
---|---|---|
@Controller |
アプリケーション層 | クライアントとのデータの入出力 |
@Service |
ドメイン層 | アプリケーションの中核で、業務処理を提供する |
@Repository |
インフラストラクチャ層 | データベースへのデータ永続化、データアクセス処理 |
@Component |
サブ処理 | それ以外のインスタンス生成 |
クライアントからデータベースにアクセスする際、上のレイヤ順番に処理されていく。
ただし、@Component
だけは、どの処理層でもサブ処理として並列的に処理される。
オーバーライドした関数は@Override
読んで字のごとくですが、オーバーライドした関数は@Override
を付ける必要があります。
これらを正しく付けるとこうなります。(import部分は省略)
package com.example.demo.used;
@Component
public class Tokyo implements PerfecturesPrinter{
@Override
public void prefecturePrint() {
System.out.println("東京です");
}
}
これでTokyoクラスが完成しました!
この調子でOsakaクラスも作っちゃってください!
利用クラス
利用クラスは先ほども書いたように、最初から作成されている、プロジェクト名+Application
クラスを利用します。
まずは、インスタンスの生成をするために必要な、@Autowired
の説明です。
このアノテーションが付与されたフィールドやメソッドには、自動的に適切な依存オブジェクトを注入してくれます。
つまり、利用するクラスでnewしてインスタンスを作成することなく、実装クラスのインスタンスを利用することができるということです。
@AutoWired
Tokyo tokyo;
@AutoWired
Osaka osaka;
アノテーションは1つのオブジェクトにつき1つ必要なことに注意
続いてオーバーライドした関数を呼び出す関数を作ります。
private void Printer(){
tokyo.prefecturePrint();
osaka.prefecturePrint();
}
ここは特に問題ないですね。
最後に、この関数を呼び出すエントリーポイントを作ります。
とはいっても、エントリーポイントとなるのは、デフォルトで作られているmain関数
になるので、ここに追記していきます。
ファイル作成時点で、main関数がこのようなつくりになっているはずです。
public static void main(String[] args) {
SpringApplication.run(PrefecturesOfJapanApplication.class, args);
}
まずは、現段階で書かれている内容の説明をします。
何やら長々と書かれていますが、やっていることは単純なことです。
このアプリケーションをSpringApplication
という仕組みの、run()
というかっこ中を実行するというメソッドを利用しています。
今回は、かっこの中がPrefecturesOfJapanApplication.class
なので、この宣言がなされているクラスそのものをSpringApplicationとして実行するといった具合でしょうか。
しかし、これだけでは処理が書かれている関数は呼ばれていないので、実行しても何も起きません。(エラーも発生しません)
そのため、このクラスの、どの関数を実行するのか、という宣言が必要になります。
public static void main(String[] args) {
//わかりやすいように改行してありますが、別に改行はなくても大丈夫です
SpringApplication.run(PrefecturesOfJapanApplication.class, args)
.getBean(PrefecturesOfJapanApplication.class).Printer();
}
先ほどのコードの後ろに、.getBean(PrefecturesOfJapanApplication.class).Printer()
という処理が追加されました。
これは、PrefecturesOfJapanApplication
というBean(インスタンス)をApplicationContextから取得し、そのインスタンスのPrinter()
という関数を呼び出しています。
これで、一通りのコーディングが完了しました。
これを実行するには、
パッケジエクスプローラー => エントリーポイントとなるjavaファイルを右クリック => 実行(R) => 3 Spring Boot アプリケーション
でコンソールに結果が出力されます。
10:30:41.404 [Thread-0] DEBUG org.springframework.boot.devtools.restart.classloader.RestartClassLoader - Created RestartClassLoader org.springframework.boot.devtools.restart.classloader.RestartClassLoader@153f309
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.7.12)
2023-05-24 10:30:41.693 INFO 15228 --- [ restartedMain] c.e.demo.PrefecturesOfJapanApplication : Starting PrefecturesOfJapanApplication using Java 11.0.13 on {PCの情報とか}
2023-05-24 10:30:41.694 INFO 15228 --- [ restartedMain] c.e.demo.PrefecturesOfJapanApplication : No active profile set, falling back to 1 default profile: "default"
2023-05-24 10:30:41.734 INFO 15228 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2023-05-24 10:30:42.123 INFO 15228 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2023-05-24 10:30:42.138 INFO 15228 --- [ restartedMain] c.e.demo.PrefecturesOfJapanApplication : Started PrefecturesOfJapanApplication in 0.72 seconds (JVM running for 1.478)
東京です
大阪やで
実行する際、右クリックするのは、プロジェクトそのものではなく、エントリーポイントとなるjavaファイルであることに注意(デフォルトのままなら、プロジェクト名+Application
)
ここでエラーが発生する場合はどこかしらに間違ってしまったところがあるのでしょう。
ここで逐一エラーの説明をしてもしょうがないので、自分で調べる能力を磨きましょう。
あとがき
前回まで使っていた技術書から一度離れて、ハンズオン形式の初学者向けの技術書を読み始めたのですが、大正解でした。
前回までは、結構難しいイメージしかなくて、どんよりだったんですけど、新しい技術書で、この記事でやった内容が理解できるようになってから、かなり学ぶのが楽しくなってきました!
まだまだチュートリアルの段階ではあると思いますが、しっかり自分に合った学び方でモチベをキープして勉強し続けれるのが大事だと改めて感じることができてよかったです。