Java 広告

【Java】SpringBootでDIコンテナを使ってクラスの注入を行ってみた(アノテーション編その1)

記事内に商品プロモーションを含む場合があります

今回はJavaでSpringBootを使ってDIコンテナを使ったクラスの注入を行います。

今回使うのはアノテーションというのもので、メソッドやクラスの前に@××××などの表記を追記するものです。

今回使うアノテーションは@Autowiredと@Componentというアノテーションを使って実装してみます。

今回使うソースについて

今回使うソースは以下の5つです(XMLファイルは今回は使用しません)。

1.アプリケーションを起動するjavaソース(Article92Application.java)

package com.example.demo;

import org.springframework.boot.SpringApplication;
//アノテーションベースのDIコンテナ利用
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Article921Application {

	public static void main(String[] args) {
		SpringApplication.run(Article921Application.class, args);
	}

}

今回はこのソースに関しては特にDIコンテナに関する表記を入れていません。

2.曜日を変換する処理を定義したクラス(ConvertYoubiController.java)

package com.example.demo;


import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping()
public class ConvertYoubiController {
	//DIコンテナ注入対象となるクラス
	public static Day2Youbi d2y;
	//この関数の実行でDIコンテナ注入が行われる
	@Autowired
	public void setDay2Youbi(@Qualifier("day2Youbi") Day2Youbi day2Youbi) {
		d2y = day2Youbi;
	}

	//入力した西暦と年月日から曜日を取得する
	@PostMapping("/index/getYoubi")
	public String getYoubi(Frm form, Model model) {
		String retYoubi;
		//フォームから送信されたデータを受け取る
		String yyyyMMdd = form.getBirth();
		//受け取ったらLocalDate形式に変換する
		LocalDate ld = LocalDate.parse(yyyyMMdd, DateTimeFormatter.ofPattern("yyyyMMdd"));
		//曜日を取得
		DayOfWeek dow = ld.getDayOfWeek();
		
		// 日付から曜日を取得する
		retYoubi = d2y.Day2YoubiOpe(dow);
		
		//フォームに表示する情報をセットする
		model.addAttribute("youbi", retYoubi);
		model.addAttribute("birth", yyyyMMdd);
		return "convertYoubi";
	}
	@GetMapping("/index")
	public String index(Model model) {
		//フォームに表示する情報をセットする
		model.addAttribute("youbi", "");
		return "convertYoubi";
	}
}

このプログラムの22行目に@Autowiredというアノテーションがあります。

このアノテーションをクラスを設定するメソッドの前に追加することで、自動でDIコンテナによりクラスのインスタンスを生成してくれます。

3.フォームで表示するためのGet、Setクラスの定義(Frm.java)

package com.example.demo;

public class Frm {
	//private String youbi = "";
	private String birth = "";
	
	public String getBirth() {
		return this.birth;
	}
	
	public void setBirth(String birth) {
		this.birth = birth;
	}
}

このクラスはフォームからの入力値を受け取り、ConvertYoubiControllerクラスのgetYoubiメソッドでの処理に利用し、再表示後もフォームの入力を保持するために定義しています。

4.西暦の年月日から曜日を計算するクラス(Day2Youbi.java)

package com.example.demo;

import java.time.DayOfWeek;

import org.springframework.stereotype.Component;

//DIコンテナ注入がなされるクラス
@Component
public class Day2Youbi{
	//日付から曜日を判断する(DIコンテナ利用のために処理を独立させた)
	public String Day2YoubiOpe(DayOfWeek dow) {
		String retYoubi ="";
		
		// 日付から曜日を取得する
		switch (dow) { 
		    case SUNDAY: 
		    	retYoubi="日";
		        break;
		    case MONDAY: 
		    	retYoubi="月";
		        break;
		    case TUESDAY:
		    	retYoubi="火";
		        break;
		    case WEDNESDAY:
		    	retYoubi="水";
		        break;
		    case THURSDAY:
		    	retYoubi="木";
		        break;
		    case FRIDAY:
		    	retYoubi="金";
		        break;
		    case SATURDAY: 
		    	retYoubi="土";
		        break;
		    default:
		    	retYoubi="曜日取得失敗";     	
		}
		return retYoubi;
	}
}

