1概要

このSpring Frameworkの記事では、依存性注入に関連するアノテーション、つまり

@ Resource



@ Inject

、および

@ Autowired

アノテーションの使用方法について説明します。これらのアノテーションは、依存関係を解決するための宣言的な方法をクラスに提供します。例えば:

@Autowired
ArbitraryClass arbObject;

それらを直接インスタンス化するのではなく(命令型の方法)、例えば:

ArbitraryClass arbObject = new ArbitraryClass();

3つの注釈のうち2つはJava拡張パッケージに属します。


javax.annotation.Resource

および

javax.inject.Inject



@ Autowired

アノテーションは

org.springframework.beans.factory.annotation

パッケージに属しています。

これらの各注釈は、フィールドインジェクションまたはセッターインジェクションによって依存関係を解決できます。各アノテーションの実行パスに基づいて、3つのアノテーション間の違いを示すために、単純化された実用的な例を使用します。

例では、統合テスト中に3つの注入アノテーションを使用する方法に焦点を当てます。テストに必要な依存関係は、任意のファイルまたは任意のクラスです。


2

@リソース

注釈


@ Resource

アノテーションはhttps://jcp.org/en/jsr/detail?id=250[JSR-250]アノテーションコレクションの一部であり、Java EEと共にパッケージされています。この注釈には、優先順位の高い以下の実行パスがあります。

  1. 名前で一致

  2. タイプで一致

  3. 修飾子による一致

これらの実行パスは、セッター注入とフィールド注入の両方に適用できます。


2.1. フィールドインジェクション

フィールドインジェクションによる依存関係の解決は、

@ Resource

アノテーションを使用してインスタンス変数にアノテーションを付けることによって実現されます。

* 2.1.1。名前で一致**

名前によるフィールドインジェクションを実証するために使用された統合テストは次のとおりです。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  loader=AnnotationConfigContextLoader.class,
  classes=ApplicationContextTestResourceNameType.class)
public class FieldResourceInjectionTest {

    @Resource(name="namedFile")
    private File defaultFile;

    @Test
    public void givenResourceAnnotation__WhenOnField__ThenDependencyValid(){
        assertNotNull(defaultFile);
        assertEquals("namedFile.txt", defaultFile.getName());
    }
}

コードを見ていきましょう。

FieldResourceInjectionTest

統合テストの7行目で、名前による依存関係の解決は、Bean名を属性値として

@ Resource

アノテーションに渡すことによって行われます。

@Resource(name="namedFile")
private File defaultFile;

この設定は、名前による実行パスを使用して依存関係を解決します。 Bean

namedFile

は、

ApplicationContextTestResourceNameType

アプリケーションコンテキストで定義する必要があります。

Bean IDと対応する参照属性値は一致している必要があります。

@Configuration
public class ApplicationContextTestResourceNameType {

    @Bean(name="namedFile")
    public File namedFile() {
        File namedFile = new File("namedFile.txt");
        return namedFile;
    }
}

アプリケーションコンテキストでBeanを定義しないと、

org.springframework.beans.factory.NoSuchBeanDefinitionException

がスローされます。これは、

ApplicationContextTestResourceNameType

アプリケーションコンテキストで、@ @ Bean

アノテーションに渡された属性値を変更することによって実証できます。または、

FieldResourceInjectionTest

統合テストで、

@ Resource__アノテーションに渡された属性値を変更する。


2.1.2. タイプで一致

型による実行パスを示すには、

FieldResourceInjectionTest

統合テストの7行目の属性値を削除して、次のようになるようにします。

@Resource
private File defaultFile;

そしてテストを再度実行してください。


@ Resource

アノテーションがBeanの名前を属性値として受け取らない場合、Spring Frameworkは依存性を解決するために次のレベルの優先順位match-by-typeを続行するため、テストは成功します。


2.1.3. 限定子によるマッチング

修飾子による実行パスを示すために、

ApplicationContextTestResourceQualifier

アプリケーションコンテキストに2つのBeanが定義されるように統合テストのシナリオを変更します。

@Configuration
public class ApplicationContextTestResourceQualifier {

