JavaのWebアプリケーション開発フレームワークによる、Webサイト開発の顛末記です。

EclipseのMavenを使った、Spring-MVC、Thymeleaf、MyBatis 等のプログラミングテクニックを、
備忘録的に記録しています。実際に動くソースコードを多用して説明していますので、
これからEclipseや、Spring-MVCを始めたいと思っている人にとって、少しでも参考になれば幸いです。
■Spring Boot の小径 第4歩 Spring Boot 匍匐前進
4-1)コンポーネントスキャン
■SpringMVC の小径では、個人的な好みでクラスの性質に合わせてパッケージ階層を分けました。
cntl/blogic/model........ みたいな感じですね
そして、Spring設定ファイル(applicationContext.xml)で、コンポーネントスキャンの対象パッケージを定義しました。
<context:component-scan base-package="jp.dip.arimodoki.cntl"/>
<context:component-scan base-package="jp.dip.arimodoki.blogic"/>
<context:component-scan base-package="jp.dip.arimodoki.model"/>
のような感じです。

Spring Boot ではそもそも、Spring設定ファイル自体存在しないため
クラスのパッケージ階層を分けて、必要に応じて DI したい場合どうすればいいでしょう?
答えは、異なるパッケージ階層を使用する(DIする)クラスで、@ComponentScanアノテーションを宣言して
使用するパッケージを指定してあげれば利用可能となります。

下に、コントローラから、パッケージ階層を横断したクラスをDIするサンプルを作ってみました。

Gradle プロジェクトソースツリー
まずは、コントローラ
src/main/java/jp/dip/arimodoki/cntl/HelloCntl.java


このサンプルでは、コントローラでバインドされたFormBean(FormHello.java)を、
ビジネスロジック(BlHello.java)に継承し、ここでViewに表示するメッセージをセットします。
コントローラは、FormBeanをView(hellcntl.html)に返却しこのメッセージをブラウザに表示します。
ここでDIされるクラスのパッケージ階層は、
jp.dip.arimodoki.blogicと、 jp.dip.arimodoki.model のパッケージ階層を使用するため、
コントローラのクラス宣言部に、
@ComponentScan("jp.dip.arimodoki.blogic, jp.dip.arimodoki.model")
で、パッケージのコンポーネントスキャン宣言を行っています。
スキャンするパッケージ階層が複数の場合は、カンマ(,)で区切って複数指定が可能です。
また、jp.dip.arimodoki.* のようにワイルドカードも使えます。
続いて、フォームBean
src/main/java/jp/dip/arimodoki/model/FormHello.java


Viewに表示する discriptionを、保持する単純なBeanです。
インターフェース FormHelloIf.java は Eclipse のリファクタリング(インターフェースの抽出)で自動生成します。

続いて、ビジネスロジック
src/main/java/jp/dip/arimodoki/blogic/BlHello.java


コントローラからFormBeanを受け取り FormHello Beanの discriptionに値をセットします。
このビジネスロジックも、FormBeanのパッケージ階層jp.dip.arimodoki.modelを使用するので
クラス宣言部に@ComponentScan 宣言を行っています。
インターフェース BlHelloIf.java は Eclipse のリファクタリング(インターフェースの抽出)で自動生成します。

最後が、View
src/main/resources/templates/hellocntl.html


基本的には、前に出てきた hello.html とほとんど変わりません。
一点だけ。表示する discription をFormHelloから取り出しているところだけが異なります。

 

それでは、このアプリケーションを実行してブラウザで確認してみましょう。
ブラウザのURLに、「http://localhost:8080/hellocntl」 を入力してみます。
Hello コンポーネントスキャン !!

 

いかがでしょうか?
BlHello.javaでセットされた文字列が、期待通りブラウザに表示されました。

Spring設定ファイルで定義していたコンポーネントスキャン宣言が、
それを使用するクラスの先頭で直接指定できるので、直感的にわかりやすくなっていると思います。
まぁ、ほんのちょっとだけコーディング量は増えますけど。。。

 

※)どんでん返しのお話 2017/Apr/05 追記
ここまで話を盛り上げておいて、ここで今更いうのもなんですが、
クラスの数が増えると、一々クラスに@ComponentScanアノテーション付けるのがちょっと面倒ですよね?
なんかいい方法ないでしょうか?
実はあります。一発逆転のテクニックをご紹介しましょう。

Gradleプロジェクト / Mavenプロジェクト どちらも一緒ですが
Spring Boot プロジェクトが作成された時に自動生成されるメインクラス、
ProjectNameApplication.javaのクラスに、アノテーションを一行追加します。
このプロジェクトの例ですと、src/main/java/jp/dip/arimodoki/BootLaboApplication.java(抜粋)
@SpringBootApplication
@ComponentScan(basePackages = "jp.dip.arimodoki")
public class BootLaboApplication {
     :
     :
クラスのアノテーションで、上の赤字の行を一行追加します。

これだけで、ここでコンポーネントスキャン宣言されたパッケージ配下のクラスは全てComponentScan対象となり、
一々、個々のクラスに@ComponentScanアノテーションを宣言しなくてもよくなり、@ComponentScan宣言の手間が省けます。
対象パッケージが複数ある場合は、basePackagesにカンマ(,)区切りでパッケージ名を記述します。
このテクニックは、後述する Singleton一括排除の際にもまた出てきますので覚えておいてください。