春の配線:@Autowired、@Resource、および@Inject

春の配線:@ Autowired、@ Resource、@ Inject

1. 概要

このSpringFrameworkの記事では、依存性注入に関連するアノテーション、つまり@Resource@Inject、および@Autowiredアノテーションの使用方法を示します。 これらの注釈は、依存関係を解決する宣言的な方法をクラスに提供します。 例えば:

@Autowired
ArbitraryClass arbObject;

直接インスタンス化するのとは対照的に(必須の方法)、たとえば:

ArbitraryClass arbObject = new ArbitraryClass();

3つのアノテーションのうち2つはJava拡張パッケージに属しています:javax.annotation.Resourcejavax.inject.Inject@Autowiredアノテーションは、org.springframework.beans.factory.annotationパッケージに属しています。

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

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

2. @Resource注釈

@Resourceアノテーションは、JSR-250アノテーションコレクションの一部であり、JavaEEにパッケージ化されています。 このアノテーションには次の実行パスがあり、優先度順にリストされています。

  1. 名前で一致

  2. タイプによる一致

  3. 修飾子による一致

これらの実行パスは、セッターとフィールドインジェクションの両方に適用できます。

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

フィールドインジェクションによる依存関係の解決は、インスタンス変数に@Resourceアノテーションを付けることで実現されます。

2.1.1. 名前で一致

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

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

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

この構成は、名前による一致の実行パスを使用して依存関係を解決します。 BeannamedFileは、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は依存関係の解決を試みるために、次のレベルの優先順位、タイプごとの一致を続行するため、テストは引き続き合格です。 。

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統合テストは、修飾子ごとの依存関係の解決を示すために使用されます。 このシナリオでは、特定のBean依存関係を各参照変数に注入する必要があります。

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

    @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の2つのBean定義を検出し、どちらの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統合テストにはsetterメソッドがあることです。

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

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

この例では、namedFileBeanの依存関係が再利用されます。 Bean名と対応する属性値は一致する必要があります。

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

依存関係が名前による一致の実行パスによって実際に解決されたことを確認するには、@Resourceアノテーションに渡された属性値を選択した値に変更して、テストを再実行します。 今回は、テストはNoSuchBeanDefinitionExceptionで失敗します。

2.2.2. タイプによる一致

セッターベースのタイプごとの一致の実行を示すために、MethodByTypeResourceTest統合テストを使用します。

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

    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統合テストは、修飾子による一致の実行パスを示すために使用されます。

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

    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アノテーションは、JSR-330アノテーションコレクションに属しています。 このアノテーションには次の実行パスがあり、優先度順にリストされています。

  1. タイプによる一致

  2. 修飾子による一致

  3. 名前で一致

これらの実行パスは、セッターとフィールドインジェクションの両方に適用できます。 @Injectアノテーションにアクセスするには、javax.injectライブラリをGradleまたはMavenの依存関係として宣言する必要があります。

Gradleの場合:

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

Mavenの場合:


    javax.inject
    javax.inject
    1

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 FieldInjectIntegrationTest {

    @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が必要な場合はどうでしょうか。 別の依存関係が必要になるように、統合テストの例を変更しましょう。

この例では、タイプ別一致の例で使用されているArbitraryDependencyクラスをサブクラス化して、AnotherArbitraryDependencyクラスを作成します。

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 FieldQualifierInjectIntegrationTest {

    @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がスローされます。

この例外をスローすることは、特定のクラスの実装が複数あり、どれを使用するかについて混乱していることを指摘するSpringFrameworkの方法です。 混乱を解明するために、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 FieldByNameInjectIntegrationTest {

    @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のタイプ別一致実行パスを示すために使用される統合テストの例は、@Injectタイプ別一致実行パスを示すために使用されるテストと同様です。 @Autowiredアノテーションを使用してタイプごとの一致を示すために使用されるFieldAutowiredTest統合テストは、次のとおりです。

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

    @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参照変数のタイプを変更して、統合テストを再実行します。 今回は、FieldAutowiredTest統合テストが失敗し、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 FieldQualifierAutowiredIntegrationTest {

    @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.example.dependency"})
    public class ApplicationContextTestAutowiredName {
}

@ComponentScanアノテーションは、@Componentアノテーションが付けられたJavaクラスのパッケージを検索します。 たとえば、アプリケーションコンテキストでは、com.example.dependencyパッケージがスキャンされ、@Componentアノテーションが付けられたクラスが検索されます。 このシナリオでは、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という名前のコンポーネントであることをSpringFrameworkに通知します。 @Autowiredアノテーションが依存関係を名前で解決するには、コンポーネント名がFieldAutowiredNameTest統合テストで定義されたフィールド名に対応している必要があります。 8行目を参照してください。

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

    @Autowired
    private ArbitraryDependency autowiredFieldDependency;

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

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

しかし、@Autowiredアノテーションが実際に名前による一致の実行パスを呼び出したことをどうやって知ることができますか? 参照変数autowiredFieldDependencyの名前を任意の名前に変更してから、テストを再実行してください。

今回は、テストは失敗し、NoUniqueBeanDefinitionExceptionがスローされます。 同様のチェックは、@Component属性値autowiredFieldDependencyを選択した別の値に変更し、テストを再実行することです。 NoUniqueBeanDefinitionExceptionもスローされます。

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

4.2. セッター注入

@Autowiredアノテーションのセッターベースのインジェクションは、@Resourceセッターベースのインジェクションで示されたアプローチと似ています。 参照変数に@Injectアノテーションを付ける代わりに、対応するセッターにアノテーションを付けます。 フィールドベースの依存性注入が続く実行パスは、セッターベースの注入にも適用されます。

5. これらの注釈の適用

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

5.1. ポリモーフィズムによるシングルトンのアプリケーション全体での使用

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

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

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

アプリケーションが複雑な動作をするように設計されている場合、各動作は異なるインターフェイス/抽象クラスに基づいており、これらの各実装の使用法はアプリケーションによって異なります。次に、@Resourceアノテーションを使用します。 このシナリオでは、主要なデフォルトの実行パスは名前による一致です。

5.3. 依存性注入は、JavaEEプラットフォームのみで処理する必要があります

SpringではなくJavaEE Platformによって注入されるすべての依存関係の設計上の義務がある場合、選択は@Resourceアノテーションと@Injectアノテーションのどちらかです。 必要なデフォルトの実行パスに基づいて、2つのアノテーション間の最終決定を絞り込む必要があります。

5.4. 依存性注入は、SpringFrameworkによってのみ処理される必要があります

すべての依存関係をSpringFrameworkで処理することが義務付けられている場合、唯一の選択肢は@Autowiredアノテーションです。

5.5. ディスカッションの概要

以下の表は、議論をまとめたものです。

シナリオ

@資源

@注入

@自動

ポリモーフィズムによるシングルトンのアプリケーション全体での使用

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

依存性注入は、JavaEEプラットフォームによってのみ処理する必要があります

依存性注入は、SpringFrameworkによってのみ処理される必要があります

6. 結論

この記事の目的は、各注釈の動作をより深く理解することです。 各注釈の動作を理解することは、アプリケーション全体の設計とメンテナンスの向上に役立ちます。

議論中に使用されたコードはGitHubにあります。