    @Bean(name="defaultFile")
    public File defaultFile() {
        File defaultFile = new File("defaultFile.txt");
        return defaultFile;
    }

    @Bean(name="namedFile")
    public File namedFile() {
        File namedFile = new File("namedFile.txt");
        return namedFile;
    }
}


QualifierResourceInjectionTest

統合テストは、match-by-qualifier依存関係の解決を実証するために使用されます。このシナリオでは、特定のBean依存関係を各参照変数に挿入する必要があります。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  loader=AnnotationConfigContextLoader.class,
  classes=ApplicationContextTestResourceQualifier.class)
public class QualifierResourceInjectionTest {

    @Resource
    private File dependency1;

    @Resource
    private File dependency2;

    @Test
    public void givenResourceAnnotation__WhenField__ThenDependency1Valid(){
        assertNotNull(dependency1);
        assertEquals("defaultFile.txt", dependency1.getName());
    }

    @Test
    public void givenResourceQualifier__WhenField__ThenDependency2Valid(){
        assertNotNull(dependency2);
        assertEquals("namedFile.txt", dependency2.getName());
    }
}

統合テストを実行すると、

org.springframework.beans.factory.NoUniqueBeanDefinitionException

がスローされます。この例外は、アプリケーションコンテキストが

File

型のBean定義を2つ見つけたため、どのBeanが依存関係を解決するのか混乱しているためにスローされます。

この問題を解決するには、

QualifierResourceInjectionTest

統合テストの7行目から10行目を参照してください。

@Resource
private File dependency1;

@Resource
private File dependency2;

次のコードを追加します。

@Qualifier("defaultFile")

@Qualifier("namedFile")

コードブロックは次のようになります。

@Resource
@Qualifier("defaultFile")
private File dependency1;

@Resource
@Qualifier("namedFile")
private File dependency2;

統合テストをもう一度実行してください。今回は成功するはずです。このテストの目的は、アプリケーションコンテキストで複数のBeanが定義されている場合でも、

@ Qualifier

アノテーションが特定の依存関係をクラスに挿入できるようにすることで混乱を解消することを実証することです。


2.2. セッター注入

フィールドへの依存関係を注入するときに実行される実行パスは、セッターベースの注入に適用できます。


2.2.1. 名前で一致

唯一の違いは、

MethodResourceInjectionTest

統合テストにセッターメソッドがあることです。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  loader=AnnotationConfigContextLoader.class,
  classes=ApplicationContextTestResourceNameType.class)
public class MethodResourceInjectionTest {

    private File defaultFile;

    @Resource(name="namedFile")
    protected void setDefaultFile(File defaultFile) {
        this.defaultFile = defaultFile;
    }

    @Test
    public void givenResourceAnnotation__WhenSetter__ThenDependencyValid(){
        assertNotNull(defaultFile);
        assertEquals("namedFile.txt", defaultFile.getName());
    }
}

セッターインジェクションによる依存関係の解決は、参照変数の対応するセッターメソッドに注釈を付けることによって行われます。 Beanの依存関係の名前を属性値として

@ Resource

アノテーションに渡します。

private File defaultFile;

@Resource(name="namedFile")
protected void setDefaultFile(File defaultFile) {
    this.defaultFile = defaultFile;
}

この例では、

namedFile

Beanの依存関係が再利用されます。 Bean名と対応する属性値は一致しなければなりません。

そのまま統合テストを実行すると合格です。

依存関係が実際に名前による一致実行パスによって解決されたことを確認するには、

@ Resource

アノテーションに渡された属性値を任意の値に変更して、テストを再実行してください。今回は、テストは

NoSuchBeanDefinitionException

で失敗します。


2.2.2. タイプで一致

セッターベースの型による実行の実行を実証するために、

MethodByTypeResourceTest

統合テストを使用します。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  loader=AnnotationConfigContextLoader.class,
  classes=ApplicationContextTestResourceNameType.class)
public class MethodByTypeResourceTest {

    private File defaultFile;

    @Resource
    protected void setDefaultFile(File defaultFile) {
        this.defaultFile = defaultFile;
    }

