Springフレームワークの基本として、DI(Dependency Injection)という概念がある。
DIは日本語で「依存性の注入」といい、newを使わなくてもオブジェクトを生成してくれる仕組みのことをいう。このDIを利用すると、プログラム間での依存関係を薄くすることができるため、ソフトウェアの品質を高めることにつながる。
今回は、サンプルプログラムを通して、Springを利用したJavaの開発現場でよく使われる、アノテーションベースでのDIの具体的な実装方法について共有する。
前提条件
以下の記事のSpring BootのWEB画面用アプリが作成済であること。
やってみたこと
DIを使わない実装
他のクラスのオブジェクトを生成する際、DIを使わず、通常のnewを利用することができる。以下にそのサンプルプログラムの構成を示す。
下記DemoController.java内では、「DemoObject」クラスのメソッドを呼び出すソースコードになっていて、DIを使わず、通常のnewを利用している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package com.example.demo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller public class DemoController { @RequestMapping("/") public ModelAndView index(ModelAndView mav){ //fromStr文字列をDIを利用しない形で取得 DemoObject obj = new DemoObject(); String str = obj.getString(); //取得したfromStr文字列を画面表示用に設定 mav.addObject("fromStr", str); //画面遷移先(templates/index.html)を設定 mav.setViewName("index"); return mav; } } |
1 2 3 4 5 6 7 8 | package com.example.demo; public class DemoObject { public String getString(){ return "from DemoObject"; } } |
ちなみに、DemoController.java内の「mav.setViewName(“index”);」で、遷移先画面「templates/index.html」を指定し、また「mav.addObject(“fromStr”, str);」で遷移先画面で表示する文字例fromStrを設定している。
また、下記index.html内で、「DemoObject」クラスのメソッドから取得した文字列「fromStr」を表示している。
1 2 3 4 5 6 7 8 9 10 11 | <!DOCTYPE html> <html lang="ja" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>index page</title> </head> <body> 取得したfromString文字列: <p th:text="${fromStr}">ここに取得した文字列が設定されます</p> </body> </html> |
index.html内の「xmlns:th=”http://www.thymeleaf.org/”」でthymeleafを読み込み、「th:text=”${fromStr}”」で、DemoController.javaで設定したformStrを表示している。
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/spring-boot-di/no_di/demo
作成したSpring Bootアプリケーションを起動し、「http:// (ホスト名):(ポート番号)」とアクセスした結果は以下の通り。
https://www.purin-it.com/doctor-homenet
Componentアノテーションを利用した実装
他のクラスのオブジェクトを生成する際、Dlを利用すると、newを利用しなくて良いため、クラス間の依存度を小さくすることができる。以下にそのサンプルプログラムの構成を示す。
下記のDemoController.java内で、DemoComponent.javaクラスのメソッドを呼び出すソースコードになっていて、newを使わずDIを利用して、DemoComponentオブジェクトを生成している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | package com.example.demo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller public class DemoController { @Autowired private DemoComponent demoComponent; @RequestMapping("/") public ModelAndView index(ModelAndView mav){ //fromStr文字列をComponentアノテーションのDIから取得 String str = demoComponent.getString(); //取得したfromStr文字列を画面表示用に設定 mav.addObject("fromStr", str); //画面遷移先(templates/index.html)を設定 mav.setViewName("index"); return mav; } } |
1 2 3 4 5 6 7 8 9 10 | package com.example.demo; import org.springframework.stereotype.Component; @Component public class DemoComponent { public String getString(){ return "from DemoComponent"; } } |
DemoComponent.javaではアノテーション@Componentを付与し、DemoController.javaでDemoComponentオブジェクトに@Autowiredを付与することで、Dlによるオブジェクトの生成が行えるようになっている。なお、index.htmlはDlを使わない実装と同じなので、記載を省略する。
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/spring-boot-di/use_component/demo
作成したSpring Bootアプリケーションを起動し、「http:// (ホスト名):(ポート番号)」とアクセスした結果は以下の通り。
Component以外のアノテーションを利用した実装
DIを利用するアノテーションは、@Component以外も利用することができる。今回は、@Repository、@Service、@Controllerを利用したサンプルを掲載する。
@Repository、@Service、@Controller のアノテーションの使い分けについては以下のサイトを参照のこと。
https://qiita.com/KevinFQ/items/abc7369cb07eb4b9ae29
上記サイトに記載されている通り、一般的には、データ層のクラスには@Repositoryを、サービス層のクラスには@Serviceを、コントローラ層のクラスには@Controllerを付与するが、それぞれのアノテーションの役割は@Componentと同じである。
Javaのソースコードそれぞれの内容は以下の通り。なお、index.htmlはDlを使わない実装と同じなので、記載を省略する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | package com.example.demo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller public class DemoController { @Autowired private DemoRepository demoRepository; @Autowired private DemoService demoService; @Autowired private DemoSubController demoSubController; @RequestMapping("/") public ModelAndView index(ModelAndView mav){ //fromStr文字列をRepository, Service, Controllerの各アノテーションのDIから取得 String str1 = demoRepository.getString(); String str2 = demoService.getString(); String str3 = demoSubController.getString(); String str = str1 + " : " + str2 + " : " + str3; //取得したfromStr文字列を画面表示用に設定 mav.addObject("fromStr", str); //画面遷移先(templates/index.html)を設定 mav.setViewName("index"); return mav; } } |
1 2 3 4 5 6 7 8 9 10 | package com.example.demo; import org.springframework.stereotype.Repository; @Repository public class DemoRepository { public String getString(){ return "from DemoRepository"; } } |
1 2 3 4 5 6 7 8 9 10 | package com.example.demo; import org.springframework.stereotype.Service; @Service public class DemoService { public String getString(){ return "from DemoService"; } } |
1 2 3 4 5 6 7 8 9 10 | package com.example.demo; import org.springframework.stereotype.Controller; @Controller public class DemoSubController { public String getString(){ return "from DemoSubController"; } } |
DemoRepository.javaでアノテーション@Repositoryを、DemoService.javaでアノテーション@Serviceを、DemoSubController.javaでアノテーション@Controllerを付与し、DemoController.javaで、DemoRepository.java、DemoService.java、DemoSubController.javaの各オブジェクトに@Autowiredを付与することで、Dlによるオブジェクトの生成が行えるようになっている。
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/spring-boot-di/use_others/demo
作成したSpring Bootアプリケーションを起動し、「http:// (ホスト名):(ポート番号)」とアクセスした結果は以下の通り。
要点まとめ
- DIを利用すると、プログラム間での依存関係を薄くすることができる。
- クラスの先頭に「@Component」を付与すると、DIするオブジェクトの生成対象とすることができる。「@Repository」「@Service」「@Controller」も同じ役割をもつ。
- DIするオブジェクトを生成し利用するには、「@Autowired」アノテーションを利用する。