今回もこのソースで定義されているクラスをDIコンテナの対象とします。

ソースの8行目に注目して欲しいのですが、@Componentというアノテーションが存在しています。

この@Componentというアノテーションがあることで、DIコンテナの対象であると認識されます。

5.画面表示用ページ(convertYoubi.html)

<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org">
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title>送信のデモ</title>
 </head>
  <body>
    <form action="#" th:action="@{/index/getYoubi}" th:object="${frm}" method="post">
      <table>
        <tr>
			<td>生年月日(19800101の形式で入力)</td>
			<td>
				<input type="text" maxlength="10" id="birth" name="birth" th:value="${birth}" />
			</td>
		</tr>
      </table>
      <table>
        <tr>
			<td th:text="あなたは + ${youbi} + 曜日に生まれました。">
			</td>
		</tr>
      </table>
          <input type="submit" value="送信">
    </form>

  </body>
</html>

画面の表示のためにHTMLで書かれたページです。

今回もThymeleafによりJava側から受け取った変数の内容を表示するようにしています。

動作の確認

では、上記のプログラムの動作を確認してみることにします。

画面が表示されたので、適当な西暦と年月日を入れて送信ボタンを押してみます。

スマホのアプリのカレンダーを確認してみると、2003年7月20日は確かに日曜日でした。

ということは、ConvertYoubiController.javaクラスのsetDay2Youbiメソッドで、きちんとDay2Youbiクラスを参照するようになっていて、問題なくDay2Youbiクラスで定義されているメソッドを実行していることが分かります。

つまり、きちんとDIコンテナによるクラスの注入が動作していることが確認できました。

今回のソースの構成

今回のソースは以下のような構成で作ってみました。

4つのJavaファイルをすべて同じパッケージ内に配置しています。

Day2Youbi.javaが他の3つのJavaファイルと同じパッケージ内に存在する理由ですが、@Componentがついたクラスを別のパッケージに配置するとうまく動作しなかったためです。

そのため、同じパッケージ内に配置して動作確認を行いました。

個人的にはそういう制約なのかと思っていますが、この方法以外でDIコンテナを使うと別のパッケージにDay2Youbi.javaを置いても問題なかったので、異なるパッケージのクラスをDIコンテナを使って注入する場合は、今回紹介した方法でなくてもいいのではないかと思います。

@Autowiredと@Componentを使うメリット

今回@Autowiredと@Componentを使ってDIコンテナ利用した場合のメリットですが、アノテーションを付けるだけで他に処理がいらないため、シンプルで分かりやすいし、ソースのメンテナンスをしやすいのが利点に感じました。

特にXMLを書く場合よりもだいぶ楽にDIコンテナの機能を利用できましたので、個人的には今回の方法が一番わかりやすい方法であると思いました。

@Autowiredと@Componentを使うデメリット

では、デメリットは何かというと、先に述べたように同じパッケージの中に@Autowiredと@Componentが存在しないとうまく動いてくれない点ですね。

ここはプログラムの書き方によってはどうにでも出来そうですが、一応注意しておいた方がいいでしょう。


DIコンテナはそれぞれのクラスでNewする手間を省くために利用されることが多いですが、複数のクラスで同じクラスを参照する場合に、それぞれのクラスでNewするよりは、一つインスタンスを作っておいて、それを共通して参照するようにした方が分かりやすいし、いいプログラムになるのかなと思います。

前回から始まっているDIコンテナのプログラムは、自分も学習中の身であり、あまり本質が理解できていない部分が多いため、しっかりと学んでみて、どういうメリットがあるのかがきちんと理解できた時点で、1つの記事として書いてみたいと思います。

今回の記事はここまでとなります。
また次回の記事でお会いしましょう。