    @Test
    public void givenResourceAnnotation__WhenSetter__ThenValidDependency(){
        assertNotNull(defaultFile);
        assertEquals("namedFile.txt", defaultFile.getName());
    }
}

このテストをそのまま実行すると、成功します。


File

依存関係が型による実行パスによって実際に解決されたことを確認するには、

defaultFile

変数のクラス型を

String

などの別のクラス型に変更します。

MethodByTypeResourceTest

統合テストを再度実行すると、今度は

NoSuchBeanDefinitionException

がスローされます。

この例外は、

File

依存関係を解決するために型による一致が実際に使用されたことを検証します。

NoSuchBeanDefinitionException

は、参照変数名がBean名と一致する必要がないことを確認します。代わりに、依存関係の解決は、参照変数のクラス型と一致するBeanのクラス型に依存します。


2.2.3. 限定子によるマッチング


MethodByQualifierResourceTest

統合テストは、match-by-qualifier実行パスを示すために使用されます。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  loader=AnnotationConfigContextLoader.class,
  classes=ApplicationContextTestResourceQualifier.class)
public class MethodByQualifierResourceTest {

    private File arbDependency;
    private File anotherArbDependency;

    @Test
    public void givenResourceQualifier__WhenSetter__ThenValidDependencies(){
      assertNotNull(arbDependency);
        assertEquals("namedFile.txt", arbDependency.getName());
        assertNotNull(anotherArbDependency);
        assertEquals("defaultFile.txt", anotherArbDependency.getName());
    }

    @Resource
    @Qualifier("namedFile")
    public void setArbDependency(File arbDependency) {
        this.arbDependency = arbDependency;
    }

    @Resource
    @Qualifier("defaultFile")
    public void setAnotherArbDependency(File anotherArbDependency) {
        this.anotherArbDependency = anotherArbDependency;
    }
}

このテストの目的は、特定の型の複数のBean実装がアプリケーションコンテキストで定義されている場合でも、

@ Qualifier

アノテーションを

@ Resource

アノテーションと一緒に使用して依存関係を解決できることを示すことです。

フィールドベースの依存性注入と同様に、アプリケーションコンテキストで複数のBeanが定義されている場合、依存関係の解決に使用するBeanを指定するために

@ Qualifier

アノテーションを使用しないと

NoUniqueBeanDefinitionException

がスローされます。


3

@ Inject

アノテーション


@ Inject

アノテーションはhttps://jcp.org/en/jsr/detail?id=330[JSR-330]アノテーションコレクションに属します。

この注釈には、優先順位の高い以下の実行パスがあります。

  1. タイプで一致

  2. 修飾子による一致

  3. 名前で一致

これらの実行パスは、セッター注入とフィールド注入の両方に適用できます。


@ Inject

アノテーションにアクセスするには、

javax.inject

ライブラリをGradleまたはMavenの依存関係として宣言する必要があります。

Gradleの場合:

testCompile group: 'javax.inject', name: 'javax.inject', version: '1'

Mavenの場合:

<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>


3.1. フィールドインジェクション


3.1.1. タイプで一致

統合テストの例は、別の種類の依存関係、つまり

ArbitraryDependency

クラスを使用するように変更されます。

ArbitraryDependency

クラスの依存関係は、単純な依存関係としてのみ機能し、それ以上の意味はありません。それは次のようにリストされています。

@Component
public class ArbitraryDependency {

    private final String label = "Arbitrary Dependency";

    public String toString() {
        return label;
    }
}

問題の

FieldInjectTest

統合テストは以下のとおりです。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  loader=AnnotationConfigContextLoader.class,
  classes=ApplicationContextTestInjectType.class)
public class FieldInjectTest {

    @Inject
    private ArbitraryDependency fieldInjectDependency;

    @Test
    public void givenInjectAnnotation__WhenOnField__ThenValidDependency(){
        assertNotNull(fieldInjectDependency);
        assertEquals("Arbitrary Dependency",
          fieldInjectDependency.toString());
    }
}

最初に名前で依存関係を解決する

@ Resource

アノテーションとは異なります。

@ Inject

アノテーションのデフォルトの振る舞いは依存関係をタイプ別に解決します。

