LoginSignup
23
27

More than 5 years have passed since last update.

Spring FrameworkのDI調査

Posted at

Spring FrameworkのDependency Injection

Spring FrameworkのDependency Injectionはモジュール間の関係を疎にするために非常に有効です。それによりソフトウェアの再利用性や保守性の向上につながります。

アノテーションだけで簡単に実現ができるのですが、より詳しく理解をしていないと今後の開発において問題が発生するため、Dependency Injectionについて調査をしました。

まず、基本となるWeb Applicationは以下のようになります。単純にアクセスする度にcountをインクリメントして返します。

http://localhost:8080/count

{
  count: 3
}

Rest ControllerからはCountService I/Fを実現したBeanに@Autowiredを使用して接続し、利用しています。

CountRestController.java

@RestController
@RequestMapping("/count")
public class CountRestController {
    @Autowired
    private CountService service;

    @RequestMapping(method = RequestMethod.GET)
    public Count getCount() {
        return service.count();
    }
}

CountService.java

public interface CountService {
    Count count();
}

CountService I/Fを実現したクラスには、@Serviceアノテーションを付加して、Spring FrameworkのDIコンテナに登録をしています。

CountServiceIncrement.java

@Service
public class CountServiceIncrement implements CountService {
    private int counter;

    public CountServiceIncrement() {
        counter = 1;
    }

    @Override
    public Count count() {
        Count count = new Count(counter);
        counter++;
        return count;
    }
}

複数のコンポーネントの登録

CountService I/Fを実現した別のサービスをDIコンテナに登録します。

@Service
public class CountServiceDouble implements CountService {
    private int counter;

    public CountServiceDouble() {
        counter = 1;
    }

    @Override
    public Count count() {
        Count count = new Count(counter);
        counter = counter * 2;
        return count;
    }
}

この場合、DIコンテナは、CountRestControllerの@Autowiredで指定された変数にどちらを紐付ければ良いか分からないため以下のようなエラーを発生します。

 failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private jp.gr.java.conf.ulexite.spring.multicmp.service.CountService jp.gr.java.conf.ulexite.spring.multicmp.controller.CountRestController.service; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [jp.gr.java.conf.ulexite.spring.multicmp.service.CountService] is defined: expected single matching bean but found 2: countServiceDouble,countServiceIncrement

これを解決するためには@Qualifierアノテーションを用います。

まず二つのサービスにそれぞれ名前をつけます

@Service("increment")
public class CountServiceIncrement implements CountService {
...
}

@Service("double")
public class CountServiceDouble implements CountService {
...
}

次に使用するCountRestController側で@Qualifierでサービスの名前指定を行います。

public class CountRestController {
    @Autowired
    @Qualifier("double")
    private CountService service;

これでCountServiceDoubleを使用することができます。

以下にソースコードがあります
https://github.com/yokobonbon/spring-di-sample/tree/master/multicmp

Scope

@Scopeアノテーションで、コンポーネントの生成タイミングを制御することが可能です。@Scopeを付ける位置は、@Service, @ControllerなどDIコンポーネントの定義の下に記述します。

Scopeには以下の4種類が指定可能です。Scope指定しない場合は、デフォルトで"singleton"になります。

Scope Description
singleton インスタンスをSingletonとする(デフォルト)
prototype 利用する都度、インスタンス化する
request Servlet APIのリクエストスコープの間だけインスタンスが生存する
session Servlet APIのSessionスコープの間だけインスタンスが生存する
23
27
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
27