Spring BootのDIは、どのように使えばよいのでしょうか。

はじめに、Spring Bootのドキュメントを読んでみます。

ビーンや注入される依存性の定義には、Springフレームワークの標準技術を随意に使用できます。簡単にいうと、ビーンを探索するために@ComponentScanを使っているものを探します。これは@Autowiredコンストラクタインジェクションとの組み合わせて動きます。

前述で示唆したようにコードを構成(アプリケーションクラスをパッケージのルートに置く)していれば、@ComponentScanを引数無しで追加できます。すべてのコンポーネント(@Component@Service@Repository@Controller等)は、自動的にSpringビーンとして登録されます。

@Serviceビーンの例です。コンストラクタでRiskAssessorビーンへの依存性を定義しています。


package com.example.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class DatabaseAccountService implements AccountService {

    private final RiskAssessor riskAssessor;

    @Autowired
    public DatabaseAccountService(RiskAssessor riskAssessor) {
        this.riskAssessor = riskAssessor;
    }

    // ...

}

ビーンを欲しいところに@AutoWiredを付けておけば、うまいことやってくれるみたいです。

お試し

依存される側

コンポーネントを作成します。

src/main/java/com/example/component/HelloComponent.java

package com.example.component;

import org.springframework.stereotype.Component;

@Component
public class HelloComponent {

    public String greet(String name) {
        return "Hello " + name;
    }

}

依存する側

/greet?name=hogehogeというURLへのアクセスで、HelloComponentを呼び出してみます。

src/main/java/com/example/controller/HelloController.java

package com.example.controller;

import com.example.component.HelloComponent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    private final HelloComponent helloComponent;

    @Autowired
    public HelloController(HelloComponent helloComponent) {
        this.helloComponent = helloComponent;
    }
    
    @RequestMapping("/greet")
    public String greet(@RequestParam(value = "name", required = true) String name) {
        return helloComponent.greet(name);
    }

}

実行結果

こんなんできました。

Screenshot from 2016-11-07 17-09-52.png

スコープはどうなっているのか?

Java EEのCDIでは、アプリケーションスコープ(シングルトン)、リクエストスコープ、セッションスコープ、会話スコープ、依存スコープを定義できました。

ドキュメントによりますと、

  • singleton
  • prototype
    必要とされる度にインスタンスが作成されます。
  • request
  • session
  • globalSesion
  • application
  • websocket

があるみたいです。いっぱいですね。デフォルトではsingletonになるそうです。

さらには自前のスコープも定義できるとか。

下5つは、Webアプリケーションコンテキストでないと使用できないです。

使い方

スコープ 使い方
singleton デフォルトなので、何もしなくてOK
prototype XMLで定義? @Scope("prototype")をつける?
request @RequestScopeアノテーションをつける
globalSession XMLで定義?
application @ApplicationScopeアノテーションをつける
websocket XMLで定義?

スコープがかぶったらどうなる?

singletonにprototypeを注入したらどうなるのか?

TODO: :pencil:

注入のしかた

次の場所に注入できます。

  • コンストラクタ
  • セッター
  • プロパティ