つまり、クラス参照変数名がBean名と異なる場合でも、Beanがアプリケーションコンテキストで定義されていれば、依存関係は解決されます。次のテストで参照変数名がどのようになっているかに注意してください。

@Inject
private ArbitraryDependency fieldInjectDependency;

アプリケーションコンテキストで設定されたBean名とは異なります。

@Bean
public ArbitraryDependency injectDependency() {
    ArbitraryDependency injectDependency = new ArbitraryDependency();
    return injectDependency;
}

そしてテストが実行されるとき、それは依存関係を解決することができます。


3.1.2. 限定子によるマッチング

しかし、特定のクラス型の実装が複数あり、特定のクラスに特定のBeanが必要な場合はどうなりますか?別の依存関係が必要になるように統合テストの例を変更しましょう。

この例では、

AnotherArbitraryDependency

クラスを作成するために、match-by-typeの例で使用された

ArbitraryDependency

クラスをサブクラス化します。

public class AnotherArbitraryDependency extends ArbitraryDependency {

    private final String label = "Another Arbitrary Dependency";

    public String toString() {
        return label;
    }
}

各テストケースの目的は、各依存関係が各参照変数に正しく挿入されるようにすることです。

@Inject
private ArbitraryDependency defaultDependency;

@Inject
private ArbitraryDependency namedDependency;

修飾子による一致を示すために使用された

FieldQualifierInjectTest

統合テストは次のとおりです。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  loader=AnnotationConfigContextLoader.class,
  classes=ApplicationContextTestInjectQualifier.class)
public class FieldQualifierInjectTest {

    @Inject
    private ArbitraryDependency defaultDependency;

    @Inject
    private ArbitraryDependency namedDependency;

    @Test
    public void givenInjectQualifier__WhenOnField__ThenDefaultFileValid(){
        assertNotNull(defaultDependency);
        assertEquals("Arbitrary Dependency",
          defaultDependency.toString());
    }

    @Test
    public void givenInjectQualifier__WhenOnField__ThenNamedFileValid(){
        assertNotNull(defaultDependency);
        assertEquals("Another Arbitrary Dependency",
          namedDependency.toString());
    }
}

アプリケーションコンテキスト内に特定のクラスの実装が複数あり、

FieldQualifierInjectTest

統合テストが以下にリストされた方法で依存関係を注入しようとした場合

@Inject
private ArbitraryDependency defaultDependency;

@Inject
private ArbitraryDependency namedDependency;


NoUniqueBeanDefinitionException

がスローされます。

この例外を投げるのは、Spring Frameworkが特定のクラスに複数の実装があり、どちらを使用するかについて混乱していることを指摘する方法です。混乱を解明するために、

FieldQualifierInjectTest

統合テストの7行目と10行目に進みます。

@Inject
private ArbitraryDependency defaultDependency;

@Inject
private ArbitraryDependency namedDependency;

必要なBean名を

@ Qualifier

アノテーションに渡します。これは

@ Inject

アノテーションと一緒に使用されます。コードブロックは次のようになります。

@Inject
@Qualifier("defaultFile")
private ArbitraryDependency defaultDependency;

@Inject
@Qualifier("namedFile")
private ArbitraryDependency namedDependency;


@ Qualifier

アノテーションは、Bean名を受け取るときに完全一致を期待します。 Bean名が正しく

Qualifier

に渡されるようにしてください。そうしないと、

NoUniqueBeanDefinitionException

がスローされます。もう一度テストを実行すると、今度は合格するはずです。


3.1.3. 名前で一致

名前による一致を示すために使用される

FieldByNameInjectTest

統合テストは、タイプによる一致実行パスと似ています。唯一の違いは、特定のタイプではなく、特定のBeanが必要になることです。この例では、

ArbitraryDependency

クラスを再度サブクラス化して

YetAnotherArbitraryDependency

クラスを生成します。

public class YetAnotherArbitraryDependency extends ArbitraryDependency {

    private final String label = "Yet Another Arbitrary Dependency";

    public String toString() {
        return label;
    }
}

名前による一致の実行パスを示すために、以下の統合テストを使用します。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  loader=AnnotationConfigContextLoader.class,
  classes=ApplicationContextTestInjectName.class)
