本記事は、Spring Framework(非boot)のDIの動作確認を行った。
以下の4パターンの動作確認を行った。
No. | context:component-scan にパッケージが含まれているか |
コンポーネントスキャンの対象となるアノテーションの付与 | Autowired の付与 |
実行結果 |
---|---|---|---|---|
1 | ○ | ○ | ○ | DI可能 |
2 | ○ | ○ | x | 実行時エラーが発生 |
3 | ○ | x | ○ | 実行時エラーが発生 |
4 | x | ○ | ○ | 実行時エラーが発生 |
インスタンス生成アノテーション
Springが起動時にインスタンスを自動生成するためには、インスタンス化させたいクラスに「コンポーネントスキャンの対象となるアノテーション」を付与する必要がある。以下の4種類ある。
@Controller
@Service
@Repository
@Component
*
@Component
は、他3つに当てはまらない場合に指定するアノテーション。
各パターンの結果を確認する画面(JSP)home.jsp
各パターンの結果を表示する用の画面として以下を用意しています。
HTML
パターン1の場合
パターン1はDIが正常に出来ている例です。
コンポーネントスキャンの対象プロジェクトの確認。
まずは、どのプロジェクトがコンポーネントスキャンの対象になっているかを確認します。
servlet-context.xml(C:\workspace\sample\src\main\webapp\WEB-INF\spring\appServlet.servlet-context.xml
)を開き、context:component-scan
要素の内容を確認します。
下記を確認すると「com.my.app」プロジェクトがコンポーネントスキャンの対象になっていることが確認できます。
インスタンス生成アノテーションの付与
「com.my.app」プロジェクト配下のSampleService
に@Component
アノテーションを付与しました。
このクラスの処理は「—-@Component—-」という文字列を返すのみです。
Java
@Autowired
アノテーションの付与
「com.my.app」プロジェクト配下のコントローラクラスであるHomeController
にコンストラクタインジェクション方式で@Autowired
アノテーションを付与した。
Java
実行結果
以下のとおり、画面上に「—-@Component—-」という文字列が表示されました。
つまり、DIできています。

パターン2
パターン2は@Autowired
アノテーションを削除することで、インスタンスを注入するタイミングをなくした状態の動作確認をします。
@Autowired
アノテーションを削除する
「com.my.app」プロジェクト配下のコントローラクラスであるHomeController
から@Autowired
アノテーションをコメントアウトして削除します。
ここ以外のクラスは変更しません。パターン1と同じにします。
Java
実行結果
実行時、以下のエラーがコンソールに表示され、起動することができませんでした。
【例外】
【原因1】BeanCreationException
が発生
【原因2】BeanInstantiationException
が発生
【原因3】NoSuchMethodException
が発生
原因2のエラーをDeepL日本語訳すると
org.springframework.beans.BeanInstantiationException: Bean クラス [com.my.app.ctrl.HomeController] をインスタンス化できませんでした。デフォルトコンストラクタが見つかりません。ネストされた例外は java.lang.NoSuchMethodException: com.my.app.ctrl.HomeController.<init>()です。
となります。つまりデフォルトのコンストラクタが存在すればいいわけなので、以下のように、引数を持たないコンストラクタを宣言すれば実行時エラーは回避できます。ただし、SampleServiceのインスタンスが注入できないので、画面を表示するとエラーになります。
パターン3の場合
パターン3では、@Component
アノテーションを削除することでインスタンスを生成せないようにします。
(コントローラ側のクラスでは@Autowired
アノテーションを残しているので、インスタンスを注入するタイミングは存在してるけど、注入するためのインスタンスがない。というパターンになります。)
インスタンス生成アノテーションを削除する
「com.my.app」プロジェクト配下のSampleService
から@Component
アノテーションをコメントアウトして削除してみます。
ここ以外のクラスは変更しません。パターン1と同じにします。
実行結果
実行時、以下のエラーがコンソールに表示され、起動することができませんでした。
【例外】
【原因1】 UnsatisfiedDependencyException
が発生
【原因2】 NoSuchBeanDefinitionException
が発生
原因2のエラーをDeepL日本語訳すると
この依存関係のための autowire candidate として修飾される少なくとも 1 つの bean が期待されました。依存関係のアノテーション。{}
となりました。「1つのbeanを期待した」というのはインスタンスが1個あるはずだったけど、@Componentを付けていなかったからインスタンスがなかったということなんだと思います。
コントローラクラスのコンパイルは通っている
HomeControllerクラスにて、コンストラクタインジェクション方式でSampleServiceに対して@Autowired
アノテーションを付与していますが、これは特にコンパイルエラーになどにはなっていません。
パターン4の場合
パターン4では、コンポーネントスキャンの対象になっていないプロジェクトにクラスを作成した場合の動作確認をしてみます。
現在の設定では以下のように「com.my.app」プロジェクトがコンポーネントスキャンの対象プロジェクトになっているため、「com.my.demo」プロジェクトにDemoService.java
を作成してみます。
コントローラ側ではDemoService.java
をDIできるようにしておきます。
新規作成したDemoService.java
もインスタンスが生成されるように@Component
アノテーションを付与しておきます。
実行結果
実行時、以下のエラーがコンソールに表示され、起動することができませんでした。
【例外】
【原因1】 UnsatisfiedDependencyException
が発生
【原因2】 NoSuchBeanDefinitionException
が発生
org.springframework.beans.factory.NoSuchBeanDefinitionException:依存関係に一致するタイプ[com.my.demo.DemoService]のBeanが見つかりません:この依存関係のautowire候補として適格な少なくとも1つのBeanが必要です。依存関係の注釈:{}
となりました。この文章だと、context:component-scan
を直せばよいということが分かりづらいですね。
DIさせるには
今回作成した「com.my.demo」プロジェクトをDIの対象とするためには、servlet-context.xml
のcontext:component-scan
要素にプロジェクト名を追加すればOKです。
複数のプロジェクトを指定するには以下のようにカンマ(,
)区切りでプロジェクトを指定します。
servlet-context.xml
の修正後、サーバを再起動すれば、以下のように起動が確認できます。

DIを使わずに正常に実行する方法
@Autowired
アノテーションを付与せず、自分で任意のタイミングでdemoService = new DemoService()
を行うと、正常に実行することができます。
実行結果
以下のとおり、画面上に「—-DemoService—-」という文字列が表示されました。
つまり、DIを使わずにインスタンスを呼び出すことができています。
