Spring Boot DI/AOP

Spring BootでDIを利用してみた

Springフレームワークの基本として、DI(Dependency Injection)という概念がある。

DIは日本語で「依存性の注入」といい、newを使わなくてもオブジェクトを生成してくれる仕組みのことをいう。このDIを利用すると、プログラム間での依存関係を薄くすることができるため、ソフトウェアの品質を高めることにつながる。

今回は、サンプルプログラムを通して、Springを利用したJavaの開発現場でよく使われる、アノテーションベースでのDIの具体的な実装方法について共有する。



前提条件

以下の記事のSpring BootのWEB画面用アプリが作成済であること。

IntelliJ IDEA上でGradleを使ってWeb画面のSpring Bootプロジェクトを作成してみたSpring Bootのプロジェクトを新規作成を「IntelliJ IDEA」のメニューから実施しようとしたところ、無料の「Commun...

やってみたこと

  1. DIを使わない実装
  2. Componentアノテーションを利用した実装
  3. Component以外のアノテーションを利用した実装

DIを使わない実装

他のクラスのオブジェクトを生成する際、DIを使わず、通常のnewを利用することができる。以下にそのサンプルプログラムの構成を示す。
DIを使わないプログラムの構成

下記DemoController.java内では、「DemoObject」クラスのメソッドを呼び出すソースコードになっていて、DIを使わず、通常のnewを利用している。

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;
    }

}
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」を表示している。

<!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:// (ホスト名):(ポート番号)」とアクセスした結果は以下の通り。
DIを使わない場合の実行結果

https://www.purin-it.com/doctor-homenet

Componentアノテーションを利用した実装

他のクラスのオブジェクトを生成する際、Dlを利用すると、newを利用しなくて良いため、クラス間の依存度を小さくすることができる。以下にそのサンプルプログラムの構成を示す。
Componentアノテーションを利用したプログラムの構成

下記のDemoController.java内で、DemoComponent.javaクラスのメソッドを呼び出すソースコードになっていて、newを使わずDIを利用して、DemoComponentオブジェクトを生成している。

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;
    }

}
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アノテーションを利用した場合の実行結果

Code VillageはJavaScriptを中心としたサポート体制が充実したプログラミングスクールだったJavaScriptや、JavaScriptのフレームワーク「React」「Vue」を中心にオンラインで学習できるプログラミングスクール...

Component以外のアノテーションを利用した実装

DIを利用するアノテーションは、@Component以外も利用することができる。今回は、@Repository、@Service、@Controllerを利用したサンプルを掲載する。

@Repository、@Service、@Controller のアノテーションの使い分けについては以下のサイトを参照のこと。
https://qiita.com/KevinFQ/items/abc7369cb07eb4b9ae29

上記サイトに記載されている通り、一般的には、データ層のクラスには@Repositoryを、サービス層のクラスには@Serviceを、コントローラ層のクラスには@Controllerを付与するが、それぞれのアノテーションの役割は@Componentと同じである。

今回のサンプルコードの構成は以下の通り。
Componentアノテーション以外のDIを利用した場合のプログラムの構成

Javaのソースコードそれぞれの内容は以下の通り。なお、index.htmlはDlを使わない実装と同じなので、記載を省略する。

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;
    }

}
package com.example.demo;

import org.springframework.stereotype.Repository;

@Repository
public class DemoRepository {
    public String getString(){
        return "from DemoRepository";
    }
}
package com.example.demo;

import org.springframework.stereotype.Service;

@Service
public class DemoService {
    public String getString(){
        return "from DemoService";
    }
}
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

「AOMEI Partition Assistant Standard(無料)版」は便利なパーティション管理ツールだったハードディスクの記憶領域を論理的に分割し、分割された個々の領域のことを、パーティションといいます。 例えば、以下の図の場合、C/D...

作成したSpring Bootアプリケーションを起動し、「http:// (ホスト名):(ポート番号)」とアクセスした結果は以下の通り。
Componentアノテーション以外のDIを利用した場合の実行結果

要点まとめ

  • DIを利用すると、プログラム間での依存関係を薄くすることができる。
  • クラスの先頭に「@Component」を付与すると、DIするオブジェクトの生成対象とすることができる。「@Repository」「@Service」「@Controller」も同じ役割をもつ。
  • DIするオブジェクトを生成し利用するには、「@Autowired」アノテーションを利用する。