public class FieldByNameInjectTest {

    @Inject
    @Named("yetAnotherFieldInjectDependency")
    private ArbitraryDependency yetAnotherFieldInjectDependency;

    @Test
    public void givenInjectQualifier__WhenSetOnField__ThenDependencyValid(){
        assertNotNull(yetAnotherFieldInjectDependency);
        assertEquals("Yet Another Arbitrary Dependency",
          yetAnotherFieldInjectDependency.toString());
    }
}

アプリケーションのコンテキストは次のとおりです。

@Configuration
public class ApplicationContextTestInjectName {

    @Bean
    public ArbitraryDependency yetAnotherFieldInjectDependency() {
        ArbitraryDependency yetAnotherFieldInjectDependency =
          new YetAnotherArbitraryDependency();
        return yetAnotherFieldInjectDependency;
    }
}

そのまま統合テストを実行すれば成功します。

依存関係が実際に名前による一致実行パスによって挿入されたことを確認するには、

@ Named

アノテーションに渡された値

yetAnotherFieldInjectDependency

を任意の別の名前に変更します。テストを再度実行してください – 今回は、

NoSuchBeanDefinitionException

がスローされます。


3.2. セッター注入


@ Inject

アノテーションのセッターベースのインジェクションは、

@ Resource

セッターベースのインジェクションに使用されるアプローチと似ています。参照変数に注釈を付ける代わりに、対応する設定メソッドに注釈を付けます。フィールドベースの依存性注入が後に続く実行パスは、セッターベースの注入にも適用されます。


4

@ Autowired

アノテーション


@ Autowired

アノテーションの動作は

@ Inject

アノテーションと似ています。唯一の違いは、

@ Autowired

アノテーションがSpringフレームワークの一部であるということです。このアノテーションは

@ Inject

アノテーションと同じ実行パスを持ち、優先順位の高い順にリストされています。

  1. タイプで一致

  2. 修飾子による一致

  3. 名前で一致

これらの実行パスは、セッター注入とフィールド注入の両方に適用できます。


4.1. フィールドインジェクション


4.1.1. タイプで一致


@ Autowired

match-by-type実行パスのデモに使用された統合テストの例は、

@ Inject

type-by-type実行パスのデモに使用されたテストと似ています。

@ Autowired

アノテーションを使用して型による一致を実証するために使用された

FieldAutowiredTest

統合テストは次のとおりです。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  loader=AnnotationConfigContextLoader.class,
  classes=ApplicationContextTestAutowiredType.class)
public class FieldAutowiredTest {

    @Autowired
    private ArbitraryDependency fieldDependency;

    @Test
    public void givenAutowired__WhenSetOnField__ThenDependencyResolved() {
        assertNotNull(fieldDependency);
        assertEquals("Arbitrary Dependency", fieldDependency.toString());
    }
}

この統合テストのアプリケーションコンテキストは次のとおりです。

@Configuration
public class ApplicationContextTestAutowiredType {

    @Bean
    public ArbitraryDependency autowiredFieldDependency() {
        ArbitraryDependency autowiredFieldDependency =
          new ArbitraryDependency();
        return autowiredFieldDependency;
    }
}

統合テストの目的は、タイプによる一致が他の実行パスよりも優先されることを実証することです。


FieldAutowiredTest

統合テストの8行目で、参照変数の名前がどのようになっているかに注目してください。

@Autowired
private ArbitraryDependency fieldDependency;

アプリケーションコンテキストのBean名とは異なります。

@Bean
public ArbitraryDependency autowiredFieldDependency() {
    ArbitraryDependency autowiredFieldDependency =
      new ArbitraryDependency();
    return autowiredFieldDependency;
}

テストが実行されると、合格します。

依存関係が実際にタイプによる実行パスを使用して解決されたことを確認するには、

fieldDependency

参照変数のタイプを変更して、統合テストを再度実行してください。今回は、

FoSAutowiredTest

統合テストが失敗し、

NoSuchBeanDefinitionException

がスローされます。これは、タイプによる突き合わせが依存関係を解決するために使用されたことを検証します。


4.1.2. 限定子によるマッチング

