1. DI を使って書籍一覧画面を出す
1-1. 実習テーマ
- 書籍情報ドメインクラス作成
- (えせ)書籍一覧サービスクラスを DI する
- (えせ)書籍一覧Daoクラスを DI する
1-2.今回やること および 学習ポイント
- 書籍情報ドメインクラス作成
- やること
- 書籍情報ドメインクラスを作成する
- やること
- (えせ)書籍一覧サービスクラスを DI する
- やること
- (えせ)書籍一覧サービスクラス作成
- 書籍画面コントローラに書籍一覧サービスをDIして使用する
- 書籍一覧サービスで生成した書籍情報ドメインの情報を、書籍一覧JSP画面で表示させる
- 学習ポイント
- DI の基本メカニズムの理解
- Spring DI コンテナの理解
- やること
- (えせ)書籍一覧Daoクラスを DI する
- やること
- (えせ)書籍一覧Daoクラス作成
- 書籍画面サービスに書籍一覧DaoをDIして使用する
- 学習ポイント
- DI の必要性を考える
- やること
2. 技術解説 - DI (Dependency Injection
2-1. DI とは
-
Dependency Injection の略
日本語では「依存性の注入」と呼ばれる
-
オブジェクト同士の依存関係を外部から作成できる機構のこと
すなわち、プログラムを構成するオブジェクト間の依存性をソースコードから排除し、フレームワークが後から依存性を注入(設定)できる機能を提供するもの
-
DI は Web アプリケーションに限らず、Spring を使用した様々なアプリケーションで使用できる
そもそも DI は Spring に限らず、様々な言語のフレームワークで実装されています
2-2. DI の適用箇所
- DI はアプリケーション全ての層に適用できる技術である
レイヤ | コンポーネント | 主な Spring 提供機能 |
---|---|---|
プレゼンテーション層 | コントローラ | Spring MVC、DI、AOP |
ビジネスロジック層 | サービス、ドメイン | Validation、Spring Transaction、DI、AOP |
データアクセス層 | DAO | Spring JDBC、ORM、DI、AOP |
2-3. DI の仕組み
-
DI対象のオブジェクトは、DIを実現するための「DIコンテナ」と呼ばれる領域(箱)に格納される
-
インジェクションを要求するクラス変数があると、変数の型(もしくは名前)に合致するオブジェクトをDIコンテナから探し出して、該当変数にインジェクションする
2-4. アノテーションを使用した DI コンテナ格納
- オブジェクトを生成して DI コンテナに格納するためには、下記の何れかのアノテーションをクラス定義に付与すれば良い。
- @Controller
- @Service
- @Repository
- @Component
これらのアノテーションを付与するだけでオブジェクト生成とDIコンテナ格納が自動的に実行される
-
コントローラをDIコンテナに格納するサンプル
@Controller // @@@@ コントローラをDIコンテナに格納するアノテーション @@@@ public class BookController { // Something to do .. }
-
サービスをDIコンテナに格納するサンプル
@Service // @@@@ サービスをDIコンテナに格納するアノテーション @@@@ public class ListBookServiceImpl implements ListBookService { // Something to do .. }
-
Dao をDIコンテナに格納するサンプル
@Repository // @@@@ Dao をDIコンテナに格納するアノテーション @@@@ public class ListBookDaoImpl implements ListBookDao { // Something to do .. }
2-5. アノテーションを使用したインジェクション
-
DIコンテナに格納されているオブジェクトのうち、指定するオブジェクトをDIさせるには、クラス変数に、以下の何れかのアノテーションを付加すればよい
- @Inject
- @Autowired
- @Resource
これらのアノテーションを付与することで指定オブジェクトの検索とインジェクションが実行される 現在 @resource は殆ど使用されない、本トレーニングでは @Autowired を使用します
-
指定オブジェクトの検索方法は、型をベースに検索する方法(byType)と、名前による検索(byName)の2つがある、デフォルトは、byType による検索を行う
-
Dao をDIコンテナに格納するサンプル
@Controller public class BookController { // @@@@ // @@@@ ByType で一致するオブジェクトをインジェクションする // @@@@ @Autowired ListBookService listBookService; // @@@@ ↑ // @@@@ DI コンテナから型が一致するオブジェクトを検索 // @@@@ 一致するオブジェクトが見つかったら該当の変数に代入される @RequestMapping(value = "/listbook", method = RequestMethod.GET) public String listBook(Model model) throws Exception { List<Book> books = listBookService.getBookList(); model.addAttribute("books", books); return "listbook"; } }
2-6. インターフェースで抽象化すること
- DI でインジェクションさせるオブジェクトは、必ずインターフェースで実装を抽象化しておくことが非常に重要である!
-
インターフェースで抽象化することにより、ソースコードを変更することなく、実行時に実装クラスを差し替えることが可能となる
例えば、データ永続化の処理について、データ検索や更新などのインターフェースだけ決まっていれば、実際の永続化手段がデータベースなのか、ファイルなのかは実装クラスを差し替えれば対応できるようになる。
-
すなわち、これが依存しないということである
-
インターフェースのサンプルコード
// 書籍一覧サービスクラスインターフェース public interface ListBookService { //書籍一覧取得サービス public List<Book> getBookList() throws Exception; }
-
インジェクション対象の実装クラスのサンプルコード
@Service public class ListBookServiceImpl implements ListBookService { //書籍一覧取得サービス @Override public List<Book> getBookList() throws Exception { // Something to do return hoge; } }
-
インジェクションして利用するクラスのサンプルコード
@Controller public class BookController { @Autowired ListBookService listBookService; // @@@@ ↑ // @@@@ インターフェースの型で宣言することがミソ // @@@@ これにより、より抽象化した型で合致するオブジェクトが検索される // Something to do }
2-7. Spring 設定ファイルによる DI
- Spring設定ファイルで、DI設定する方法もある(ただし本研修ではここで紹介する程度)
- この方法は、DIを集中的に設計・管理できるメリットが有る
- このため、比較的大規模なアプリケーションの場合に有効である
- そもそもSpringは 設定ファイルによるDIのみサポートしていたが、Spring2.5から、アノテーションによるDIがサポートされ、利便性が大幅に向上した経緯がある
3. 技術解説 - ドメイン情報を画面表示 - Spring MVC
3-1. ドメインオブジェクトの情報を画面に渡す
- Domain を画面(JSP)に渡すには、Spring MVC に用意されている Model オブジェクトを使う
- Modelオブジェクトは、Model - View - Controller の Model に該当
-
すなわち、Controller からView に引き渡すデータを格納するオブジェクト
-
Book ドメインを Model に登録するサンプルコード
@RequestMapping(value = "/listbook", method = RequestMethod.GET) public String listBook(Model model) throws Exception { // @@@@ ↑ // @@@@ Modelオブジェクトをコントローラメソッドの引数で取得 // @@@@ // 書籍一覧取得ロジック処理、Domain オブジェクト取得 List<Book> books = listBookService.getBookList(); // 書籍一覧情報をモデルに登録 model.addAttribute("books", books); // @@@@ ↑ // @@@@ Domain オブジェクト book を Model に登録 // @@@@ 上記の場合 "books" という名前で登録している // @@@@ // 画面表示に listbook.jsp を呼び出す return "listbook"; }
3-2. 渡されたドメインオブジェクト情報を画面に表示する
- Modelオブジェクトに格納した Domain は、Modelオブジェクト格納時に設定した名前でJSPに引き渡される
-
つまり自動的にHttpServletReqestに設定されることと同意
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <html> <head><title>書籍一覧画面</title></head> <body> <h1>書籍一覧画面</h1> <table> <tr><th>id</th><th>isbn</th><th>name</th><th>price</th></tr> <!-- @@@@ @@@@ Model から Domain オブジェクトを取り出す @@@@ 下記例の場合、"books" という名前でアクセスできる @@@@ --> <c:forEach items="${books}" var="book" varStatus="status"> <tr> <td><c:out value="${book.id}" /></td> <td><c:out value="${book.isbn}" /></td> <td><c:out value="${book.name}" /></td> <td><c:out value="${book.price}" /></td> </tr> </c:forEach> <!-- @@@@ 上の forEach について @@@@ @@@@ ${books} はList型なので、一要素ずつbookドメインオブジェクトを取り出し @@@@ "book" という変数に格納しながら要素が無くなるまでループさせる @@@@ --> </table> </body> </html>
4. ハンズオン実習
STEP03 ハンズオン
-
ハンズオン資料「 STEP03 - DIによる(えせ)書籍一覧画面 」に従い実習を開始してください。
- DI を使用して Controller に Service オブジェクトをインジェクションしてみましょう
- DI を使用して Service に Dao オブジェクトをインジェクションしてみましょう
- インターフェースを使用して、インジェクションするオブジェクトを抽象化しましょう
- 書籍一覧画面に Book (Domain) オブジェクトの情報を表示させましょう
STEP03 実装イメージ
次のステップ
次のステップは「 STEP04 - Spring JDBC を使った書籍テーブル検索 」です。いい感じです。