今回は少し難しめの記事になるのですが、DIコンテナを使ってクラスのインスタンス生成を行ってみることにします。
DIコンテナでインスタンスを生成する方法は3つありますが、今回はXMLを利用して実装します。
残り2つはアノテーションを使って実装する方法になります。
今回使うソースについて
今回使うソースは以下の6つです。
1.アプリケーションを起動するjavaソース(Article92Application.java)
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.support.ClassPathXmlApplicationContext;
//XMLベースのDIコンテナ利用
@SpringBootApplication
public class Article92Application {
public static void main(String[] args) {
ClassPathXmlApplicationContext contxt =
new ClassPathXmlApplicationContext("di.xml");
SpringApplication.run(Article92Application.class, args);
}
}
この11行目から12行目にかけてDIコンテナのXMLを読み込む処理が記述されています。
2.曜日を変換する処理を定義したクラス(ConvertYoubiController.java)
package com.example.demo;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
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;
import dayYoubiBean.Day2Youbi;
@Controller
@RequestMapping()
public class ConvertYoubiController {
//DIコンテナ注入対象となるクラス
public static Day2Youbi d2y;
//この関数の実行でDIコンテナ注入が行われる
public void setDay2Youbi(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";
}
}
このソースで書かれたsetDay2Youbi()が、DIコンテナが生成したインスタンスを参照する処理となります。
つまり、DIコンテナにより、d2yが実体のあるクラスを参照できるようになります。
3.フォームで表示するためのGet、Setクラスの定義(Frm.java)
package com.example.demo;
public class Frm {
private String birth = "";
public String getBirth() {
return this.birth;
}
public void setBirth(String birth) {
this.birth = birth;
}
}
このクラスはフォームからの入力値を受け取り、ConvertYoubiControllerクラスのgetYoubiメソッドでの処理に利用し、再表示後もフォームの入力を保持するために定義しています。
4.西暦の年月日から曜日を計算するクラス(Day2Youbi.java)
package dayYoubiBean;
import java.time.DayOfWeek;
//DIコンテナ注入がなされるクラス
public class Day2Youbi {
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コンテナによりインスタンスを生成する対象になります。
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>
このページはThymeleafを使って変数の内容を表示しています。
ConvertYoubiControllerクラスのgetYoubiメソッド内にある
model.addAttribute("youbi", retYoubi);
model.addAttribute("birth", yyyyMMdd);
により、入力した生年月日と、曜日の情報を画面に表示させています。
6.DIコンテナを定義するXMLファイル(di.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="day2Youbi" class="dayYoubiBean.Day2Youbi"/>
<bean id="cYc" class="com.example.demo.ConvertYoubiController">
<property name="day2Youbi" ref="day2Youbi"/>
</bean>
</beans>
ここで注目して欲しいのは7行目から10行目の部分です。
7行目でDIコンテナで生成したいインスタンスを定義し、8~10行目でConvertYoubiControllerクラスでday2Youbiのクラスのインスタンス作成を行うことを宣言しています。
動作の確認
では、実際に上記のソースを作成した時の動作を確認してみましょう。

最初の画面が表示されたので、生年月日を入力して、「送信」を押してみます。

きちんと曜日が表示され、期待通りの動作になっていることが確認できました。
今回のソースの構成
今回のソースはそれぞれ以下の場所に格納して動作検証を行いました。

DIコンテナによるインスタンス生成の対象となるクラスは、あえて別のパッケージに定義しましたが、動作に問題はありませんでした。
XMLを使ったDIコンテナの定義の問題点
XMLを使ったDIコンテナ定義については、DIコンテナによるインスタンス生成を行いたいクラスの定義を全てもれなく書かなければなりません。
今回のプログラムでは、DIコンテナによるインスタンス生成の対象のクラスが1つだけだったのですが、複数存在する場合はそれらすべてをXMLファイルに記載する必要があります。
XMLの記述に誤りがあるとプログラムが動かないうえ、問題個所の特定が難しかったことが、自分の働く現場で起こったこともありましたので、記述のルールをしっかり決めて、読みやすい記述になるように気を付ける必要があります。
XMLを使ったDIコンテナの定義の利点
XMLを使ったDIコンテナの定義は同じクラスを異なる複数のクラスで生成したい場合に共通部品化できるため、XMLの書き方のルールを決めておけば、そんなに複雑な理解が必要というわけではなくなります。
また、それぞれのクラスでNewしなくて良く、複数のクラスで1つ生成されたインスタンスを共有できるというのはメモリの消費量の節約の点でもメリットがあるのかなと考えています。
同じクラスを異なる形で使いたい場合はDIコンテナのインスタンス生成対象から外してNewすればいいわけですが、そんなケースはそこまで多くないかと思います。
基本的にDIコンテナによるインスタンス生成の手段として知っていて損はなく、極端に使いづらい方法でもないので、まずはこの方法を知っていれば、DIコンテナによるインスタンス生成で悩むことはないかなと思っています。
ただ、後日記事にするアノテーションを使った方法はもっと簡単にできますので、こちらもしっかり理解して、どのような方法でDIコンテナによるインスタンス生成を行うべきか、慎重に検討してプログラムを生成して頂ければ、いいプログラムに仕上がるかと思います。
今回の記事はここまでとなります。
また次回の記事でお会いしましょう。