下記のように、アプリケーションのコンテキストで複数のBean実装が定義されている状況に直面した場合はどうでしょうか。

@Configuration
public class ApplicationContextTestAutowiredQualifier {

    @Bean
    public ArbitraryDependency autowiredFieldDependency() {
        ArbitraryDependency autowiredFieldDependency =
          new ArbitraryDependency();
        return autowiredFieldDependency;
    }

    @Bean
    public ArbitraryDependency anotherAutowiredFieldDependency() {
        ArbitraryDependency anotherAutowiredFieldDependency =
          new AnotherArbitraryDependency();
        return anotherAutowiredFieldDependency;
    }
}

下記の

FieldQualifierAutowiredTest

統合テストが実行されると、

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  loader=AnnotationConfigContextLoader.class,
  classes=ApplicationContextTestAutowiredQualifier.class)
public class FieldQualifierAutowiredTest {

    @Autowired
    private ArbitraryDependency fieldDependency1;

    @Autowired
    private ArbitraryDependency fieldDependency2;

    @Test
    public void givenAutowiredQualifier__WhenOnField__ThenDep1Valid(){
        assertNotNull(fieldDependency1);
        assertEquals("Arbitrary Dependency", fieldDependency1.toString());
    }

    @Test
    public void givenAutowiredQualifier__WhenOnField__ThenDep2Valid(){
        assertNotNull(fieldDependency2);
        assertEquals("Another Arbitrary Dependency",
          fieldDependency2.toString());
    }
}


NoUniqueBeanDefinitionException

がスローされます。

例外は、アプリケーションコンテキストで定義されている2つのBeanによるあいまいさのためです。 Spring Frameworkは、どのBean依存関係がどの参照変数に自動配線されるべきかを知りません。この問題を解決するには、

FieldQualifierAutowiredTest

統合テストの7行目と10行目に

@ Qualifier

アノテーションを追加します。

@Autowired
private FieldDependency fieldDependency1;

@Autowired
private FieldDependency fieldDependency2;

コードブロックは次のようになります。

@Autowired
@Qualifier("autowiredFieldDependency")
private FieldDependency fieldDependency1;

@Autowired
@Qualifier("anotherAutowiredFieldDependency")
private FieldDependency fieldDependency2;

もう一度テストを実行すると、今度は成功します。


4.1.3. 名前で一致


@ Autowired

アノテーションを使用してフィールドの依存関係を挿入する場合は、同じ統合テストシナリオを使用して名前による実行パスを実演します。依存関係を名前で自動配線する場合は、

@ ComponentScan

アノテーションをアプリケーションコンテキスト

ApplicationContextTestAutowiredName

と共に使用する必要があります。

@Configuration
@ComponentScan(basePackages={"com.baeldung.dependency"})
    public class ApplicationContextTestAutowiredName {
}


@ ComponentScan

アノテーションは、

@ Component

アノテーションが付けられたJavaクラスのパッケージを検索します。たとえば、アプリケーションのコンテキストでは、

@ Component

アノテーションでアノテーションが付けられているクラスについて

com.baeldung.dependency

パッケージがスキャンされます。このシナリオでは、Spring Frameworkは

@ Component

アノテーションを持つ

ArbitraryDependency

クラスを検出する必要があります。

@Component(value="autowiredFieldDependency")
public class ArbitraryDependency {

    private final String label = "Arbitrary Dependency";

    public String toString() {
        return label;
    }
}


@ Component

アノテーションに渡された属性値

autowiredFieldDependency

は、

ArbitraryDependency

クラスが

autowiredFieldDependency

という名前のコンポーネントであることをSpring Frameworkに伝えます。

@ Autowired

アノテーションが名前によって依存関係を解決するには、コンポーネント名が

FieldAutowiredNameTest

統合テストで定義されたフィールド名と一致している必要があります。 8行目を参照してください。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  loader=AnnotationConfigContextLoader.class,
  classes=ApplicationContextTestAutowiredName.class)
public class FieldAutowiredNameTest {

    @Autowired
    private ArbitraryDependency autowiredFieldDependency;

    @Test
    public void givenAutowiredAnnotation__WhenOnField__ThenDepValid(){
        assertNotNull(autowiredFieldDependency);
        assertEquals("Arbitrary Dependency",
          autowiredFieldDependency.toString());
    }
}


FieldAutowiredNameTest

統合テストをそのまま実行すると、成功します。

しかし、

@ Autowired

アノテーションが実際にmatch-by-name実行パスを呼び出したことをどうやって知ることができるでしょうか。参照変数

autowiredFieldDependency

の名前を任意の別の名前に変更してから、テストを再実行してください。

今回はテストは失敗し、

NoUniqueBeanDefinitionException

がスローされます。同様の確認として、

@ Component

属性値

autowiredFieldDependency

を、選択した別の値に変更して、テストを再実行してください。

NoUniqueBeanDefinitionException

もスローされます。

この例外は、誤ったBean名が使用された場合、有効なBeanが見つからないことを証明しています。したがって、名前による実行パスが呼び出されました。


4.2. セッター注入


@ Autowired

アノテーションのセッターベースのインジェクションは、

@ Resource

セッターベースのインジェクションで示したアプローチと似ています。

@ Inject

アノテーションで参照変数にアノテーションを付ける代わりに、対応するセッターにアノテーションを付けます。実行パスとそれに続くフィールドベースの依存関係注入は、セッターベースの注入にも適用されます。


5これらの注釈を適用する

これは、どの注釈がどのような状況下で使用されるべきかという疑問を提起します。これらの質問に対する答えは、問題のアプリケーションが直面している設計シナリオと、各アノテーションのデフォルトの実行パスに基づいて開発者がポリモーフィズムをどのように活用したいかによって異なります。


5.1. 多型によるシングルトンのアプリケーション全体での使用

アプリケーションの動作がインタフェースまたは抽象クラスの実装に基づいており、これらの動作がアプリケーション全体で使用されるように設計されている場合は、

@ Inject

または

@ Autowired

注釈を使用します。

このアプローチの利点は、アプリケーションがアップグレードされたとき、またはバグを修正するためにパッチを適用する必要があることです。そうすれば、アプリケーション全体の動作への悪影響を最小限に抑えながらクラスを交換できます。このシナリオでは、主要なデフォルトの実行パスはタイプによる一致です。


5.2. ポリモーフィズムによるきめ細かいアプリケーション動作設定

アプリケーションが複雑な振る舞いをするように設計されていて、それぞれの振る舞いが異なるインターフェース/抽象クラスに基づいており、これらの各実装の使用法がアプリケーションによって異なる場合は、

@ Resource

アノテーションを使用します。このシナリオでは、デフォルトの主な実行パスは名前による一致です。


5.3. 依存性注入はJava EEプラットフォームによってのみ処理されるべきです

Springではなく、すべての依存関係をJava EEプラットフォームによってインジェクトするという設計上の指示がある場合、選択は

@ Resource

アノテーションと

@ Inject

アノテーションのどちらかです。どちらのデフォルト実行パスが必要かに基づいて、2つのアノテーション間の最終決定を絞り込む必要があります。

** 5.4. 依存性注入はSpring Frameworkによってのみ処理されるべきです

すべての依存関係がSpring Frameworkによって処理されることがマンデートである場合、唯一の選択は

@ Autowired

アノテーションです。


5.5. ディスカッションサマリー

以下の表はその説明をまとめたものです。

| =================================================== ===================== |シナリオ| @Resource | @Inject | @Autowired |多態性によるシングルトンのアプリケーション全体での使用|✗|✔|✔

|多態性によるきめ細かいアプリケーション動作設定|✔|✗|✗

|依存性注入は、Java EEプラットフォームによってのみ処理されるべきです|✔|✔|✗

|依存性注入はSpring Frameworkによってのみ処理されるべきです|✗|✗|✔| ==================================== ==========================================


6. 結論

この記事は、各注釈の動作についてより深い洞察を提供することを目的としていました。各注釈がどのように振る舞うかを理解することは、より良い全体的なアプリケーション設計とメンテナンスに貢献するでしょう。

議論中に使用されたコードはhttps://github.com/eugenp/tutorials/tree/master/spring-core[GitHub]にあります。